diff --git a/meilisearch/tests/auth/api_keys.rs b/meilisearch/tests/auth/api_keys.rs index d33610d0a..0ae57d726 100644 --- a/meilisearch/tests/auth/api_keys.rs +++ b/meilisearch/tests/auth/api_keys.rs @@ -790,7 +790,7 @@ async fn list_api_keys() { "###); meili_snap::snapshot!(code, @"201 Created"); - let (response, code) = server.list_api_keys().await; + let (response, code) = server.list_api_keys("").await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".results[].createdAt" => "[ignored]", ".results[].updatedAt" => "[ignored]", ".results[].uid" => "[ignored]", ".results[].key" => "[ignored]" }), @r###" { "results": [ @@ -864,7 +864,7 @@ async fn list_api_keys() { async fn error_list_api_keys_no_header() { let server = Server::new_auth().await; - let (response, code) = server.list_api_keys().await; + let (response, code) = server.list_api_keys("").await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { "message": "The Authorization header is missing. It must use the bearer authorization method.", @@ -881,7 +881,7 @@ async fn error_list_api_keys_bad_key() { let mut server = Server::new_auth().await; server.use_api_key("d4000bd7225f77d1eb22cc706ed36772bbc36767c016a27f76def7537b68600d"); - let (response, code) = server.list_api_keys().await; + let (response, code) = server.list_api_keys("").await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { "message": "The provided API key is invalid.", @@ -1723,7 +1723,7 @@ async fn error_access_api_key_routes_no_master_key_set() { "###); meili_snap::snapshot!(code, @"401 Unauthorized"); - let (response, code) = server.list_api_keys().await; + let (response, code) = server.list_api_keys("").await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { "message": "Meilisearch is running without a master key. To access this API endpoint, you must have set a master key at launch.", @@ -1769,7 +1769,7 @@ async fn error_access_api_key_routes_no_master_key_set() { "###); meili_snap::snapshot!(code, @"401 Unauthorized"); - let (response, code) = server.list_api_keys().await; + let (response, code) = server.list_api_keys("").await; meili_snap::snapshot!(meili_snap::json_string!(response, { ".createdAt" => "[ignored]", ".updatedAt" => "[ignored]" }), @r###" { "message": "Meilisearch is running without a master key. To access this API endpoint, you must have set a master key at launch.", diff --git a/meilisearch/tests/auth/errors.rs b/meilisearch/tests/auth/errors.rs new file mode 100644 index 000000000..2ef853d72 --- /dev/null +++ b/meilisearch/tests/auth/errors.rs @@ -0,0 +1,438 @@ +use meili_snap::*; +use serde_json::json; +use uuid::Uuid; + +use crate::common::Server; + +#[actix_rt::test] +async fn create_api_key_bad_description() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.add_api_key(json!({ "description": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.description`: expected a string, but found an array: `[\"doggo\"]`", + "code": "invalid_api_key_description", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_description" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_bad_name() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.add_api_key(json!({ "name": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.name`: expected a string, but found an array: `[\"doggo\"]`", + "code": "invalid_api_key_name", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_name" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_bad_uid() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + // bad type + let (response, code) = server.add_api_key(json!({ "uid": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.uid`: expected a string, but found an array: `[\"doggo\"]`", + "code": "invalid_api_key_uid", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_uid" + } + "###); + + // can't parse + let (response, code) = server.add_api_key(json!({ "uid": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value at `.uid`: invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `o` at 2", + "code": "invalid_api_key_uid", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_uid" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_bad_actions() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + // bad type + let (response, code) = server.add_api_key(json!({ "actions": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.actions`: expected an array, but found a string: `\"doggo\"`", + "code": "invalid_api_key_actions", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" + } + "###); + + // can't parse + let (response, code) = server.add_api_key(json!({ "actions": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown value `doggo` at `.actions[0]`: expected one of `*`, `search`, `documents.*`, `documents.add`, `documents.get`, `documents.delete`, `indexes.*`, `indexes.create`, `indexes.get`, `indexes.update`, `indexes.delete`, `indexes.swap`, `tasks.*`, `tasks.cancel`, `tasks.delete`, `tasks.get`, `settings.*`, `settings.get`, `settings.update`, `stats.*`, `stats.get`, `metrics.*`, `metrics.get`, `dumps.*`, `dumps.create`, `version`, `keys.create`, `keys.get`, `keys.update`, `keys.delete`", + "code": "invalid_api_key_actions", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_bad_indexes() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + // bad type + let (response, code) = server.add_api_key(json!({ "indexes": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.indexes`: expected an array, but found a string: `\"doggo\"`", + "code": "invalid_api_key_indexes", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_indexes" + } + "###); + + // can't parse + let (response, code) = server.add_api_key(json!({ "indexes": ["good doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value at `.indexes[0]`: `good doggo` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_).", + "code": "invalid_api_key_indexes", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_indexes" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_bad_expires_at() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + // bad type + let (response, code) = server.add_api_key(json!({ "expires_at": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown field `expires_at`: expected one of `description`, `name`, `uid`, `actions`, `indexes`, `expiresAt`", + "code": "bad_request", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#bad_request" + } + "###); + + // can't parse + let (response, code) = server.add_api_key(json!({ "expires_at": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown field `expires_at`: expected one of `description`, `name`, `uid`, `actions`, `indexes`, `expiresAt`", + "code": "bad_request", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#bad_request" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_missing_action() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = + server.add_api_key(json!({ "indexes": ["doggo"], "expiresAt": null })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Missing field `actions`", + "code": "missing_api_key_actions", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#missing_api_key_actions" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_missing_indexes() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server + .add_api_key(json!({ "uid": Uuid::nil() , "actions": ["*"], "expiresAt": null })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Missing field `indexes`", + "code": "missing_api_key_indexes", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#missing_api_key_indexes" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_missing_expires_at() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server + .add_api_key(json!({ "uid": Uuid::nil(), "actions": ["*"], "indexes": ["doggo"] })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Missing field `expiresAt`", + "code": "missing_api_key_expires_at", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#missing_api_key_expires_at" + } + "###); +} + +#[actix_rt::test] +async fn create_api_key_unexpected_field() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server + .add_api_key(json!({ "uid": Uuid::nil(), "actions": ["*"], "indexes": ["doggo"], "expiresAt": null, "doggo": "bork" })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown field `doggo`: expected one of `description`, `name`, `uid`, `actions`, `indexes`, `expiresAt`", + "code": "bad_request", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#bad_request" + } + "###); +} + +#[actix_rt::test] +async fn list_api_keys_bad_offset() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.list_api_keys("?offset=doggo").await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value in parameter `offset`: could not parse `doggo` as a positive integer", + "code": "invalid_api_key_offset", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_offset" + } + "###); +} + +#[actix_rt::test] +async fn list_api_keys_bad_limit() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.list_api_keys("?limit=doggo").await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value in parameter `limit`: could not parse `doggo` as a positive integer", + "code": "invalid_api_key_limit", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_limit" + } + "###); +} + +#[actix_rt::test] +async fn list_api_keys_unexpected_field() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.list_api_keys("?doggo=no_limit").await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown parameter `doggo`: expected one of `offset`, `limit`", + "code": "bad_request", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#bad_request" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_bad_description() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "description": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.description`: expected a string, but found an array: `[\"doggo\"]`", + "code": "invalid_api_key_description", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_description" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_bad_name() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "name": ["doggo"] })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Invalid value type at `.name`: expected a string, but found an array: `[\"doggo\"]`", + "code": "invalid_api_key_name", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_api_key_name" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_uid() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "uid": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `uid`: expected one of `description`, `name`", + "code": "immutable_api_key_uid", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_uid" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_actions() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "actions": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `actions`: expected one of `description`, `name`", + "code": "immutable_api_key_actions", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_actions" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_indexes() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "indexes": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `indexes`: expected one of `description`, `name`", + "code": "immutable_api_key_indexes", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_indexes" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_expires_at() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "expiresAt": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `expiresAt`: expected one of `description`, `name`", + "code": "immutable_api_key_expires_at", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_expires_at" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_created_at() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "createdAt": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `createdAt`: expected one of `description`, `name`", + "code": "immutable_api_key_created_at", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_created_at" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_immutable_updated_at() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "updatedAt": "doggo" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Immutable field `updatedAt`: expected one of `description`, `name`", + "code": "immutable_api_key_updated_at", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#immutable_api_key_updated_at" + } + "###); +} + +#[actix_rt::test] +async fn patch_api_keys_unknown_field() { + let mut server = Server::new_auth().await; + server.use_admin_key("MASTER_KEY").await; + + let (response, code) = server.patch_api_key("doggo", json!({ "doggo": "bork" })).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Unknown field `doggo`: expected one of `description`, `name`", + "code": "bad_request", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#bad_request" + } + "###); +} diff --git a/meilisearch/tests/auth/mod.rs b/meilisearch/tests/auth/mod.rs index dec02cf1f..422f92d6e 100644 --- a/meilisearch/tests/auth/mod.rs +++ b/meilisearch/tests/auth/mod.rs @@ -1,5 +1,6 @@ mod api_keys; mod authorization; +mod errors; mod payload; mod tenant_token; @@ -16,7 +17,7 @@ impl Server { /// Fetch and use the default admin key for nexts http requests. pub async fn use_admin_key(&mut self, master_key: impl AsRef) { self.use_api_key(master_key); - let (response, code) = self.list_api_keys().await; + let (response, code) = self.list_api_keys("").await; assert_eq!(200, code, "{:?}", response); let admin_key = &response["results"][1]["key"]; self.use_api_key(admin_key.as_str().unwrap()); @@ -37,8 +38,8 @@ impl Server { self.service.patch(url, content).await } - pub async fn list_api_keys(&self) -> (Value, StatusCode) { - let url = "/keys"; + pub async fn list_api_keys(&self, params: &str) -> (Value, StatusCode) { + let url = format!("/keys{params}"); self.service.get(url).await } diff --git a/meilisearch/tests/dumps/mod.rs b/meilisearch/tests/dumps/mod.rs index 0759454e8..06cb21f20 100644 --- a/meilisearch/tests/dumps/mod.rs +++ b/meilisearch/tests/dumps/mod.rs @@ -811,7 +811,7 @@ async fn import_dump_v5() { assert_eq!(code, 200); assert_eq!(stats, expected_stats); - let (keys, code) = server.list_api_keys().await; + let (keys, code) = server.list_api_keys("").await; assert_eq!(code, 200); let key = &keys["results"][0];