466 lines
16 KiB
Rust
Raw Normal View History

2021-06-23 16:21:32 +02:00
use std::collections::HashMap;
use once_cell::sync::Lazy;
2023-09-11 16:50:53 +02:00
use crate::common::{Server, Value};
use crate::json;
2021-06-23 16:21:32 +02:00
static DEFAULT_SETTINGS_VALUES: Lazy<HashMap<&'static str, Value>> = Lazy::new(|| {
let mut map = HashMap::new();
map.insert("displayed_attributes", json!(["*"]));
map.insert("searchable_attributes", json!(["*"]));
map.insert("localized_attributes", json!(null));
2021-06-23 16:21:32 +02:00
map.insert("filterable_attributes", json!([]));
2023-09-11 16:50:53 +02:00
map.insert("distinct_attribute", json!(null));
2021-06-24 16:25:52 +02:00
map.insert(
"ranking_rules",
2022-10-20 18:00:07 +02:00
json!(["words", "typo", "proximity", "attribute", "sort", "exactness"]),
2021-06-24 16:25:52 +02:00
);
2021-06-23 16:21:32 +02:00
map.insert("stop_words", json!([]));
2023-07-19 18:15:48 +02:00
map.insert("non_separator_tokens", json!([]));
map.insert("separator_tokens", json!([]));
map.insert("dictionary", json!([]));
2021-06-23 16:21:32 +02:00
map.insert("synonyms", json!({}));
map.insert(
"faceting",
json!({
"maxValuesPerFacet": json!(100),
2023-06-27 15:31:11 +02:00
"sortFacetValuesBy": {
"*": "alpha"
}
}),
);
map.insert(
"pagination",
json!({
"maxTotalHits": json!(1000),
}),
);
map.insert("search_cutoff_ms", json!(null));
2021-06-23 16:21:32 +02:00
map
});
2021-02-24 09:30:51 +01:00
#[actix_rt::test]
async fn get_settings_unexisting_index() {
let server = Server::new().await;
2021-09-28 18:10:09 +02:00
let (response, code) = server.index("test").settings().await;
assert_eq!(code, 404, "{}", response)
2021-02-24 09:30:51 +01:00
}
#[actix_rt::test]
async fn get_settings() {
let server = Server::new().await;
let index = server.index("test");
2024-03-11 18:24:21 +01:00
let (response, _code) = index.create(None).await;
index.wait_task(response.uid()).await;
2021-02-24 09:30:51 +01:00
let (response, code) = index.settings().await;
assert_eq!(code, 200);
let settings = response.as_object().unwrap();
2024-07-25 10:50:45 +02:00
assert_eq!(settings.keys().len(), 17);
2021-02-24 09:30:51 +01:00
assert_eq!(settings["displayedAttributes"], json!(["*"]));
assert_eq!(settings["searchableAttributes"], json!(["*"]));
assert_eq!(settings["filterableAttributes"], json!([]));
assert_eq!(settings["sortableAttributes"], json!([]));
2021-04-20 12:07:22 +02:00
assert_eq!(settings["distinctAttribute"], json!(null));
2021-03-15 18:11:10 +01:00
assert_eq!(
settings["rankingRules"],
2022-10-20 18:00:07 +02:00
json!(["words", "typo", "proximity", "attribute", "sort", "exactness"])
2021-03-15 18:11:10 +01:00
);
assert_eq!(settings["stopWords"], json!([]));
2023-07-25 10:55:37 +02:00
assert_eq!(settings["nonSeparatorTokens"], json!([]));
assert_eq!(settings["separatorTokens"], json!([]));
2023-07-19 18:15:48 +02:00
assert_eq!(settings["dictionary"], json!([]));
assert_eq!(
settings["faceting"],
json!({
2022-06-09 10:17:55 +02:00
"maxValuesPerFacet": 100,
2023-06-27 15:31:11 +02:00
"sortFacetValuesBy": {
"*": "alpha"
}
2022-06-09 10:17:55 +02:00
})
);
assert_eq!(
settings["pagination"],
json!({
"maxTotalHits": 1000,
})
);
assert_eq!(settings["proximityPrecision"], json!("byWord"));
assert_eq!(settings["searchCutoffMs"], json!(null));
2021-02-24 09:30:51 +01:00
}
2024-03-26 10:36:56 +01:00
#[actix_rt::test]
async fn secrets_are_hidden_in_settings() {
let server = Server::new().await;
let (response, code) = server.set_features(json!({"vectorStore": true})).await;
meili_snap::snapshot!(code, @"200 OK");
meili_snap::snapshot!(meili_snap::json_string!(response), @r###"
{
"vectorStore": true,
"metrics": false,
"logsRoute": false,
"editDocumentsByFunction": false,
"containsFilter": false
2024-03-26 10:36:56 +01:00
}
"###);
let index = server.index("test");
let (response, _code) = index.create(None).await;
index.wait_task(response.uid()).await;
let (response, code) = index
.update_settings(json!({
"embedders": {
"default": {
"source": "rest",
"url": "https://localhost:7777",
2024-04-03 19:10:19 +02:00
"apiKey": "My super secret value you will never guess",
"dimensions": 4,
2024-06-12 18:27:03 +02:00
"request": "{{text}}",
"response": "{{embedding}}"
2024-03-26 10:36:56 +01:00
}
}
}))
.await;
meili_snap::snapshot!(code, @"202 Accepted");
meili_snap::snapshot!(meili_snap::json_string!(response, { ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" }),
@r###"
{
"taskUid": 1,
"indexUid": "test",
"status": "enqueued",
"type": "settingsUpdate",
"enqueuedAt": "[date]"
}
"###);
let settings_update_uid = response.uid();
index.wait_task(settings_update_uid).await;
let (response, code) = index.settings().await;
meili_snap::snapshot!(code, @"200 OK");
meili_snap::snapshot!(meili_snap::json_string!(response), @r###"
{
"displayedAttributes": [
"*"
],
"searchableAttributes": [
"*"
],
"filterableAttributes": [],
"sortableAttributes": [],
"rankingRules": [
"words",
"typo",
"proximity",
"attribute",
"sort",
"exactness"
],
"stopWords": [],
"nonSeparatorTokens": [],
"separatorTokens": [],
"dictionary": [],
"synonyms": {},
"distinctAttribute": null,
"proximityPrecision": "byWord",
"typoTolerance": {
"enabled": true,
"minWordSizeForTypos": {
"oneTypo": 5,
"twoTypos": 9
},
"disableOnWords": [],
"disableOnAttributes": []
},
"faceting": {
"maxValuesPerFacet": 100,
"sortFacetValuesBy": {
"*": "alpha"
}
},
"pagination": {
"maxTotalHits": 1000
},
"embedders": {
"default": {
"source": "rest",
"apiKey": "My suXXXXXX...",
2024-04-03 19:10:19 +02:00
"dimensions": 4,
2024-09-02 11:31:31 +02:00
"documentTemplate": "{% for field in fields %}{% if field.is_searchable and field.value != nil %}{{ field.name }}: {{ field.value }}\n{% endif %}{% endfor %}",
2024-08-28 09:10:09 +02:00
"documentTemplateMaxBytes": 400,
2024-03-26 10:36:56 +01:00
"url": "https://localhost:7777",
2024-06-12 18:27:03 +02:00
"request": "{{text}}",
2024-07-22 12:04:29 +02:00
"response": "{{embedding}}",
"headers": {}
2024-03-26 10:36:56 +01:00
}
},
2024-07-25 10:50:45 +02:00
"searchCutoffMs": null,
"localizedAttributes": null
2024-03-26 10:36:56 +01:00
}
"###);
let (response, code) = server.get_task(settings_update_uid).await;
meili_snap::snapshot!(code, @"200 OK");
meili_snap::snapshot!(meili_snap::json_string!(response["details"]), @r###"
{
"embedders": {
"default": {
"source": "rest",
"apiKey": "My suXXXXXX...",
2024-04-16 14:51:21 +02:00
"dimensions": 4,
2024-06-12 18:27:03 +02:00
"url": "https://localhost:7777",
"request": "{{text}}",
"response": "{{embedding}}"
2024-03-26 10:36:56 +01:00
}
}
}
"###);
}
2021-02-24 09:42:36 +01:00
#[actix_rt::test]
2021-11-04 13:38:44 +01:00
async fn error_update_settings_unknown_field() {
2021-02-24 09:42:36 +01:00
let server = Server::new().await;
let index = server.index("test");
let (_response, code) = index.update_settings(json!({"foo": 12})).await;
2021-06-22 11:10:57 +02:00
assert_eq!(code, 400);
2021-02-24 09:42:36 +01:00
}
#[actix_rt::test]
async fn test_partial_update() {
let server = Server::new().await;
let index = server.index("test");
2022-10-20 18:00:07 +02:00
let (_response, _code) = index.update_settings(json!({"displayedAttributes": ["foo"]})).await;
index.wait_task(0).await;
2021-02-24 09:42:36 +01:00
let (response, code) = index.settings().await;
assert_eq!(code, 200);
2021-03-15 18:11:10 +01:00
assert_eq!(response["displayedAttributes"], json!(["foo"]));
assert_eq!(response["searchableAttributes"], json!(["*"]));
2021-02-24 09:42:36 +01:00
2022-10-20 18:00:07 +02:00
let (_response, _) = index.update_settings(json!({"searchableAttributes": ["bar"]})).await;
index.wait_task(1).await;
2021-02-24 09:42:36 +01:00
let (response, code) = index.settings().await;
assert_eq!(code, 200);
2021-03-15 18:11:10 +01:00
assert_eq!(response["displayedAttributes"], json!(["foo"]));
assert_eq!(response["searchableAttributes"], json!(["bar"]));
2021-02-24 09:42:36 +01:00
}
2021-02-24 10:14:36 +01:00
#[actix_rt::test]
2021-11-04 13:38:44 +01:00
async fn error_delete_settings_unexisting_index() {
2021-02-24 10:14:36 +01:00
let server = Server::new().await;
let index = server.index("test");
let (_response, code) = index.delete_settings().await;
assert_eq!(code, 202);
2021-11-04 13:38:44 +01:00
let response = index.wait_task(0).await;
2021-11-04 13:38:44 +01:00
assert_eq!(response["status"], "failed");
2021-02-24 10:14:36 +01:00
}
2021-02-24 10:19:22 +01:00
#[actix_rt::test]
async fn reset_all_settings() {
let server = Server::new().await;
let index = server.index("test");
2021-06-03 20:08:31 +02:00
let documents = json!([
{
"id": 1,
"name": "curqui",
"age": 99
}
]);
let (response, code) = index.add_documents(documents, None).await;
assert_eq!(code, 202);
assert_eq!(response["taskUid"], 0);
index.wait_task(0).await;
2021-06-03 20:08:31 +02:00
2021-03-15 18:11:10 +01:00
index
2021-06-03 14:19:56 +02:00
.update_settings(json!({"displayedAttributes": ["name", "age"], "searchableAttributes": ["name"], "stopWords": ["the"], "filterableAttributes": ["age"], "synonyms": {"puppy": ["dog", "doggo", "potat"] }}))
2021-03-15 18:11:10 +01:00
.await;
index.wait_task(1).await;
2021-02-24 10:19:22 +01:00
let (response, code) = index.settings().await;
assert_eq!(code, 200);
2021-06-03 20:08:31 +02:00
assert_eq!(response["displayedAttributes"], json!(["name", "age"]));
assert_eq!(response["searchableAttributes"], json!(["name"]));
2021-04-06 18:29:38 +02:00
assert_eq!(response["stopWords"], json!(["the"]));
2022-10-20 18:00:07 +02:00
assert_eq!(response["synonyms"], json!({"puppy": ["dog", "doggo", "potat"] }));
assert_eq!(response["filterableAttributes"], json!(["age"]));
2021-02-24 10:19:22 +01:00
index.delete_settings().await;
index.wait_task(2).await;
2021-02-24 10:19:22 +01:00
let (response, code) = index.settings().await;
assert_eq!(code, 200);
2021-03-15 18:11:10 +01:00
assert_eq!(response["displayedAttributes"], json!(["*"]));
assert_eq!(response["searchableAttributes"], json!(["*"]));
2021-04-06 18:29:38 +02:00
assert_eq!(response["stopWords"], json!([]));
assert_eq!(response["filterableAttributes"], json!([]));
2021-06-14 14:35:40 +02:00
assert_eq!(response["synonyms"], json!({}));
2021-06-03 20:08:31 +02:00
let (response, code) = index.get_document(1, None).await;
assert_eq!(code, 200);
assert!(response.as_object().unwrap().get("age").is_some());
2021-02-24 10:19:22 +01:00
}
2021-02-24 09:30:51 +01:00
#[actix_rt::test]
async fn update_setting_unexisting_index() {
let server = Server::new().await;
let index = server.index("test");
let (_response, code) = index.update_settings(json!({})).await;
2021-03-17 14:44:32 +01:00
assert_eq!(code, 202);
let response = index.wait_task(0).await;
assert_eq!(response["status"], "succeeded");
2021-02-24 09:30:51 +01:00
let (_response, code) = index.get().await;
assert_eq!(code, 200);
index.delete_settings().await;
let response = index.wait_task(1).await;
assert_eq!(response["status"], "succeeded");
2021-02-24 09:30:51 +01:00
}
2021-03-10 14:43:10 +01:00
#[actix_rt::test]
2021-11-04 13:38:44 +01:00
async fn error_update_setting_unexisting_index_invalid_uid() {
2021-03-10 14:43:10 +01:00
let server = Server::new().await;
let index = server.index("test##! ");
2021-09-28 18:10:09 +02:00
let (response, code) = index.update_settings(json!({})).await;
2023-01-11 14:31:34 +01:00
meili_snap::snapshot!(code, @"400 Bad Request");
meili_snap::snapshot!(meili_snap::json_string!(response), @r###"
{
2024-09-16 22:22:24 +03:00
"message": "`test##! ` is not a valid index uid. Index uid can be an integer or a string containing only alphanumeric characters, hyphens (-) and underscores (_), and can not be more than 512 bytes.",
2023-01-11 14:31:34 +01:00
"code": "invalid_index_uid",
"type": "invalid_request",
2023-01-19 15:48:20 +01:00
"link": "https://docs.meilisearch.com/errors#invalid_index_uid"
2023-01-11 14:31:34 +01:00
}
"###);
2021-03-10 14:43:10 +01:00
}
2021-02-24 09:30:51 +01:00
macro_rules! test_setting_routes {
($($setting:ident $write_method:ident), *) => {
2021-02-24 09:30:51 +01:00
$(
mod $setting {
use crate::common::Server;
2021-06-23 16:21:32 +02:00
use super::DEFAULT_SETTINGS_VALUES;
2021-02-24 09:30:51 +01:00
#[actix_rt::test]
async fn get_unexisting_index() {
let server = Server::new().await;
let url = format!("/indexes/test/settings/{}",
stringify!($setting)
.chars()
.map(|c| if c == '_' { '-' } else { c })
.collect::<String>());
let (_response, code) = server.service.get(url).await;
2021-06-15 22:21:52 +02:00
assert_eq!(code, 404);
2021-02-24 09:30:51 +01:00
}
#[actix_rt::test]
async fn update_unexisting_index() {
let server = Server::new().await;
let url = format!("/indexes/test/settings/{}",
stringify!($setting)
.chars()
.map(|c| if c == '_' { '-' } else { c })
.collect::<String>());
2023-09-11 16:50:53 +02:00
let (response, code) = server.service.$write_method(url, serde_json::Value::Null.into()).await;
2021-04-01 15:50:45 +02:00
assert_eq!(code, 202, "{}", response);
server.index("").wait_task(0).await;
2021-03-12 00:37:43 +01:00
let (response, code) = server.index("test").get().await;
assert_eq!(code, 200, "{}", response);
2021-02-24 09:30:51 +01:00
}
#[actix_rt::test]
async fn delete_unexisting_index() {
let server = Server::new().await;
let url = format!("/indexes/test/settings/{}",
stringify!($setting)
.chars()
.map(|c| if c == '_' { '-' } else { c })
.collect::<String>());
let (_, code) = server.service.delete(url).await;
assert_eq!(code, 202);
let response = server.index("").wait_task(0).await;
assert_eq!(response["status"], "failed");
2021-06-23 16:21:32 +02:00
}
#[actix_rt::test]
async fn get_default() {
let server = Server::new().await;
let index = server.index("test");
let (response, code) = index.create(None).await;
assert_eq!(code, 202, "{}", response);
index.wait_task(0).await;
2021-06-23 16:21:32 +02:00
let url = format!("/indexes/test/settings/{}",
stringify!($setting)
.chars()
.map(|c| if c == '_' { '-' } else { c })
.collect::<String>());
let (response, code) = server.service.get(url).await;
assert_eq!(code, 200, "{}", response);
let expected = DEFAULT_SETTINGS_VALUES.get(stringify!($setting)).unwrap();
assert_eq!(expected, &response);
2021-02-24 09:30:51 +01:00
}
}
)*
};
}
test_setting_routes!(
filterable_attributes put,
displayed_attributes put,
localized_attributes put,
searchable_attributes put,
distinct_attribute put,
stop_words put,
2023-08-08 16:03:16 +02:00
separator_tokens put,
non_separator_tokens put,
dictionary put,
ranking_rules put,
synonyms put,
pagination patch,
2024-03-12 18:19:02 +01:00
faceting patch,
search_cutoff_ms put
2021-03-15 18:11:10 +01:00
);
2021-11-04 13:38:44 +01:00
#[actix_rt::test]
async fn error_set_invalid_ranking_rules() {
let server = Server::new().await;
let index = server.index("test");
index.create(None).await;
2023-01-11 12:33:56 +01:00
let (response, code) = index.update_settings(json!({ "rankingRules": [ "manyTheFish"]})).await;
2023-01-11 14:31:34 +01:00
meili_snap::snapshot!(code, @"400 Bad Request");
meili_snap::snapshot!(meili_snap::json_string!(response), @r###"
2023-01-11 12:33:56 +01:00
{
"message": "Invalid value at `.rankingRules[0]`: `manyTheFish` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.",
2023-01-11 12:33:56 +01:00
"code": "invalid_settings_ranking_rules",
"type": "invalid_request",
2023-01-19 15:48:20 +01:00
"link": "https://docs.meilisearch.com/errors#invalid_settings_ranking_rules"
2023-01-11 12:33:56 +01:00
}
"###);
2021-11-04 13:38:44 +01:00
}
#[actix_rt::test]
async fn set_and_reset_distinct_attribute_with_dedicated_route() {
let server = Server::new().await;
let index = server.index("test");
let (_response, _code) = index.update_distinct_attribute(json!("test")).await;
index.wait_task(0).await;
2021-11-04 13:38:44 +01:00
let (response, _) = index.get_distinct_attribute().await;
assert_eq!(response, "test");
index.update_distinct_attribute(json!(null)).await;
index.wait_task(1).await;
2021-11-04 13:38:44 +01:00
let (response, _) = index.get_distinct_attribute().await;
assert_eq!(response, json!(null));
}