use crate::common::Server; use assert_json_diff::assert_json_include; use serde_json::json; use std::{thread, time}; #[actix_rt::test] async fn add_valid_api_key() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let expected_response = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected_response); assert_eq!(code, 201); } #[actix_rt::test] async fn add_valid_api_key_expired_at() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13" }); let (response, code) = server.add_api_key(content).await; assert!(response["key"].is_string(), "{:?}", response); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let expected_response = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected_response); assert_eq!(code, 201); } #[actix_rt::test] async fn add_valid_api_key_no_description() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": "2050-11-13T00:00:00" }); let (response, code) = server.add_api_key(content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let expected_response = json!({ "actions": [ "documents.add" ], "indexes": [ "products" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected_response); assert_eq!(code, 201); } #[actix_rt::test] async fn error_add_api_key_no_header() { let server = Server::new_auth().await; let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); assert_eq!(response, expected_response); assert_eq!(code, 401); } #[actix_rt::test] async fn error_add_api_key_bad_key() { let mut server = Server::new_auth().await; server.use_api_key("d4000bd7225f77d1eb22cc706ed36772bbc36767c016a27f76def7537b68600d"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); assert_eq!(response, expected_response); assert_eq!(code, 403); } #[actix_rt::test] async fn error_add_api_key_missing_parameter() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); // missing indexes let content = json!({ "description": "Indexing API key", "actions": ["documents.add"], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": "`indexes` field is mandatory.", "code": "missing_parameter", "type": "invalid_request", "link":"https://docs.meilisearch.com/errors#missing_parameter" }); assert_eq!(response, expected_response); assert_eq!(code, 400); // missing actions let content = json!({ "description": "Indexing API key", "indexes": ["products"], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": "`actions` field is mandatory.", "code": "missing_parameter", "type": "invalid_request", "link":"https://docs.meilisearch.com/errors#missing_parameter" }); assert_eq!(response, expected_response); assert_eq!(code, 400); // missing expiration date let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": ["documents.add"], }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": "`expiresAt` field is mandatory.", "code": "missing_parameter", "type": "invalid_request", "link":"https://docs.meilisearch.com/errors#missing_parameter" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_add_api_key_invalid_parameters_description() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": {"name":"products"}, "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"description field value `{"name":"products"}` is invalid. It should be a string or specified as a null value."#, "code": "invalid_api_key_description", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_description" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_add_api_key_invalid_parameters_indexes() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": {"name":"products"}, "actions": [ "documents.add" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"indexes field value `{"name":"products"}` is invalid. It should be an array of string representing index names."#, "code": "invalid_api_key_indexes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_indexes" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_add_api_key_invalid_parameters_actions() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": {"name":"products"}, "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"actions field value `{"name":"products"}` is invalid. It should be an array of string representing action names."#, "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" }); assert_eq!(response, expected_response); assert_eq!(code, 400); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "doc.add" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"actions field value `["doc.add"]` is invalid. It should be an array of string representing action names."#, "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_add_api_key_invalid_parameters_expires_at() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": {"name":"products"} }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"expiresAt field value `{"name":"products"}` is invalid. It should be in ISO-8601 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:MM:SS'."#, "code": "invalid_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_expires_at" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_add_api_key_invalid_parameters_expires_at_in_the_past() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "documents.add" ], "expiresAt": "2010-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; let expected_response = json!({ "message": r#"expiresAt field value `"2010-11-13T00:00:00Z"` is invalid. It should be in ISO-8601 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:MM:SS'."#, "code": "invalid_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_expires_at" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn get_api_key() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); let key = response["key"].as_str().unwrap(); let (response, code) = server.get_api_key(&key).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let expected_response = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected_response); assert_eq!(code, 200); } #[actix_rt::test] async fn error_get_api_key_no_header() { let server = Server::new_auth().await; let (response, code) = server .get_api_key("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); assert_eq!(response, expected_response); assert_eq!(code, 401); } #[actix_rt::test] async fn error_get_api_key_bad_key() { let mut server = Server::new_auth().await; server.use_api_key("d4000bd7225f77d1eb22cc706ed36772bbc36767c016a27f76def7537b68600d"); let (response, code) = server .get_api_key("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); assert_eq!(response, expected_response); assert_eq!(code, 403); } #[actix_rt::test] async fn error_get_api_key_not_found() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let (response, code) = server .get_api_key("d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "API key `d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4` not found.", "code": "api_key_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#api_key_not_found" }); assert_eq!(response, expected_response); assert_eq!(code, 404); } #[actix_rt::test] async fn list_api_keys() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (_response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); let (response, code) = server.list_api_keys().await; let expected_response = json!({ "results": [ { "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }, { "description": "Default Search API Key (Use it to search from the frontend)", "indexes": ["*"], "actions": ["search"], "expiresAt": serde_json::Value::Null, }, { "description": "Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)", "indexes": ["*"], "actions": ["*"], "expiresAt": serde_json::Value::Null, } ]}); assert_json_include!(actual: response, expected: expected_response); assert_eq!(code, 200); } #[actix_rt::test] async fn error_list_api_keys_no_header() { let server = Server::new_auth().await; let (response, code) = server.list_api_keys().await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); assert_eq!(response, expected_response); assert_eq!(code, 401); } #[actix_rt::test] 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 expected_response = json!({ "message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); assert_eq!(response, expected_response); assert_eq!(code, 403); } #[actix_rt::test] async fn delete_api_key() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "tasks.get", "settings.get", "settings.update", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); let key = response["key"].as_str().unwrap(); let (_response, code) = server.delete_api_key(&key).await; assert_eq!(code, 204); // check if API key no longer exist. let (_response, code) = server.get_api_key(&key).await; assert_eq!(code, 404); } #[actix_rt::test] async fn error_delete_api_key_no_header() { let server = Server::new_auth().await; let (response, code) = server .delete_api_key("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); assert_eq!(response, expected_response); assert_eq!(code, 401); } #[actix_rt::test] async fn error_delete_api_key_bad_key() { let mut server = Server::new_auth().await; server.use_api_key("d4000bd7225f77d1eb22cc706ed36772bbc36767c016a27f76def7537b68600d"); let (response, code) = server .delete_api_key("d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); assert_eq!(response, expected_response); assert_eq!(code, 403); } #[actix_rt::test] async fn error_delete_api_key_not_found() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let (response, code) = server .delete_api_key("d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4") .await; let expected_response = json!({ "message": "API key `d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4` not found.", "code": "api_key_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#api_key_not_found" }); assert_eq!(response, expected_response); assert_eq!(code, 404); } #[actix_rt::test] async fn patch_api_key_description() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let key = response["key"].as_str().unwrap(); let created_at = response["createdAt"].as_str().unwrap(); let updated_at = response["updatedAt"].as_str().unwrap(); // Add a description let content = json!({ "description": "Indexing API key" }); thread::sleep(time::Duration::new(1, 0)); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert_ne!(response["updatedAt"].as_str().unwrap(), updated_at); assert_eq!(response["createdAt"].as_str().unwrap(), created_at); let expected = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); // Change the description let content = json!({ "description": "Porduct API key" }); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); let expected = json!({ "description": "Porduct API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); // Remove the description let content = json!({ "description": serde_json::Value::Null }); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); let expected = json!({ "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); } #[actix_rt::test] async fn patch_api_key_indexes() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let key = response["key"].as_str().unwrap(); let created_at = response["createdAt"].as_str().unwrap(); let updated_at = response["updatedAt"].as_str().unwrap(); let content = json!({ "indexes": ["products", "prices"] }); thread::sleep(time::Duration::new(1, 0)); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert_ne!(response["updatedAt"].as_str().unwrap(), updated_at); assert_eq!(response["createdAt"].as_str().unwrap(), created_at); let expected = json!({ "description": "Indexing API key", "indexes": ["products", "prices"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); } #[actix_rt::test] async fn patch_api_key_actions() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let key = response["key"].as_str().unwrap(); let created_at = response["createdAt"].as_str().unwrap(); let updated_at = response["updatedAt"].as_str().unwrap(); let content = json!({ "actions": [ "search", "documents.get", "indexes.get", "tasks.get", "settings.get", ], }); thread::sleep(time::Duration::new(1, 0)); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert_ne!(response["updatedAt"].as_str().unwrap(), updated_at); assert_eq!(response["createdAt"].as_str().unwrap(), created_at); let expected = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.get", "indexes.get", "tasks.get", "settings.get", ], "expiresAt": "2050-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); } #[actix_rt::test] async fn patch_api_key_expiration_date() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); assert!(response["createdAt"].is_string()); assert!(response["updatedAt"].is_string()); let key = response["key"].as_str().unwrap(); let created_at = response["createdAt"].as_str().unwrap(); let updated_at = response["updatedAt"].as_str().unwrap(); let content = json!({ "expiresAt": "2055-11-13T00:00:00Z" }); thread::sleep(time::Duration::new(1, 0)); let (response, code) = server.patch_api_key(&key, content).await; assert!(response["key"].is_string()); assert!(response["expiresAt"].is_string()); assert!(response["createdAt"].is_string()); assert_ne!(response["updatedAt"].as_str().unwrap(), updated_at); assert_eq!(response["createdAt"].as_str().unwrap(), created_at); let expected = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", "documents.add", "documents.get", "documents.delete", "indexes.create", "indexes.get", "indexes.update", "indexes.delete", "stats.get", "dumps.create", "dumps.get" ], "expiresAt": "2055-11-13T00:00:00Z" }); assert_json_include!(actual: response, expected: expected); assert_eq!(code, 200); } #[actix_rt::test] async fn error_patch_api_key_no_header() { let server = Server::new_auth().await; let (response, code) = server .patch_api_key( "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", json!({}), ) .await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); assert_eq!(response, expected_response); assert_eq!(code, 401); } #[actix_rt::test] async fn error_patch_api_key_bad_key() { let mut server = Server::new_auth().await; server.use_api_key("d4000bd7225f77d1eb22cc706ed36772bbc36767c016a27f76def7537b68600d"); let (response, code) = server .patch_api_key( "d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", json!({}), ) .await; let expected_response = json!({ "message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); assert_eq!(response, expected_response); assert_eq!(code, 403); } #[actix_rt::test] async fn error_patch_api_key_not_found() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let (response, code) = server .patch_api_key( "d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4", json!({}), ) .await; let expected_response = json!({ "message": "API key `d0552b41d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4` not found.", "code": "api_key_not_found", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#api_key_not_found" }); assert_eq!(response, expected_response); assert_eq!(code, 404); } #[actix_rt::test] async fn error_patch_api_key_indexes_invalid_parameters() { let mut server = Server::new_auth().await; server.use_api_key("MASTER_KEY"); let content = json!({ "description": "Indexing API key", "indexes": ["products"], "actions": [ "search", ], "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await; // must pass if add_valid_api_key test passes. assert_eq!(code, 201); assert!(response["key"].is_string()); let key = response["key"].as_str().unwrap(); // invalid description let content = json!({ "description": 13 }); let (response, code) = server.patch_api_key(&key, content).await; let expected_response = json!({ "message": "description field value `13` is invalid. It should be a string or specified as a null value.", "code": "invalid_api_key_description", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_description" }); assert_eq!(response, expected_response); assert_eq!(code, 400); // invalid indexes let content = json!({ "indexes": 13 }); let (response, code) = server.patch_api_key(&key, content).await; let expected_response = json!({ "message": "indexes field value `13` is invalid. It should be an array of string representing index names.", "code": "invalid_api_key_indexes", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_indexes" }); assert_eq!(response, expected_response); assert_eq!(code, 400); // invalid actions let content = json!({ "actions": 13 }); let (response, code) = server.patch_api_key(&key, content).await; let expected_response = json!({ "message": "actions field value `13` is invalid. It should be an array of string representing action names.", "code": "invalid_api_key_actions", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_actions" }); assert_eq!(response, expected_response); assert_eq!(code, 400); // invalid expiresAt let content = json!({ "expiresAt": 13 }); let (response, code) = server.patch_api_key(&key, content).await; let expected_response = json!({ "message": "expiresAt field value `13` is invalid. It should be in ISO-8601 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DDTHH:MM:SS'.", "code": "invalid_api_key_expires_at", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_api_key_expires_at" }); assert_eq!(response, expected_response); assert_eq!(code, 400); } #[actix_rt::test] async fn error_access_api_key_routes_no_master_key_set() { let mut server = Server::new().await; let expected_response = json!({ "message": "The Authorization header is missing. It must use the bearer authorization method.", "code": "missing_authorization_header", "type": "auth", "link": "https://docs.meilisearch.com/errors#missing_authorization_header" }); let expected_code = 401; let (response, code) = server.add_api_key(json!({})).await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.patch_api_key("content", json!({})).await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.get_api_key("content").await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.list_api_keys().await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); server.use_api_key("MASTER_KEY"); let expected_response = json!({"message": "The provided API key is invalid.", "code": "invalid_api_key", "type": "auth", "link": "https://docs.meilisearch.com/errors#invalid_api_key" }); let expected_code = 403; let (response, code) = server.add_api_key(json!({})).await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.patch_api_key("content", json!({})).await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.get_api_key("content").await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); let (response, code) = server.list_api_keys().await; assert_eq!(response, expected_response); assert_eq!(code, expected_code); }