2024-11-28 11:55:38 +01:00
use crate ::common ::Server ;
2023-09-11 16:50:53 +02:00
use crate ::json ;
2021-06-23 16:21:32 +02:00
2024-11-28 15:16:13 +01:00
macro_rules ! test_setting_routes {
( $( { setting : $setting :ident , update_verb : $update_verb :ident , default_value : $default_value :tt } , ) * ) = > {
$(
mod $setting {
use crate ::common ::Server ;
#[ 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 ;
assert_eq! ( code , 404 ) ;
}
#[ 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 > ( ) ) ;
let ( response , code ) = server . service . $update_verb ( url , serde_json ::Value ::Null . into ( ) ) . await ;
assert_eq! ( code , 202 , " {} " , response ) ;
server . index ( " " ) . wait_task ( 0 ) . await ;
let ( response , code ) = server . index ( " test " ) . get ( ) . await ;
assert_eq! ( code , 200 , " {} " , response ) ;
}
#[ 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 " ) ;
}
#[ 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 ;
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 = crate ::json! ( $default_value ) ;
assert_eq! ( expected , response ) ;
}
}
) *
#[ actix_rt::test ]
async fn all_setting_tested ( ) {
let expected = std ::collections ::BTreeSet ::from_iter ( meilisearch ::routes ::indexes ::settings ::ALL_SETTINGS_NAMES . iter ( ) ) ;
let tested = std ::collections ::BTreeSet ::from_iter ( [ $( stringify! ( $setting ) ) , * ] . iter ( ) ) ;
let diff : Vec < _ > = expected . difference ( & tested ) . collect ( ) ;
assert! ( diff . is_empty ( ) , " Not all settings were tested, please add the following settings to the `test_setting_routes!` macro: {:?} " , diff ) ;
}
} ;
}
test_setting_routes! (
{
setting : filterable_attributes ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : displayed_attributes ,
update_verb : put ,
default_value : [ " * " ]
} ,
{
setting : localized_attributes ,
update_verb : put ,
default_value : null
} ,
{
setting : searchable_attributes ,
update_verb : put ,
default_value : [ " * " ]
} ,
{
setting : distinct_attribute ,
update_verb : put ,
default_value : null
} ,
{
setting : stop_words ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : separator_tokens ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : non_separator_tokens ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : dictionary ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : ranking_rules ,
update_verb : put ,
default_value : [ " words " , " typo " , " proximity " , " attribute " , " sort " , " exactness " ]
} ,
{
setting : synonyms ,
update_verb : put ,
default_value : { }
} ,
{
setting : pagination ,
update_verb : patch ,
default_value : { " maxTotalHits " : 1000 }
} ,
{
setting : faceting ,
update_verb : patch ,
default_value : { " maxValuesPerFacet " : 100 , " sortFacetValuesBy " : { " * " : " alpha " } }
} ,
{
setting : search_cutoff_ms ,
update_verb : put ,
default_value : null
} ,
{
setting : embedders ,
update_verb : patch ,
default_value : null
} ,
{
setting : facet_search ,
update_verb : put ,
default_value : true
} ,
{
setting : prefix_search ,
update_verb : put ,
default_value : " indexingTime "
} ,
{
setting : proximity_precision ,
update_verb : put ,
default_value : " byWord "
} ,
{
setting : sortable_attributes ,
update_verb : put ,
default_value : [ ]
} ,
{
setting : typo_tolerance ,
update_verb : patch ,
default_value : { " enabled " : true , " minWordSizeForTypos " : { " oneTypo " : 5 , " twoTypos " : 9 } , " disableOnWords " : [ ] , " disableOnAttributes " : [ ] }
} ,
) ;
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-11-19 15:57:56 +01:00
assert_eq! ( settings . keys ( ) . len ( ) , 19 ) ;
2021-02-24 09:30:51 +01:00
assert_eq! ( settings [ " displayedAttributes " ] , json! ( [ " * " ] ) ) ;
assert_eq! ( settings [ " searchableAttributes " ] , json! ( [ " * " ] ) ) ;
2021-06-03 23:47:16 +02:00
assert_eq! ( settings [ " filterableAttributes " ] , json! ( [ ] ) ) ;
2021-08-24 15:46:14 +02:00
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
) ;
2021-04-06 15:43:27 +02: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! ( [ ] ) ) ;
2022-06-08 18:03:56 +02:00
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! ( {
2022-06-22 17:24:25 +02:00
" maxTotalHits " : 1000 ,
2022-06-08 18:03:56 +02:00
} )
) ;
2024-01-08 11:09:37 +01:00
assert_eq! ( settings [ " proximityPrecision " ] , json! ( " byWord " ) ) ;
2024-03-18 12:06:00 +01:00
assert_eq! ( settings [ " searchCutoffMs " ] , json! ( null ) ) ;
2024-11-19 15:57:56 +01:00
assert_eq! ( settings [ " prefixSearch " ] , json! ( " indexingTime " ) ) ;
assert_eq! ( settings [ " facetSearch " ] , json! ( true ) ) ;
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 ,
2024-07-09 11:15:57 +02:00
" logsRoute " : false ,
2024-07-17 11:13:37 +02:00
" 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 ,
2024-11-19 15:57:56 +01:00
" localizedAttributes " : null ,
" facetSearch " : true ,
" prefixSearch " : " indexingTime "
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 ;
2021-12-02 16:03:26 +01:00
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 ;
2021-12-02 16:03:26 +01:00
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 " ) ;
2021-12-02 16:03:26 +01:00
let ( _response , code ) = index . delete_settings ( ) . await ;
assert_eq! ( code , 202 ) ;
2021-11-04 13:38:44 +01:00
2021-12-02 16:03:26 +01:00
let response = index . wait_task ( 0 ) . await ;
2021-11-04 13:38:44 +01:00
2021-12-02 16:03:26 +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 ) ;
2022-05-17 11:17:32 +02:00
assert_eq! ( response [ " taskUid " ] , 0 ) ;
2021-12-02 16:03:26 +01:00
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 ;
2021-12-02 16:03:26 +01:00
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 " ] } ) ) ;
2021-06-03 23:47:16 +02:00
assert_eq! ( response [ " filterableAttributes " ] , json! ( [ " age " ] ) ) ;
2021-02-24 10:19:22 +01:00
index . delete_settings ( ) . await ;
2021-12-02 16:03:26 +01:00
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! ( [ ] ) ) ;
2021-06-03 23:47:16 +02:00
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 ) ;
2021-12-02 16:03:26 +01:00
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 ) ;
2021-12-02 16:03:26 +01:00
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-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
{
2023-01-12 13:55:53 +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 ;
2021-12-02 16:03:26 +01:00
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 ;
2021-12-02 16:03:26 +01:00
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 ) ) ;
}