From 3ebff65ef313b3ef4f54d5ea8c920f924e573654 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:28:30 +0300 Subject: [PATCH 01/11] tests: Faster search::filters IT tests Use shared server + unique indices Related-to: https://github.com/meilisearch/meilisearch/issues/4840 Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 62 +++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 49409efa6..1e2fac998 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -10,17 +10,17 @@ use crate::{ #[actix_rt::test] async fn search_with_filter_string_notation() { - let server = Server::new().await; - let index = server.index("test"); + let server = Server::new_shared(); + let index = server.unique_index(); let (_, code) = index.update_settings(json!({"filterableAttributes": ["title"]})).await; - meili_snap::snapshot!(code, @"202 Accepted"); + snapshot!(code, @"202 Accepted"); let documents = DOCUMENTS.clone(); let (task, code) = index.add_documents(documents, None).await; - meili_snap::snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await; - meili_snap::snapshot!(res["status"], @r###""succeeded""###); + snapshot!(code, @"202 Accepted"); + let res = index.wait_task(task.uid()).await.succeeded(); + snapshot!(res["status"], @r###""succeeded""###); index .search( @@ -28,44 +28,44 @@ async fn search_with_filter_string_notation() { "filter": "title = Gläss" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }, ) .await; - let index = server.index("nested"); + let nested_index = server.unique_index(); let (_, code) = - index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; - meili_snap::snapshot!(code, @"202 Accepted"); + nested_index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; + snapshot!(code, @"202 Accepted"); let documents = NESTED_DOCUMENTS.clone(); - let (task, code) = index.add_documents(documents, None).await; - meili_snap::snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await; - meili_snap::snapshot!(res["status"], @r###""succeeded""###); + let (task, code) = nested_index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let res = nested_index.wait_task(task.uid()).await.succeeded(); + snapshot!(res["status"], @r###""succeeded""###); - index + nested_index .search( json!({ "filter": "cattos = pésti" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); assert_eq!(response["hits"][0]["id"], json!(852)); }, ) .await; - index + nested_index .search( json!({ "filter": "doggos.age > 5" }), |response, code| { - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); assert_eq!(response["hits"][0]["id"], json!(654)); assert_eq!(response["hits"][1]["id"], json!(951)); @@ -82,7 +82,7 @@ async fn search_with_filter_array_notation() { "filter": ["title = Gläss"] })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 1); let (response, code) = index @@ -90,7 +90,7 @@ async fn search_with_filter_array_notation() { "filter": [["title = Gläss", "title = \"Shazam!\"", "title = \"Escape Room\""]] })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 3); } @@ -116,7 +116,7 @@ async fn search_with_contains_filter() { "filter": "title CONTAINS cap" })) .await; - assert_eq!(code, 200, "{}", response); + assert_eq!(code, 200, "{response}"); assert_eq!(response["hits"].as_array().unwrap().len(), 2); } @@ -276,8 +276,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { let index = server.index("test"); let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); let (task, code) = index @@ -289,8 +289,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works @@ -355,8 +355,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works @@ -467,8 +467,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter returns an error @@ -567,8 +567,8 @@ async fn search_with_pattern_filter_settings_scenario_1() { } }]})) .await; - assert_eq!(code, 202, "{}", task); - let response = index.wait_task(task.uid()).await; + assert_eq!(code, 202, "{task}"); + let response = index.wait_task(task.uid()).await.succeeded(); snapshot!(response["status"], @r###""succeeded""###); // Check if the Equality filter works From b41af0d0f6cb1e315d002b2fd70bb472274d56c0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Mon, 2 Jun 2025 15:57:43 +0300 Subject: [PATCH 02/11] Formatting Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 1e2fac998..19a6ad775 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -36,8 +36,9 @@ async fn search_with_filter_string_notation() { let nested_index = server.unique_index(); - let (_, code) = - nested_index.update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})).await; + let (_, code) = nested_index + .update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})) + .await; snapshot!(code, @"202 Accepted"); let documents = NESTED_DOCUMENTS.clone(); From 3f256a79592e4e6527da67855eaf6cad9b5650a0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 13:51:34 +0300 Subject: [PATCH 03/11] Use the shared index with DOCUMENTS where possible Remove useless assertion that is covered by the earlier call of .succeeded() Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 32 ++++++---------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 19a6ad775..f6ce5d0b7 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,6 +3,7 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; +use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, @@ -10,17 +11,7 @@ use crate::{ #[actix_rt::test] async fn search_with_filter_string_notation() { - let server = Server::new_shared(); - let index = server.unique_index(); - - let (_, code) = index.update_settings(json!({"filterableAttributes": ["title"]})).await; - snapshot!(code, @"202 Accepted"); - - let documents = DOCUMENTS.clone(); - let (task, code) = index.add_documents(documents, None).await; - snapshot!(code, @"202 Accepted"); - let res = index.wait_task(task.uid()).await.succeeded(); - snapshot!(res["status"], @r###""succeeded""###); + let index = shared_index_with_documents().await; index .search( @@ -34,6 +25,7 @@ async fn search_with_filter_string_notation() { ) .await; + let server = Server::new_shared(); let nested_index = server.unique_index(); let (_, code) = nested_index @@ -44,8 +36,7 @@ async fn search_with_filter_string_notation() { let documents = NESTED_DOCUMENTS.clone(); let (task, code) = nested_index.add_documents(documents, None).await; snapshot!(code, @"202 Accepted"); - let res = nested_index.wait_task(task.uid()).await.succeeded(); - snapshot!(res["status"], @r###""succeeded""###); + nested_index.wait_task(task.uid()).await.succeeded(); nested_index .search( @@ -278,8 +269,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); let (task, code) = index .update_settings(json!({"filterableAttributes": [{ @@ -291,8 +281,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index @@ -357,8 +346,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index @@ -469,8 +457,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter returns an error index @@ -569,8 +556,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { }]})) .await; assert_eq!(code, 202, "{task}"); - let response = index.wait_task(task.uid()).await.succeeded(); - snapshot!(response["status"], @r###""succeeded""###); + index.wait_task(task.uid()).await.succeeded(); // Check if the Equality filter works index From a15ebb283f2b7087be3c5247698a6176d200d864 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Wed, 4 Jun 2025 14:17:01 +0300 Subject: [PATCH 04/11] Remove unused import Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index f6ce5d0b7..26f7c88e4 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,7 +3,6 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; -use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, From e497008161b4f1e4f213d1baa0088c40fb98e239 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 5 Jun 2025 11:28:29 +0300 Subject: [PATCH 05/11] Add `cattos` to the shared_index_with_nested_documents() as a filterable attribute This allows to make some more search::filters IT tests using shared server + unique/shared indices Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/mod.rs | 2 +- crates/meilisearch/tests/search/filters.rs | 25 ++++++---------------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/crates/meilisearch/tests/common/mod.rs b/crates/meilisearch/tests/common/mod.rs index 00e4732d0..373f89f78 100644 --- a/crates/meilisearch/tests/common/mod.rs +++ b/crates/meilisearch/tests/common/mod.rs @@ -352,7 +352,7 @@ pub async fn shared_index_with_nested_documents() -> &'static Index<'static, Sha index.wait_task(response.uid()).await.succeeded(); let (response, _code) = index ._update_settings( - json!({"filterableAttributes": ["father", "doggos"], "sortableAttributes": ["doggos"]}), + json!({"filterableAttributes": ["father", "doggos", "cattos"], "sortableAttributes": ["doggos"]}), ) .await; index.wait_task(response.uid()).await.succeeded(); diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 26f7c88e4..3df80b90c 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,6 +3,7 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; +use crate::common::shared_index_with_nested_documents; use crate::{ common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, json, @@ -24,18 +25,7 @@ async fn search_with_filter_string_notation() { ) .await; - let server = Server::new_shared(); - let nested_index = server.unique_index(); - - let (_, code) = nested_index - .update_settings(json!({"filterableAttributes": ["cattos", "doggos.age"]})) - .await; - snapshot!(code, @"202 Accepted"); - - let documents = NESTED_DOCUMENTS.clone(); - let (task, code) = nested_index.add_documents(documents, None).await; - snapshot!(code, @"202 Accepted"); - nested_index.wait_task(task.uid()).await.succeeded(); + let nested_index = shared_index_with_nested_documents().await; nested_index .search( @@ -260,11 +250,10 @@ async fn search_with_pattern_filter_settings() { #[actix_rt::test] async fn search_with_pattern_filter_settings_scenario_1() { - let temp = TempDir::new().unwrap(); - let server = Server::new_with_options(Opt { ..default_settings(temp.path()) }).await.unwrap(); + let server = Server::new_shared(); eprintln!("Documents -> Settings -> test"); - let index = server.index("test"); + let index = server.unique_index(); let (task, code) = index.add_documents(NESTED_DOCUMENTS.clone(), None).await; assert_eq!(code, 202, "{task}"); @@ -324,7 +313,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -468,7 +457,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `=` is not allowed for the attribute `cattos`.\n - Note: allowed operators: OR, AND, NOT, <, >, <=, >=, TO, IS EMPTY, IS NULL, EXISTS.\n - Note: field `cattos` matched rule #0 in `filterableAttributes`\n - Hint: enable equality in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `cattos` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" @@ -599,7 +588,7 @@ async fn search_with_pattern_filter_settings_scenario_1() { snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", + "message": "Index `[uuid]`: Filter operator `>` is not allowed for the attribute `doggos.age`.\n - Note: allowed operators: OR, AND, NOT, =, !=, IN, IS EMPTY, IS NULL, EXISTS.\n - Note: field `doggos.age` matched rule #0 in `filterableAttributes`\n - Hint: enable comparison in rule #0 by modifying the features.filter object\n - Hint: prepend another rule matching `doggos.age` with appropriate filter features before rule #0", "code": "invalid_search_filter", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#invalid_search_filter" From 3770e705818cce2735ba4fa544249d78a752c80b Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Thu, 5 Jun 2025 11:30:39 +0300 Subject: [PATCH 06/11] Optimize the imports Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/search/filters.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/search/filters.rs b/crates/meilisearch/tests/search/filters.rs index 3df80b90c..9670a036c 100644 --- a/crates/meilisearch/tests/search/filters.rs +++ b/crates/meilisearch/tests/search/filters.rs @@ -3,9 +3,11 @@ use meilisearch::Opt; use tempfile::TempDir; use super::test_settings_documents_indexing_swapping_and_search; -use crate::common::shared_index_with_nested_documents; use crate::{ - common::{default_settings, shared_index_with_documents, Server, DOCUMENTS, NESTED_DOCUMENTS}, + common::{ + default_settings, shared_index_with_documents, shared_index_with_nested_documents, Server, + DOCUMENTS, NESTED_DOCUMENTS, + }, json, }; From 89c0cf9b12159932951914bffa9b3d7eb6020bb0 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 09:51:18 +0300 Subject: [PATCH 07/11] temporary: Dump the threads stack traces when .wait_task() times out Signed-off-by: Martin Tzvetanov Grigorov --- .cargo/config.toml | 3 +++ .github/workflows/test-suite.yml | 2 ++ crates/meilisearch/tests/common/server.rs | 16 ++++++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index e11d56a31..b172ee2af 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,5 @@ [alias] xtask = "run --release --package xtask --" + +[build] +rustflags = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"] diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 6cf8bfa0f..100068965 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -158,6 +158,8 @@ jobs: uses: Swatinem/rust-cache@v2.7.8 - name: Run tests in debug uses: actions-rs/cargo@v1 + env: + RUSTFLAGS: "--cfg tokio_unstable --cfg tokio_taskdump" with: command: test args: --locked --all diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 7e30c5d17..02ea2f79a 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -400,12 +400,8 @@ impl Server { // try several times to get status, or panic to not wait forever let url = format!("/tasks/{}", update_id); // Increase timeout for vector-related tests - let max_attempts = if url.contains("/tasks/") { - if update_id > 1000 { - 400 // 200 seconds for vector tests - } else { - 100 // 50 seconds for other tests - } + let max_attempts = if update_id > 1000 { + 400 // 200 seconds for vector tests } else { 100 // 50 seconds for other tests }; @@ -421,6 +417,14 @@ impl Server { // wait 0.5 second. sleep(Duration::from_millis(500)).await; } + let handle = tokio::runtime::Handle::current(); + if let Ok(dump) = tokio::time::timeout(Duration::from_secs(2), handle.dump()).await { + for (i, task) in dump.tasks().iter().enumerate() { + let trace = task.trace(); + println!("TASK {i}:"); + println!("{trace}\n"); + } + } panic!("Timeout waiting for update id"); } From 1b4d344e18bf58f3202bcbe706863f16598ca558 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 11:42:54 +0300 Subject: [PATCH 08/11] Increase the wait time in the tests Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 02ea2f79a..1bfbf7641 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -403,7 +403,7 @@ impl Server { let max_attempts = if update_id > 1000 { 400 // 200 seconds for vector tests } else { - 100 // 50 seconds for other tests + 1000 // 50 seconds for other tests }; for _ in 0..max_attempts { From 63ccd19ab16ac7b336531d7485f06d749185987c Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 13:45:05 +0300 Subject: [PATCH 09/11] Use Server::wait_task() instead of Index::wait_task() for tasks IT tests Revert the debugging helper that dumped the thread stack traces. Try with 400 max attempts for the task success/failure (200 secs) Signed-off-by: Martin Tzvetanov Grigorov --- .cargo/config.toml | 3 -- .github/workflows/test-suite.yml | 2 - crates/meilisearch/tests/common/server.rs | 19 ++----- crates/meilisearch/tests/tasks/mod.rs | 66 ++++++++++++----------- 4 files changed, 39 insertions(+), 51 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index b172ee2af..e11d56a31 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,5 +1,2 @@ [alias] xtask = "run --release --package xtask --" - -[build] -rustflags = ["--cfg", "tokio_unstable", "--cfg", "tokio_taskdump"] diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml index 100068965..6cf8bfa0f 100644 --- a/.github/workflows/test-suite.yml +++ b/.github/workflows/test-suite.yml @@ -158,8 +158,6 @@ jobs: uses: Swatinem/rust-cache@v2.7.8 - name: Run tests in debug uses: actions-rs/cargo@v1 - env: - RUSTFLAGS: "--cfg tokio_unstable --cfg tokio_taskdump" with: command: test args: --locked --all diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 1bfbf7641..431972983 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,14 +399,9 @@ impl Server { 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); - // Increase timeout for vector-related tests - let max_attempts = if update_id > 1000 { - 400 // 200 seconds for vector tests - } else { - 1000 // 50 seconds for other tests - }; + let max_attempts = 400; // 200 seconds total, 0.5s per attempt - for _ in 0..max_attempts { + for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await; assert_eq!(200, status_code, "response: {}", response); @@ -416,13 +411,9 @@ impl Server { // wait 0.5 second. sleep(Duration::from_millis(500)).await; - } - let handle = tokio::runtime::Handle::current(); - if let Ok(dump) = tokio::time::timeout(Duration::from_secs(2), handle.dump()).await { - for (i, task) in dump.tasks().iter().enumerate() { - let trace = task.trace(); - println!("TASK {i}:"); - println!("{trace}\n"); + + if i == max_attempts - 1 { + dbg!(response); } } panic!("Timeout waiting for update id"); diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index c31e43883..064b52a1f 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -39,7 +39,7 @@ async fn get_task_status() { None, ) .await; - index.wait_task(create_task.uid()).await.succeeded(); + server.wait_task(create_task.uid()).await.succeeded(); let (_response, code) = index.get_task(add_task.uid()).await; assert_eq!(code, 200); // TODO check response format, as per #48 @@ -51,7 +51,7 @@ async fn list_tasks() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -105,7 +105,7 @@ async fn list_tasks_with_star_filters() { // Do not use a unique index here, as we want to test the `indexUids=*` filter. let index = server.index("test"); let (task, _code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -154,9 +154,9 @@ async fn list_tasks_status_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; assert_eq!(code, 200, "{response}"); @@ -177,7 +177,7 @@ async fn list_tasks_type_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -197,10 +197,12 @@ async fn list_tasks_invalid_canceled_by_filter() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); + let (task, _code) = index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; + server.wait_task(task.uid()).await.succeeded(); let (response, code) = index.filtered_tasks(&[], &[], &[format!("{}", task.uid()).as_str()]).await; @@ -214,7 +216,7 @@ async fn list_tasks_status_and_type_filtered() { let server = Server::new().await; let index = server.index("test"); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); index .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) .await; @@ -284,7 +286,7 @@ async fn test_summarized_document_addition_or_update() { let index = server.unique_index(); let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -309,7 +311,7 @@ async fn test_summarized_document_addition_or_update() { let (task, _status_code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -343,7 +345,7 @@ async fn test_summarized_delete_documents_by_batch() { let (task, _status_code) = index .delete_batch(vec![non_existing_task_id1, non_existing_task_id2, non_existing_task_id3]) .await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -374,7 +376,7 @@ async fn test_summarized_delete_documents_by_batch() { index.create(None).await; let (del_task, _status_code) = index.delete_batch(vec![42]).await; - index.wait_task(del_task.uid()).await.succeeded(); + server.wait_task(del_task.uid()).await.succeeded(); let (task, _) = index.get_task(del_task.uid()).await; snapshot!(task, @r###" @@ -406,7 +408,7 @@ async fn test_summarized_delete_documents_by_filter() { let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -438,7 +440,7 @@ async fn test_summarized_delete_documents_by_filter() { index.create(None).await; let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -470,7 +472,7 @@ async fn test_summarized_delete_documents_by_filter() { index.update_settings(json!({ "filterableAttributes": ["doggo"] })).await; let (task, _status_code) = index.delete_document_by_filter(json!({ "filter": "doggo = bernese" })).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -500,7 +502,7 @@ async fn test_summarized_delete_document_by_id() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.delete_document(1).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -531,7 +533,7 @@ async fn test_summarized_delete_document_by_id() { index.create(None).await; let (task, _status_code) = index.delete_document(42).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -573,7 +575,7 @@ async fn test_summarized_settings_update() { "###); let (task,_status_code) = index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -611,7 +613,7 @@ async fn test_summarized_index_creation() { let server = Server::new_shared(); let index = server.unique_index(); let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -634,7 +636,7 @@ async fn test_summarized_index_creation() { "###); let (task, _status_code) = index.create(Some("doggos")).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -667,7 +669,7 @@ async fn test_summarized_index_deletion() { let server = Server::new_shared(); let index = server.unique_index(); let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -698,7 +700,7 @@ async fn test_summarized_index_deletion() { // both tasks may get autobatched and the deleted documents count will be wrong. let (ret, _code) = index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -721,7 +723,7 @@ async fn test_summarized_index_deletion() { "###); let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -744,7 +746,7 @@ async fn test_summarized_index_deletion() { // What happens when you delete an index that doesn't exists. let (ret, _code) = index.delete().await; - let task = index.wait_task(ret.uid()).await; + let task = server.wait_task(ret.uid()).await; snapshot!(task, @r###" { @@ -777,7 +779,7 @@ async fn test_summarized_index_update() { let index = server.unique_index(); // If the index doesn't exist yet, we should get errors with or without the primary key. let (task, _status_code) = index.update(None).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -805,7 +807,7 @@ async fn test_summarized_index_update() { "###); let (task, _status_code) = index.update(Some("bones")).await; - index.wait_task(task.uid()).await.failed(); + server.wait_task(task.uid()).await.failed(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -836,7 +838,7 @@ async fn test_summarized_index_update() { index.create(None).await; let (task, _status_code) = index.update(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -859,7 +861,7 @@ async fn test_summarized_index_update() { "###); let (task, _status_code) = index.update(Some("bones")).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" @@ -973,9 +975,9 @@ async fn test_summarized_task_cancelation() { // to avoid being flaky we're only going to cancel an already finished task :( let (task, _status_code) = index.create(None).await; let task_uid = task.uid(); - index.wait_task(task_uid).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.cancel_tasks(format!("uids={task_uid}").as_str()).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(json_string!(task, { ".uid" => "[uid]", ".batchUid" => "[batch_uid]", ".**.originalFilter" => "[of]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }), @@ -1007,9 +1009,9 @@ async fn test_summarized_task_deletion() { let index = server.unique_index(); // to avoid being flaky we're only going to delete an already finished task :( let (task, _status_code) = index.create(None).await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _status_code) = server.delete_tasks("uids=0").await; - index.wait_task(task.uid()).await.succeeded(); + server.wait_task(task.uid()).await.succeeded(); let (task, _) = index.get_task(task.uid()).await; snapshot!(task, @r###" From 10028515acca965be2b37c6d488c2231edb15205 Mon Sep 17 00:00:00 2001 From: Martin Tzvetanov Grigorov Date: Fri, 6 Jun 2025 14:52:05 +0300 Subject: [PATCH 10/11] Use a unique server for the summarized dump creation test Signed-off-by: Martin Tzvetanov Grigorov --- crates/meilisearch/tests/common/server.rs | 2 +- crates/meilisearch/tests/tasks/mod.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index 431972983..e6f2aca2c 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,7 +399,7 @@ impl Server { 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); - let max_attempts = 400; // 200 seconds total, 0.5s per attempt + let max_attempts = 100; // 50 seconds total, 0.5s per attempt for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await; diff --git a/crates/meilisearch/tests/tasks/mod.rs b/crates/meilisearch/tests/tasks/mod.rs index 064b52a1f..09700d3c5 100644 --- a/crates/meilisearch/tests/tasks/mod.rs +++ b/crates/meilisearch/tests/tasks/mod.rs @@ -1038,7 +1038,8 @@ async fn test_summarized_task_deletion() { #[actix_web::test] async fn test_summarized_dump_creation() { - let server = Server::new_shared(); + // Do not use a shared server because it takes too long to create a dump + let server = Server::new().await; let (task, _status_code) = server.create_dump().await; server.wait_task(task.uid()).await; let (task, _) = server.get_task(task.uid()).await; From 8f96724adf54ef6da06dae274ddef414a58ec1c8 Mon Sep 17 00:00:00 2001 From: Martin Grigorov Date: Mon, 9 Jun 2025 14:03:49 +0300 Subject: [PATCH 11/11] Set max_attempts to 400 for Server::wait_task() Co-authored-by: Tamo --- crates/meilisearch/tests/common/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/meilisearch/tests/common/server.rs b/crates/meilisearch/tests/common/server.rs index e6f2aca2c..431972983 100644 --- a/crates/meilisearch/tests/common/server.rs +++ b/crates/meilisearch/tests/common/server.rs @@ -399,7 +399,7 @@ impl Server { 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); - let max_attempts = 100; // 50 seconds total, 0.5s per attempt + let max_attempts = 400; // 200 seconds total, 0.5s per attempt for i in 0..max_attempts { let (response, status_code) = self.service.get(&url).await;