From a85d5b4981b3aa9555a5a701738d48aff3dada22 Mon Sep 17 00:00:00 2001 From: Irevoire Date: Wed, 26 Oct 2022 11:09:44 +0200 Subject: [PATCH] test the details of all tasks type --- .../src/routes/indexes/settings.rs | 1 + meilisearch-http/src/routes/swap_indexes.rs | 4 +- meilisearch-http/tests/common/server.rs | 46 +- meilisearch-http/tests/tasks/mod.rs | 594 ++++++++++++++++++ 4 files changed, 642 insertions(+), 3 deletions(-) diff --git a/meilisearch-http/src/routes/indexes/settings.rs b/meilisearch-http/src/routes/indexes/settings.rs index 4e33cb0b4..0eec5d5b8 100644 --- a/meilisearch-http/src/routes/indexes/settings.rs +++ b/meilisearch-http/src/routes/indexes/settings.rs @@ -439,6 +439,7 @@ pub async fn update_all( Some(&req), ); + println!("Registering a setting update"); let allow_index_creation = index_scheduler.filters().allow_index_creation; let index_uid = IndexUid::try_from(index_uid.into_inner())?.into_inner(); let task = KindWithContent::SettingsUpdate { diff --git a/meilisearch-http/src/routes/swap_indexes.rs b/meilisearch-http/src/routes/swap_indexes.rs index b958f5859..86d66910b 100644 --- a/meilisearch-http/src/routes/swap_indexes.rs +++ b/meilisearch-http/src/routes/swap_indexes.rs @@ -20,7 +20,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) { #[derive(Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SwapIndexesPayload { - swap: (String, String), + indexes: (String, String), } pub async fn swap_indexes( @@ -33,7 +33,7 @@ pub async fn swap_indexes( let mut indexes_set = HashSet::::default(); let mut unknown_indexes = HashSet::new(); let mut duplicate_indexes = HashSet::new(); - for SwapIndexesPayload { swap: (lhs, rhs) } in params.into_inner().into_iter() { + for SwapIndexesPayload { indexes: (lhs, rhs) } in params.into_inner().into_iter() { if !search_rules.is_index_authorized(&lhs) { unknown_indexes.insert(lhs.clone()); } diff --git a/meilisearch-http/tests/common/server.rs b/meilisearch-http/tests/common/server.rs index 599b32e8f..8d2f68c5e 100644 --- a/meilisearch-http/tests/common/server.rs +++ b/meilisearch-http/tests/common/server.rs @@ -1,6 +1,13 @@ #![allow(dead_code)] use std::path::Path; +<<<<<<< HEAD +||||||| parent of 931d5622 (test the details of all tasks type) +use std::sync::Arc; +======= +use std::sync::Arc; +use std::time::Duration; +>>>>>>> 931d5622 (test the details of all tasks type) use actix_http::body::MessageBody; use actix_web::dev::ServiceResponse; @@ -10,8 +17,9 @@ use clap::Parser; use meilisearch_http::option::{IndexerOpts, MaxMemory, Opt}; use meilisearch_http::{analytics, create_app, setup_meilisearch}; use once_cell::sync::Lazy; -use serde_json::Value; +use serde_json::{json, Value}; use tempfile::TempDir; +use tokio::time::sleep; use super::index::Index; use super::service::Service; @@ -133,6 +141,42 @@ impl Server { pub async fn get_dump_status(&self, uid: &str) -> (Value, StatusCode) { self.service.get(format!("/dumps/{}/status", uid)).await } + + pub async fn create_dump(&self) -> (Value, StatusCode) { + self.service.post("/dumps", json!(null)).await + } + + pub async fn index_swap(&self, value: Value) -> (Value, StatusCode) { + self.service.post("/swap-indexes", value).await + } + + pub async fn cancel_task(&self, value: Value) -> (Value, StatusCode) { + self.service + .post(format!("/tasks/cancel?{}", yaup::to_string(&value).unwrap()), json!(null)) + .await + } + + pub async fn wait_task(&self, update_id: u64) -> Value { + // try several times to get status, or panic to not wait forever + let url = format!("/tasks/{}", update_id); + for _ in 0..100 { + let (response, status_code) = self.service.get(&url).await; + assert_eq!(200, status_code, "response: {}", response); + + if response["status"] == "succeeded" || response["status"] == "failed" { + return response; + } + + // wait 0.5 second. + sleep(Duration::from_millis(500)).await; + } + panic!("Timeout waiting for update id"); + } + + pub async fn get_task(&self, update_id: u64) -> (Value, StatusCode) { + let url = format!("/tasks/{}", update_id); + self.service.get(url).await + } } pub fn default_settings(dir: impl AsRef) -> Opt { diff --git a/meilisearch-http/tests/tasks/mod.rs b/meilisearch-http/tests/tasks/mod.rs index e0828c440..bb0720164 100644 --- a/meilisearch-http/tests/tasks/mod.rs +++ b/meilisearch-http/tests/tasks/mod.rs @@ -1,3 +1,5 @@ +use meili_snap::insta::assert_json_snapshot; +use meili_snap::snapshot; use serde_json::json; use time::format_description::well_known::Rfc3339; use time::OffsetDateTime; @@ -214,3 +216,595 @@ async fn test_summarized_task_view() { let (response, _) = index.delete().await; assert_valid_summarized_task!(response, "indexDeletion", "test"); } + +#[actix_web::test] +async fn test_summarized_document_addition_or_update() { + let server = Server::new().await; + let index = server.index("test"); + index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "details": { + "receivedDocuments": 1, + "indexedDocuments": 1 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; + index.wait_task(1).await; + let (task, _) = index.get_task(1).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 1, + "indexUid": "test", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "details": { + "receivedDocuments": 1, + "indexedDocuments": 1 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_delete_batch() { + let server = Server::new().await; + let index = server.index("test"); + index.delete_batch(vec![1, 2, 3]).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "failed", + "type": "documentDeletion", + "details": { + "matchedDocuments": 3, + "deletedDocuments": null + }, + "error": { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.create(None).await; + index.delete_batch(vec![42]).await; + index.wait_task(2).await; + let (task, _) = index.get_task(2).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 2, + "indexUid": "test", + "status": "succeeded", + "type": "documentDeletion", + "details": { + "matchedDocuments": 1, + "deletedDocuments": 0 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_delete_document() { + let server = Server::new().await; + let index = server.index("test"); + index.delete_document(1).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "failed", + "type": "documentDeletion", + "details": { + "matchedDocuments": 1, + "deletedDocuments": null + }, + "error": { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.create(None).await; + index.delete_document(42).await; + index.wait_task(2).await; + let (task, _) = index.get_task(2).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 2, + "indexUid": "test", + "status": "succeeded", + "type": "documentDeletion", + "details": { + "matchedDocuments": 1, + "deletedDocuments": 0 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_settings_update() { + let server = Server::new().await; + let index = server.index("test"); + // here we should find my payload even in the failed task. + index.update_settings(json!({ "rankingRules": ["custom"] })).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + dbg!(&task); + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "failed", + "type": "settingsUpdate", + "details": { + "rankingRules": [ + "custom" + ] + }, + "error": { + "message": "`custom` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.", + "code": "invalid_ranking_rule", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_ranking_rule" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await; + index.wait_task(1).await; + let (task, _) = index.get_task(1).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 1, + "indexUid": "test", + "status": "succeeded", + "type": "settingsUpdate", + "details": { + "displayedAttributes": [ + "doggos", + "name" + ], + "filterableAttributes": [ + "age", + "nb_paw_pads" + ], + "sortableAttributes": [ + "iq" + ] + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_index_creation() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "succeeded", + "type": "indexCreation", + "details": { + "primaryKey": null + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.create(Some("doggos")).await; + index.wait_task(1).await; + let (task, _) = index.get_task(1).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 1, + "indexUid": "test", + "status": "failed", + "type": "indexCreation", + "details": { + "primaryKey": "doggos" + }, + "error": { + "message": "Index `test` already exists.", + "code": "index_already_exists", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_already_exists" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_index_deletion() { + let server = Server::new().await; + let index = server.index("test"); + index.delete().await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "failed", + "type": "indexDeletion", + "error": { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // is the details correctly set when documents are actually deleted. + index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; + index.delete().await; + index.wait_task(2).await; + let (task, _) = index.get_task(2).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 2, + "indexUid": "test", + "status": "succeeded", + "type": "indexDeletion", + "details": { + "deletedDocuments": 1 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // What happens when you delete an index that doesn't exists. + index.delete().await; + index.wait_task(2).await; + let (task, _) = index.get_task(2).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 2, + "indexUid": "test", + "status": "succeeded", + "type": "indexDeletion", + "details": { + "deletedDocuments": 1 + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_index_update() { + let server = Server::new().await; + let index = server.index("test"); + // If the index doesn't exist yet, we should get errors with or without the primary key. + index.update(None).await; + index.wait_task(0).await; + let (task, _) = index.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "failed", + "type": "indexUpdate", + "details": { + "primaryKey": null + }, + "error": { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.update(Some("bones")).await; + index.wait_task(1).await; + let (task, _) = index.get_task(1).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 1, + "indexUid": "test", + "status": "failed", + "type": "indexUpdate", + "details": { + "primaryKey": "bones" + }, + "error": { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // And run the same two tests once the index do exists. + index.create(None).await; + + index.update(None).await; + index.wait_task(3).await; + let (task, _) = index.get_task(3).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 3, + "indexUid": "test", + "status": "succeeded", + "type": "indexUpdate", + "details": { + "primaryKey": null + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + index.update(Some("bones")).await; + index.wait_task(4).await; + let (task, _) = index.get_task(4).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 4, + "indexUid": "test", + "status": "succeeded", + "type": "indexUpdate", + "details": { + "primaryKey": "bones" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +async fn test_summarized_index_swap() { + let server = Server::new().await; + let (v, _) = server + .index_swap(json!([ + { "indexes": ["doggos", "cattos"] } + ])) + .await; + dbg!(v); + server.wait_task(0).await; + let (task, _) = server.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": null, + "status": "failed", + "type": "indexSwap", + "details": { + "indexes": [ + [ + "doggos", + "cattos" + ] + ] + }, + "error": { + "message": "Index `doggos` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index_not_found" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + server.index("doggos").create(None).await; + server.index("cattos").create(None).await; + server + .index_swap(json!([ + { "indexes": ["doggos", "cattos"] } + ])) + .await; + server.wait_task(3).await; + let (task, _) = server.get_task(3).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 3, + "indexUid": null, + "status": "succeeded", + "type": "indexSwap", + "details": { + "indexes": [ + [ + "doggos", + "cattos" + ] + ] + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +} + +#[actix_web::test] +#[ignore] +async fn test_summarized_task_cancelation() { + let server = Server::new().await; + let index = server.index("doggos"); + // to avoid being flaky we're only going to test to cancel an already finished task :( + index.create(None).await; + index.wait_task(0).await; + let (ret, code) = server.cancel_task(json!({ "uid": [0] })).await; + dbg!(ret, code); + index.wait_task(1).await; + let (task, _) = index.get_task(1).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": "test", + "status": "succeeded", + "type": "indexCreation", + "details": { + "primaryKey": null + }, + "duration": "PT0.002782S", + "enqueuedAt": "2022-10-25T15:23:26.898722Z", + "startedAt": "2022-10-25T15:23:26.90063Z", + "finishedAt": "2022-10-25T15:23:26.903412Z" + } + "###); +} + +#[actix_web::test] +#[ignore] +async fn test_summarized_task_deletion() { + let server = Server::new().await; + +} + +#[actix_web::test] +async fn test_summarized_dump_creation() { + let server = Server::new().await; + server.create_dump().await; + server.wait_task(0).await; + let (task, _) = server.get_task(0).await; + assert_json_snapshot!(task, + { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }, + @r###" + { + "uid": 0, + "indexUid": null, + "status": "succeeded", + "type": "dumpCreation", + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); +}