// This modules contains all the test concerning search. Each particular feture of the search // should be tested in its own module to isolate tests and keep the tests readable. mod errors; use crate::common::Server; use once_cell::sync::Lazy; use serde_json::{json, Value}; static DOCUMENTS: Lazy = Lazy::new(|| { json!([ { "title": "Shazam!", "id": "287947" }, { "title": "Captain Marvel", "id": "299537" }, { "title": "Escape Room", "id": "522681" }, { "title": "How to Train Your Dragon: The Hidden World", "id": "166428" }, { "title": "Glass", "id": "450465" } ]) }); #[actix_rt::test] async fn simple_placeholder_search() { let server = Server::new().await; let index = server.index("test"); let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(0).await; index .search(json!({}), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }) .await; } #[actix_rt::test] async fn simple_search() { let server = Server::new().await; let index = server.index("test"); let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(0).await; index .search(json!({"q": "glass"}), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }) .await; } #[actix_rt::test] async fn search_multiple_params() { let server = Server::new().await; let index = server.index("test"); let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(0).await; index .search( json!({ "q": "glass", "attributesToCrop": ["title:2"], "attributesToHighlight": ["title"], "limit": 1, "offset": 0, }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }, ) .await; } #[actix_rt::test] async fn search_with_filter_string_notation() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"filterableAttributes": ["title"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; index .search( json!({ "filter": "title = Glass" }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1); }, ) .await; } #[actix_rt::test] async fn search_with_filter_array_notation() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"filterableAttributes": ["title"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; let (response, code) = index .search_post(json!({ "filter": ["title = Glass"] })) .await; assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1); let (response, code) = index .search_post(json!({ "filter": [["title = Glass", "title = \"Shazam!\"", "title = \"Escape Room\""]] })) .await; assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 3); } #[actix_rt::test] async fn search_with_sort_on_numbers() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"sortableAttributes": ["id"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; index .search( json!({ "sort": ["id:asc"] }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }, ) .await; } #[actix_rt::test] async fn search_with_sort_on_strings() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"sortableAttributes": ["title"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; index .search( json!({ "sort": ["title:desc"] }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 5); }, ) .await; } #[actix_rt::test] async fn search_with_multiple_sort() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"sortableAttributes": ["id", "title"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; let (response, code) = index .search_post(json!({ "sort": ["id:asc", "title:desc"] })) .await; assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 5); } #[actix_rt::test] async fn search_facet_distribution() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({"filterableAttributes": ["title"]})) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; index .search( json!({ "facetsDistribution": ["title"] }), |response, code| { assert_eq!(code, 200, "{}", response); let dist = response["facetsDistribution"].as_object().unwrap(); assert_eq!(dist.len(), 1); assert!(dist.get("title").is_some()); }, ) .await; } #[actix_rt::test] async fn displayed_attributes() { let server = Server::new().await; let index = server.index("test"); index .update_settings(json!({ "displayedAttributes": ["title"] })) .await; let documents = DOCUMENTS.clone(); index.add_documents(documents, None).await; index.wait_task(1).await; let (response, code) = index .search_post(json!({ "attributesToRetrieve": ["title", "id"] })) .await; assert_eq!(code, 200, "{}", response); assert!(response["hits"].get("title").is_none()); } #[actix_rt::test] async fn placeholder_search_is_hard_limited() { let server = Server::new().await; let index = server.index("test"); let documents: Vec<_> = (0..1200) .map(|i| json!({ "id": i, "text": "I am unique!" })) .collect(); index.add_documents(documents.into(), None).await; index.wait_task(0).await; index .search( json!({ "limit": 1500, }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1000); }, ) .await; index .search( json!({ "offset": 800, "limit": 400, }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) .await; } #[actix_rt::test] async fn search_is_hard_limited() { let server = Server::new().await; let index = server.index("test"); let documents: Vec<_> = (0..1200) .map(|i| json!({ "id": i, "text": "I am unique!" })) .collect(); index.add_documents(documents.into(), None).await; index.wait_task(0).await; index .search( json!({ "q": "unique", "limit": 1500, }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 1000); }, ) .await; index .search( json!({ "q": "unique", "offset": 800, "limit": 400, }), |response, code| { assert_eq!(code, 200, "{}", response); assert_eq!(response["hits"].as_array().unwrap().len(), 200); }, ) .await; }