From d4157c0ce4b3af1d74269dcaaeb6d8b1115ce3f7 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 10 Jan 2023 17:22:01 +0100 Subject: [PATCH 1/3] add a test on the search route for each possible error codes snapshot the json directly instead of using the debug formatting --- meilisearch/tests/search/errors.rs | 407 +++++++++++++++++++++++------ 1 file changed, 332 insertions(+), 75 deletions(-) diff --git a/meilisearch/tests/search/errors.rs b/meilisearch/tests/search/errors.rs index 163a63d6f..1a82dcbc5 100644 --- a/meilisearch/tests/search/errors.rs +++ b/meilisearch/tests/search/errors.rs @@ -1,3 +1,4 @@ +use meili_snap::*; use serde_json::json; use super::DOCUMENTS; @@ -37,104 +38,360 @@ async fn search_unexisting_parameter() { } #[actix_rt::test] -async fn search_invalid_crop_marker() { +async fn search_bad_q() { let server = Server::new().await; let index = server.index("test"); - // object - let response = index.search_post(json!({"cropMarker": { "marker": "" }})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Map `{\"marker\":\"\"}`, expected a String at `.cropMarker`."), - "code": String("invalid_search_crop_marker"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-crop-marker"), - }, - 400, - ) + let (response, code) = index.search_post(json!({"q": ["doggo"]})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.q`.", + "code": "invalid_search_q", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-q" + } + "###); + // Can't make the `q` fail with a get search since it'll accept anything as a string. +} + +#[actix_rt::test] +async fn search_bad_offset() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"offset": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Integer at `.offset`.", + "code": "invalid_search_offset", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-offset" + } "###); - // array - let response = index.search_post(json!({"cropMarker": ["marker", ""]})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Sequence `[\"marker\",\"\"]`, expected a String at `.cropMarker`."), - "code": String("invalid_search_crop_marker"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-crop-marker"), - }, - 400, - ) + let (response, code) = index.search_get(json!({"offset": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid digit found in string at `.offset`.", + "code": "invalid_search_offset", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-offset" + } "###); } #[actix_rt::test] -async fn search_invalid_highlight_pre_tag() { +async fn search_bad_limit() { let server = Server::new().await; let index = server.index("test"); - // object - let response = index.search_post(json!({"highlightPreTag": { "marker": "" }})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Map `{\"marker\":\"\"}`, expected a String at `.highlightPreTag`."), - "code": String("invalid_search_highlight_pre_tag"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-highlight-pre-tag"), - }, - 400, - ) + let (response, code) = index.search_post(json!({"limit": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Integer at `.limit`.", + "code": "invalid_search_limit", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-limit" + } "###); - // array - let response = index.search_post(json!({"highlightPreTag": ["marker", ""]})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Sequence `[\"marker\",\"\"]`, expected a String at `.highlightPreTag`."), - "code": String("invalid_search_highlight_pre_tag"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-highlight-pre-tag"), - }, - 400, - ) + let (response, code) = index.search_get(json!({"limit": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid digit found in string at `.limit`.", + "code": "invalid_search_limit", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-limit" + } "###); } #[actix_rt::test] -async fn search_invalid_highlight_post_tag() { +async fn search_bad_page() { let server = Server::new().await; let index = server.index("test"); - // object - let response = index.search_post(json!({"highlightPostTag": { "marker": "" }})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Map `{\"marker\":\"\"}`, expected a String at `.highlightPostTag`."), - "code": String("invalid_search_highlight_post_tag"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-highlight-post-tag"), - }, - 400, - ) + let (response, code) = index.search_post(json!({"page": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Integer at `.page`.", + "code": "invalid_search_page", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-page" + } "###); - // array - let response = index.search_post(json!({"highlightPostTag": ["marker", ""]})).await; - meili_snap::snapshot!(format!("{:#?}", response), @r###" - ( - Object { - "message": String("invalid type: Sequence `[\"marker\",\"\"]`, expected a String at `.highlightPostTag`."), - "code": String("invalid_search_highlight_post_tag"), - "type": String("invalid_request"), - "link": String("https://docs.meilisearch.com/errors#invalid-search-highlight-post-tag"), - }, - 400, - ) + let (response, code) = index.search_get(json!({"page": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid digit found in string at `.page`.", + "code": "invalid_search_page", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-page" + } + "###); +} + +#[actix_rt::test] +async fn search_bad_hits_per_page() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"hitsPerPage": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Integer at `.hitsPerPage`.", + "code": "invalid_search_hits_per_page", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-hits-per-page" + } + "###); + + let (response, code) = index.search_get(json!({"hitsPerPage": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid digit found in string at `.hitsPerPage`.", + "code": "invalid_search_hits_per_page", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-hits-per-page" + } + "###); +} + +#[actix_rt::test] +async fn search_bad_attributes_to_crop() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"attributesToCrop": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.attributesToCrop`.", + "code": "invalid_search_attributes_to_crop", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-attributes-to-crop" + } + "###); + // Can't make the `attributes_to_crop` fail with a get search since it'll accept anything as an array of strings. +} + +#[actix_rt::test] +async fn search_bad_crop_length() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"cropLength": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Integer at `.cropLength`.", + "code": "invalid_search_crop_length", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-crop-length" + } + "###); + + let (response, code) = index.search_get(json!({"cropLength": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid digit found in string at `.cropLength`.", + "code": "invalid_search_crop_length", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-crop-length" + } + "###); +} + +#[actix_rt::test] +async fn search_bad_attributes_to_highlight() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"attributesToHighlight": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.attributesToHighlight`.", + "code": "invalid_search_attributes_to_highlight", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-attributes-to-highlight" + } + "###); + // Can't make the `attributes_to_highlight` fail with a get search since it'll accept anything as an array of strings. +} + +#[actix_rt::test] +async fn search_bad_filter() { + let server = Server::new().await; + let index = server.index("test"); + + // Can't make the `filter` fail with a get search since it'll accept anything as a strings. + let (response, code) = index.search_post(json!({ "filter": true })).await; + snapshot!(code, @"404 Not Found"); + snapshot!(json_string!(response), @r###" + { + "message": "Index `test` not found.", + "code": "index_not_found", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#index-not-found" + } + "###); +} + +#[actix_rt::test] +async fn search_bad_sort() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"sort": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.sort`.", + "code": "invalid_search_sort", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-sort" + } + "###); + // Can't make the `sort` fail with a get search since it'll accept anything as a strings. +} + +#[actix_rt::test] +async fn search_bad_show_matches_position() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"showMatchesPosition": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Boolean at `.showMatchesPosition`.", + "code": "invalid_search_show_matches_position", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-show-matches-position" + } + "###); + + let (response, code) = index.search_get(json!({"showMatchesPosition": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "provided string was not `true` or `false` at `.showMatchesPosition`.", + "code": "invalid_search_show_matches_position", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-show-matches-position" + } + "###); +} + +#[actix_rt::test] +async fn search_bad_facets() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"facets": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: String `\"doggo\"`, expected a Sequence at `.facets`.", + "code": "invalid_search_facets", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-facets" + } + "###); + // Can't make the `attributes_to_highlight` fail with a get search since it'll accept anything as an array of strings. +} + +#[actix_rt::test] +async fn search_bad_highlight_pre_tag() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"highlightPreTag": ["doggo"]})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.highlightPreTag`.", + "code": "invalid_search_highlight_pre_tag", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-highlight-pre-tag" + } + "###); + // Can't make the `highlight_pre_tag` fail with a get search since it'll accept anything as a strings. +} + +#[actix_rt::test] +async fn search_bad_highlight_post_tag() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"highlightPostTag": ["doggo"]})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.highlightPostTag`.", + "code": "invalid_search_highlight_post_tag", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-highlight-post-tag" + } + "###); + // Can't make the `highlight_post_tag` fail with a get search since it'll accept anything as a strings. +} + +#[actix_rt::test] +async fn search_bad_crop_marker() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"cropMarker": ["doggo"]})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "invalid type: Sequence `[\"doggo\"]`, expected a String at `.cropMarker`.", + "code": "invalid_search_crop_marker", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-crop-marker" + } + "###); + // Can't make the `crop_marker` fail with a get search since it'll accept anything as a strings. +} + +#[actix_rt::test] +async fn search_bad_matching_strategy() { + let server = Server::new().await; + let index = server.index("test"); + + let (response, code) = index.search_post(json!({"matchingStrategy": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Incorrect tag value at `.matchingStrategy`.", + "code": "invalid_search_matching_strategy", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-matching-strategy" + } + "###); + + let (response, code) = index.search_get(json!({"matchingStrategy": "doggo"})).await; + snapshot!(code, @"400 Bad Request"); + snapshot!(json_string!(response), @r###" + { + "message": "Incorrect tag value at `.matchingStrategy`.", + "code": "invalid_search_matching_strategy", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid-search-matching-strategy" + } "###); } From d0a85057a33bb582152cc2f57fd95af0d6fb6342 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 11 Jan 2023 11:37:12 +0100 Subject: [PATCH 2/3] fix the bad filter test --- meilisearch/src/error.rs | 2 +- meilisearch/src/search.rs | 2 +- meilisearch/tests/search/errors.rs | 16 +++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/meilisearch/src/error.rs b/meilisearch/src/error.rs index bec233971..23a101080 100644 --- a/meilisearch/src/error.rs +++ b/meilisearch/src/error.rs @@ -55,7 +55,7 @@ impl ErrorCode for MeilisearchHttpError { MeilisearchHttpError::MissingPayload(_) => Code::MissingPayload, MeilisearchHttpError::InvalidContentType(_, _) => Code::InvalidContentType, MeilisearchHttpError::DocumentNotFound(_) => Code::DocumentNotFound, - MeilisearchHttpError::InvalidExpression(_, _) => Code::Filter, + MeilisearchHttpError::InvalidExpression(_, _) => Code::InvalidSearchFilter, MeilisearchHttpError::PayloadTooLarge => Code::PayloadTooLarge, MeilisearchHttpError::SwapIndexPayloadWrongLength(_) => Code::InvalidSwapIndexes, MeilisearchHttpError::IndexUid(e) => e.error_code(), diff --git a/meilisearch/src/search.rs b/meilisearch/src/search.rs index cd6dc6e30..39af9bedb 100644 --- a/meilisearch/src/search.rs +++ b/meilisearch/src/search.rs @@ -695,7 +695,7 @@ fn parse_filter(facets: &Value) -> Result, MeilisearchHttpError> Ok(condition) } Value::Array(arr) => parse_filter_array(arr), - v => Err(MeilisearchHttpError::InvalidExpression(&["Array"], v.clone())), + v => Err(MeilisearchHttpError::InvalidExpression(&["String", "Array"], v.clone())), } } diff --git a/meilisearch/tests/search/errors.rs b/meilisearch/tests/search/errors.rs index 1a82dcbc5..60a52d07d 100644 --- a/meilisearch/tests/search/errors.rs +++ b/meilisearch/tests/search/errors.rs @@ -233,20 +233,26 @@ async fn search_bad_attributes_to_highlight() { #[actix_rt::test] async fn search_bad_filter() { + // Since a filter is deserialized as a json Value it will never fail to deserialize. + // Thus the error message is not generated by deserr but written by us. let server = Server::new().await; let index = server.index("test"); + // Also, to trigger the error message we need to effectively create the index or else it'll throw an + // index does not exists error. + let (_, code) = index.create(None).await; + snapshot!(code, @"202 Accepted"); - // Can't make the `filter` fail with a get search since it'll accept anything as a strings. let (response, code) = index.search_post(json!({ "filter": true })).await; - snapshot!(code, @"404 Not Found"); + snapshot!(code, @"400 Bad Request"); snapshot!(json_string!(response), @r###" { - "message": "Index `test` not found.", - "code": "index_not_found", + "message": "Invalid syntax for the filter parameter: `expected String, Array, found: true`.", + "code": "invalid_search_filter", "type": "invalid_request", - "link": "https://docs.meilisearch.com/errors#index-not-found" + "link": "https://docs.meilisearch.com/errors#invalid-search-filter" } "###); + // Can't make the `filter` fail with a get search since it'll accept anything as a strings. } #[actix_rt::test] From 7a30d98264971805369a634ea2712cd9c1038ad5 Mon Sep 17 00:00:00 2001 From: Tamo Date: Wed, 11 Jan 2023 14:54:29 +0100 Subject: [PATCH 3/3] fix a flaky test --- meilisearch/tests/search/errors.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meilisearch/tests/search/errors.rs b/meilisearch/tests/search/errors.rs index 60a52d07d..bf05dc916 100644 --- a/meilisearch/tests/search/errors.rs +++ b/meilisearch/tests/search/errors.rs @@ -240,6 +240,8 @@ async fn search_bad_filter() { // Also, to trigger the error message we need to effectively create the index or else it'll throw an // index does not exists error. let (_, code) = index.create(None).await; + server.wait_task(0).await; + snapshot!(code, @"202 Accepted"); let (response, code) = index.search_post(json!({ "filter": true })).await;