diff --git a/proxmox-api-macro/Cargo.toml b/proxmox-api-macro/Cargo.toml index c5c6af1a..645d9fbc 100644 --- a/proxmox-api-macro/Cargo.toml +++ b/proxmox-api-macro/Cargo.toml @@ -16,6 +16,7 @@ syn = { version = "1.0", features = [ "full" ] } [dev-dependencies] futures = "0.3" proxmox = { path = "../proxmox" } +proxmox-api = { path = "../proxmox-api", features = [ "test-harness" ] } serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/proxmox-api-macro/tests/api1.rs b/proxmox-api-macro/tests/api1.rs index 29ef4864..cc6890ec 100644 --- a/proxmox-api-macro/tests/api1.rs +++ b/proxmox-api-macro/tests/api1.rs @@ -42,6 +42,61 @@ pub fn create_ticket(_param: Value) -> Result { panic!("implement me"); } +#[test] +fn create_ticket_schema_check() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_create_ticket), + &::proxmox::api::schema::ObjectSchema::new( + "Create or verify authentication ticket.", + &[ + ( + "password", + false, + &::proxmox::api::schema::StringSchema::new( + "The secret password or a valid ticket.", + ) + .schema(), + ), + ( + "username", + false, + &::proxmox::api::schema::StringSchema::new("User name") + .max_length(64) + .schema(), + ), + ], + ), + ) + .returns( + &::proxmox::api::schema::ObjectSchema::new( + "A ticket.", + &[ + ( + "CSRFPreventionToken", + false, + &::proxmox::api::schema::StringSchema::new( + "Cross Site Request Forgerty Prevention Token.", + ) + .schema(), + ), + ( + "ticket", + false, + &::proxmox::api::schema::StringSchema::new("Auth ticket.").schema(), + ), + ( + "username", + false, + &::proxmox::api::schema::StringSchema::new("User name.").schema(), + ), + ], + ) + .schema(), + ) + .protected(true); + assert_eq!(TEST_METHOD, API_METHOD_CREATE_TICKET); +} + #[api( input: { properties: { @@ -85,6 +140,61 @@ pub fn create_ticket_direct(username: String, password: String) -> Result<&'stat Ok("an:invalid:ticket") } +#[test] +fn create_ticket_direct_schema_check() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_create_ticket_direct), + &::proxmox::api::schema::ObjectSchema::new( + "Create or verify authentication ticket.", + &[ + ( + "password", + false, + &::proxmox::api::schema::StringSchema::new( + "The secret password or a valid ticket.", + ) + .schema(), + ), + ( + "username", + false, + &::proxmox::api::schema::StringSchema::new("User name") + .max_length(64) + .schema(), + ), + ], + ), + ) + .returns( + &::proxmox::api::schema::ObjectSchema::new( + "A ticket.", + &[ + ( + "CSRFPreventionToken", + false, + &::proxmox::api::schema::StringSchema::new( + "Cross Site Request Forgerty Prevention Token.", + ) + .schema(), + ), + ( + "ticket", + false, + &::proxmox::api::schema::StringSchema::new("Auth ticket.").schema(), + ), + ( + "username", + false, + &::proxmox::api::schema::StringSchema::new("User name.").schema(), + ), + ], + ) + .schema(), + ) + .protected(true); + assert_eq!(TEST_METHOD, API_METHOD_CREATE_TICKET_DIRECT); +} + #[api( input: { properties: { @@ -124,6 +234,24 @@ pub fn func_with_option(verbose: Option) -> Result<(), Error> { Ok(()) } +#[test] +fn func_with_option_schema_check() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_func_with_option), + &::proxmox::api::schema::ObjectSchema::new( + "Optional parameter", + &[( + "verbose", + true, + &::proxmox::api::schema::BooleanSchema::new("Verbose output.").schema(), + )], + ), + ) + .protected(false); + + assert_eq!(TEST_METHOD, API_METHOD_FUNC_WITH_OPTION); +} + struct RpcEnv; impl proxmox::api::RpcEnvironment for RpcEnv { fn set_result_attrib(&mut self, name: &str, value: Value) { diff --git a/proxmox-api-macro/tests/ext-schema.rs b/proxmox-api-macro/tests/ext-schema.rs index 32c07363..b879eb34 100644 --- a/proxmox-api-macro/tests/ext-schema.rs +++ b/proxmox-api-macro/tests/ext-schema.rs @@ -25,6 +25,19 @@ pub fn get_archive(archive_name: String) { let _ = archive_name; } +#[test] +fn get_archive_schema_check() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_get_archive), + &::proxmox::api::schema::ObjectSchema::new( + "Get an archive.", + &[("archive-name", false, &NAME_SCHEMA)], + ), + ) + .protected(false); + assert_eq!(TEST_METHOD, API_METHOD_GET_ARCHIVE); +} + #[api( input: { properties: { @@ -41,6 +54,19 @@ pub fn get_archive_2(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result Result<(), Error> { let _ = param; Ok(()) } + +#[test] +fn get_data_schema_test() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_get_data), + &::proxmox::api::schema::ObjectSchema::new( + "Get data.", + &[( + "data", + false, + &::proxmox::api::schema::ArraySchema::new("The data", &NAME_SCHEMA).schema(), + )], + ), + ) + .protected(false); + + assert_eq!(TEST_METHOD, API_METHOD_GET_DATA); +} diff --git a/proxmox-api-macro/tests/types.rs b/proxmox-api-macro/tests/types.rs index c6c83cce..af1b2421 100644 --- a/proxmox-api-macro/tests/types.rs +++ b/proxmox-api-macro/tests/types.rs @@ -16,21 +16,88 @@ use serde_json::Value; //#[derive(Clone, Debug, Deserialize, Serialize)] pub struct OkString(String); +#[test] +fn ok_string() { + const TEST_SCHEMA: &'static ::proxmox::api::schema::Schema = + &::proxmox::api::schema::StringSchema::new("A string") + .format(&schema::ApiStringFormat::Enum(&["ok", "not-ok"])) + .schema(); + assert_eq!(TEST_SCHEMA, OkString::API_SCHEMA); +} + #[api] -/// A Foo. -pub struct Foo { +/// An example of a simple struct type. +pub struct TestStruct { /// A test string. - test: String, + test_string: String, /// An optional auto-derived value for testing: another: Option, } -// generates the following without the '_' prefix in the constant: -impl OkString { - pub const _API_SCHEMA: &'static schema::Schema = &schema::StringSchema::new("A string") - .format(&schema::ApiStringFormat::Enum(&["ok", "not-ok"])) +#[test] +fn test_struct() { + pub const TEST_SCHEMA: &'static ::proxmox::api::schema::Schema = + &::proxmox::api::schema::ObjectSchema::new( + "An example of a simple struct type.", + &[ + ( + "test_string", + false, + &::proxmox::api::schema::StringSchema::new("A test string.").schema(), + ), + ( + "another", + true, + &::proxmox::api::schema::StringSchema::new( + "An optional auto-derived value for testing:", + ) + .schema(), + ), + ], + ) .schema(); + + assert_eq!(TEST_SCHEMA, TestStruct::API_SCHEMA); +} + +#[api] +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case")] +/// An example of a struct with renamed fields. +pub struct RenamedStruct { + /// A test string. + test_string: String, + + /// An optional auto-derived value for testing: + #[serde(rename = "SomeOther")] + another: Option, +} + +#[test] +fn renamed_struct() { + const TEST_SCHEMA: &'static ::proxmox::api::schema::Schema = + &::proxmox::api::schema::ObjectSchema::new( + "An example of a struct with renamed fields.", + &[ + ( + "test-string", + false, + &::proxmox::api::schema::StringSchema::new("A test string.").schema(), + ), + ( + "SomeOther", + true, + &::proxmox::api::schema::StringSchema::new( + "An optional auto-derived value for testing:", + ) + .schema(), + ), + ], + ) + .schema(); + + assert_eq!(TEST_SCHEMA, RenamedStruct::API_SCHEMA); } #[api] @@ -44,6 +111,22 @@ pub enum Selection { SelectionNumberThree, } +#[test] +fn selection_test() { + const TEST_SCHEMA: &'static ::proxmox::api::schema::Schema = + &::proxmox::api::schema::StringSchema::new( + "A selection of either \'onekind\', \'another-kind\' or \'selection-number-three\'.", + ) + .format(&::proxmox::api::schema::ApiStringFormat::Enum(&[ + "onekind", + "another-kind", + "selection-number-three", + ])) + .schema(); + + assert_eq!(TEST_SCHEMA, Selection::API_SCHEMA); +} + // Initial test: #[api( input: { @@ -62,3 +145,21 @@ pub fn string_check(arg: Value, selection: Selection) -> Result { let _ = selection; panic!("body") } + +#[test] +fn string_check_schema_test() { + const TEST_METHOD: ::proxmox::api::ApiMethod = ::proxmox::api::ApiMethod::new( + &::proxmox::api::ApiHandler::Sync(&api_function_string_check), + &::proxmox::api::schema::ObjectSchema::new( + "Check a string.", + &[ + ("arg", false, OkString::API_SCHEMA), + ("selection", false, Selection::API_SCHEMA), + ], + ), + ) + .returns(&::proxmox::api::schema::BooleanSchema::new("Whether the string was \"ok\".").schema()) + .protected(false); + + assert_eq!(TEST_METHOD, API_METHOD_STRING_CHECK); +}