mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-27 07:14:26 +01:00
457a473b72
* Fix error code of the "duplicate index found" error * Use the content of the ProcessingTasks in the tasks cancelation system * Change the missing_filters error code into missing_task_filters * WIP Introduce the invalid_task_uid error code * Use more precise error codes/message for the task routes + Allow star operator in delete/cancel tasks + rename originalQuery to originalFilters + Display error/canceled_by in task view even when they are = null + Rename task filter fields by using their plural forms + Prepare an error code for canceledBy filter + Only return global tasks if the API key action `index.*` is there * Add canceledBy task filter * Update tests following task API changes * Rename original_query to original_filters everywhere * Update more insta-snap tests * Make clippy happy They're a happy clip now. * Make rustfmt happy >:-( * Fix Index name parsing error message to fit the specification * Bump milli version to 0.35.1 * Fix the new error messages * fix the error messages and add tests * rename the error codes for the sake of consistency * refactor the way we send the cli informations + add the analytics for the config file and ssl usage * Apply suggestions from code review Co-authored-by: Clément Renault <clement@meilisearch.com> * add a comment over the new infos structure * reformat, sorry @kero * Store analytics for the documents deletions * Add analytics on all the settings * Spawn threads with names * Spawn rayon threads with names * update the distinct attributes to the spec update * update the analytics on the search route * implements the analytics on the health and version routes * Fix task details serialization * Add the question mark to the task deletion query filter * Add the question mark to the task cancelation query filter * Fix tests * add analytics on the task route * Add all the missing fields of the new task query type * Create a new analytics for the task deletion * Create a new analytics for the task creation * batch the tasks seen events * Update the finite pagination analytics * add the analytics of the swap-indexes route * Stop removing the DB when failing to read it * Rename originalFilters into originalFilters * Rename matchedDocuments into providedIds * Add `workflow_dispatch` to flaky.yml * Bump grenad to 0.4.4 * Bump milli to version v0.37.0 * Don't multiply total memory returned by sysinfo anymore sysinfo now returns bytes rather than KB * Add a dispatch to the publish binaries workflow * Fix publish release CI * Don't use gold but the default linker * Always display details for the indexDeletion task * Fix the insta tests * refactorize the whole test suite 1. Make a call to assert_internally_consistent automatically when snapshoting the scheduler. There is no point in snapshoting something broken and expect the dumb humans to notice. 2. Replace every possible call to assert_internally_consistent by a snapshot of the scheduler. It takes as many lines and ensure we never change something without noticing in any tests ever. 3. Name every snapshots: it's easier to debug when something goes wrong and easier to review in general. 4. Stop skipping breakpoints, it's too easy to miss something. Now you must explicitely show which path is the scheduler supposed to use. 5. Add a timeout on the channel.recv, it eases the process of writing tests, now when something file you get a failure instead of a deadlock. * rebase on release-v0.30 * makes clippy happy * update the snapshots after a rebase * try to remove the flakyness of the failing test * Add more analytics on the ranking rules positions * Update the dump test to check for the dumpUid dumpCreation task details * send the ranking rules as a string because amplitude is too dumb to process an array as a single value * Display a null dumpUid until we computed the dump itself on disk * Update tests * Check if the master key is missing before returning an error Co-authored-by: Loïc Lecrenier <loic.lecrenier@me.com> Co-authored-by: bors[bot] <26634292+bors[bot]@users.noreply.github.com> Co-authored-by: Kerollmops <clement@meilisearch.com> Co-authored-by: ManyTheFish <many@meilisearch.com> Co-authored-by: Tamo <tamo@meilisearch.com> Co-authored-by: Louis Dureuil <louis@meilisearch.com>
1005 lines
31 KiB
Rust
1005 lines
31 KiB
Rust
use meili_snap::insta::{self, assert_json_snapshot};
|
|
use serde_json::json;
|
|
use time::format_description::well_known::Rfc3339;
|
|
use time::OffsetDateTime;
|
|
|
|
use crate::common::Server;
|
|
|
|
#[actix_rt::test]
|
|
async fn error_get_unexisting_task_status() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
let (response, code) = index.get_task(1).await;
|
|
|
|
let expected_response = json!({
|
|
"message": "Task `1` not found.",
|
|
"code": "task_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#task_not_found"
|
|
});
|
|
|
|
assert_eq!(response, expected_response);
|
|
assert_eq!(code, 404);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn get_task_status() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index
|
|
.add_documents(
|
|
serde_json::json!([{
|
|
"id": 1,
|
|
"content": "foobar",
|
|
}]),
|
|
None,
|
|
)
|
|
.await;
|
|
index.wait_task(0).await;
|
|
let (_response, code) = index.get_task(1).await;
|
|
assert_eq!(code, 200);
|
|
// TODO check response format, as per #48
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn list_tasks() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
index
|
|
.add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None)
|
|
.await;
|
|
let (response, code) = index.list_tasks().await;
|
|
assert_eq!(code, 200);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn list_tasks_with_star_filters() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
index
|
|
.add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None)
|
|
.await;
|
|
let (response, code) = index.service.get("/tasks?indexUids=test").await;
|
|
assert_eq!(code, 200);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) = index.service.get("/tasks?indexUids=*").await;
|
|
assert_eq!(code, 200);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) = index.service.get("/tasks?indexUids=*,pasteque").await;
|
|
assert_eq!(code, 200);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) = index.service.get("/tasks?types=*").await;
|
|
assert_eq!(code, 200);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) =
|
|
index.service.get("/tasks?types=*,documentAdditionOrUpdate&statuses=*").await;
|
|
assert_eq!(code, 200, "{:?}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) = index
|
|
.service
|
|
.get("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids=test")
|
|
.await;
|
|
assert_eq!(code, 200, "{:?}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
|
|
let (response, code) = index
|
|
.service
|
|
.get("/tasks?types=*,documentAdditionOrUpdate&statuses=*,failed&indexUids=test,*")
|
|
.await;
|
|
assert_eq!(code, 200, "{:?}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn list_tasks_status_filtered() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
index
|
|
.add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None)
|
|
.await;
|
|
|
|
let (response, code) = index.filtered_tasks(&[], &["succeeded"]).await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 1);
|
|
|
|
// We can't be sure that the update isn't already processed so we can't test this
|
|
// let (response, code) = index.filtered_tasks(&[], &["processing"]).await;
|
|
// assert_eq!(code, 200, "{}", response);
|
|
// assert_eq!(response["results"].as_array().unwrap().len(), 1);
|
|
|
|
index.wait_task(1).await;
|
|
|
|
let (response, code) = index.filtered_tasks(&[], &["succeeded"]).await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn list_tasks_type_filtered() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
index
|
|
.add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None)
|
|
.await;
|
|
|
|
let (response, code) = index.filtered_tasks(&["indexCreation"], &[]).await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 1);
|
|
|
|
let (response, code) =
|
|
index.filtered_tasks(&["indexCreation", "documentAdditionOrUpdate"], &[]).await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn list_tasks_status_and_type_filtered() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
index
|
|
.add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None)
|
|
.await;
|
|
|
|
let (response, code) = index.filtered_tasks(&["indexCreation"], &["failed"]).await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 0);
|
|
|
|
let (response, code) = index
|
|
.filtered_tasks(
|
|
&["indexCreation", "documentAdditionOrUpdate"],
|
|
&["succeeded", "processing", "enqueued"],
|
|
)
|
|
.await;
|
|
assert_eq!(code, 200, "{}", response);
|
|
assert_eq!(response["results"].as_array().unwrap().len(), 2);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn get_task_filter_error() {
|
|
let server = Server::new().await;
|
|
|
|
let (response, code) = server.tasks_filter(json!( { "lol": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query deserialize error: unknown field `lol`",
|
|
"code": "bad_request",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#bad_request"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.tasks_filter(json!( { "uids": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Task uid `pied` is invalid. It should only contain numeric characters.",
|
|
"code": "invalid_task_uids_filter",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_task_uids_filter"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.tasks_filter(json!( { "from": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query deserialize error: invalid digit found in string",
|
|
"code": "bad_request",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#bad_request"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.tasks_filter(json!( { "beforeStartedAt": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Task `beforeStartedAt` `pied` is invalid. It should follow the YYYY-MM-DD or RFC 3339 date-time format.",
|
|
"code": "invalid_task_date_filter",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_task_date_filter"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn delete_task_filter_error() {
|
|
let server = Server::new().await;
|
|
|
|
let (response, code) = server.delete_tasks(json!(null)).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query parameters to filter the tasks to delete are missing. Available query parameters are: `uids`, `indexUids`, `statuses`, `types`, `beforeEnqueuedAt`, `afterEnqueuedAt`, `beforeStartedAt`, `afterStartedAt`, `beforeFinishedAt`, `afterFinishedAt`.",
|
|
"code": "missing_task_filters",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#missing_task_filters"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.delete_tasks(json!({ "lol": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query deserialize error: unknown field `lol`",
|
|
"code": "bad_request",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#bad_request"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.delete_tasks(json!({ "uids": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Task uid `pied` is invalid. It should only contain numeric characters.",
|
|
"code": "invalid_task_uids_filter",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_task_uids_filter"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn cancel_task_filter_error() {
|
|
let server = Server::new().await;
|
|
|
|
let (response, code) = server.cancel_tasks(json!(null)).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query parameters to filter the tasks to cancel are missing. Available query parameters are: `uids`, `indexUids`, `statuses`, `types`, `beforeEnqueuedAt`, `afterEnqueuedAt`, `beforeStartedAt`, `afterStartedAt`, `beforeFinishedAt`, `afterFinishedAt`.",
|
|
"code": "missing_task_filters",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#missing_task_filters"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.cancel_tasks(json!({ "lol": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Query deserialize error: unknown field `lol`",
|
|
"code": "bad_request",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#bad_request"
|
|
}
|
|
"###);
|
|
|
|
let (response, code) = server.cancel_tasks(json!({ "uids": "pied" })).await;
|
|
assert_eq!(code, 400, "{}", response);
|
|
insta::assert_json_snapshot!(response, @r###"
|
|
{
|
|
"message": "Task uid `pied` is invalid. It should only contain numeric characters.",
|
|
"code": "invalid_task_uids_filter",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_task_uids_filter"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
macro_rules! assert_valid_summarized_task {
|
|
($response:expr, $task_type:literal, $index:literal) => {{
|
|
assert_eq!($response.as_object().unwrap().len(), 5);
|
|
assert!($response["taskUid"].as_u64().is_some());
|
|
assert_eq!($response["indexUid"], $index);
|
|
assert_eq!($response["status"], "enqueued");
|
|
assert_eq!($response["type"], $task_type);
|
|
let date = $response["enqueuedAt"].as_str().expect("missing date");
|
|
|
|
OffsetDateTime::parse(date, &Rfc3339).unwrap();
|
|
}};
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_task_view() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
|
|
let (response, _) = index.create(None).await;
|
|
assert_valid_summarized_task!(response, "indexCreation", "test");
|
|
|
|
let (response, _) = index.update(None).await;
|
|
assert_valid_summarized_task!(response, "indexUpdate", "test");
|
|
|
|
let (response, _) = index.update_settings(json!({})).await;
|
|
assert_valid_summarized_task!(response, "settingsUpdate", "test");
|
|
|
|
let (response, _) = index.update_documents(json!([{"id": 1}]), None).await;
|
|
assert_valid_summarized_task!(response, "documentAdditionOrUpdate", "test");
|
|
|
|
let (response, _) = index.add_documents(json!([{"id": 1}]), None).await;
|
|
assert_valid_summarized_task!(response, "documentAdditionOrUpdate", "test");
|
|
|
|
let (response, _) = index.delete_document(1).await;
|
|
assert_valid_summarized_task!(response, "documentDeletion", "test");
|
|
|
|
let (response, _) = index.clear_all_documents().await;
|
|
assert_valid_summarized_task!(response, "documentDeletion", "test");
|
|
|
|
let (response, _) = index.delete().await;
|
|
assert_valid_summarized_task!(response, "indexDeletion", "test");
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_document_addition_or_update() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), None).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "documentAdditionOrUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"receivedDocuments": 1,
|
|
"indexedDocuments": 1
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "documentAdditionOrUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"receivedDocuments": 1,
|
|
"indexedDocuments": 1
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_delete_batch() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.delete_batch(vec![1, 2, 3]).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "documentDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"providedIds": 3,
|
|
"deletedDocuments": 0
|
|
},
|
|
"error": {
|
|
"message": "Index `test` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.create(None).await;
|
|
index.delete_batch(vec![42]).await;
|
|
index.wait_task(2).await;
|
|
let (task, _) = index.get_task(2).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 2,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "documentDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"providedIds": 1,
|
|
"deletedDocuments": 0
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_delete_document() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.delete_document(1).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "documentDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"providedIds": 1,
|
|
"deletedDocuments": 0
|
|
},
|
|
"error": {
|
|
"message": "Index `test` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.create(None).await;
|
|
index.delete_document(42).await;
|
|
index.wait_task(2).await;
|
|
let (task, _) = index.get_task(2).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 2,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "documentDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"providedIds": 1,
|
|
"deletedDocuments": 0
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_settings_update() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
// here we should find my payload even in the failed task.
|
|
index.update_settings(json!({ "rankingRules": ["custom"] })).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
dbg!(&task);
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"rankingRules": [
|
|
"custom"
|
|
]
|
|
},
|
|
"error": {
|
|
"message": "`custom` ranking rule is invalid. Valid ranking rules are words, typo, sort, proximity, attribute, exactness and custom ranking rules.",
|
|
"code": "invalid_ranking_rule",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#invalid_ranking_rule"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.update_settings(json!({ "displayedAttributes": ["doggos", "name"], "filterableAttributes": ["age", "nb_paw_pads"], "sortableAttributes": ["iq"] })).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "settingsUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"displayedAttributes": [
|
|
"doggos",
|
|
"name"
|
|
],
|
|
"filterableAttributes": [
|
|
"age",
|
|
"nb_paw_pads"
|
|
],
|
|
"sortableAttributes": [
|
|
"iq"
|
|
]
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_index_creation() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "indexCreation",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": null
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.create(Some("doggos")).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "indexCreation",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": "doggos"
|
|
},
|
|
"error": {
|
|
"message": "Index `test` already exists.",
|
|
"code": "index_already_exists",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_already_exists"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_index_deletion() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
index.delete().await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "indexDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"deletedDocuments": 0
|
|
},
|
|
"error": {
|
|
"message": "Index `test` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
// is the details correctly set when documents are actually deleted.
|
|
index.add_documents(json!({ "id": 42, "content": "doggos & fluff" }), Some("id")).await;
|
|
index.delete().await;
|
|
index.wait_task(2).await;
|
|
let (task, _) = index.get_task(2).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 2,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "indexDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"deletedDocuments": 1
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
// What happens when you delete an index that doesn't exists.
|
|
index.delete().await;
|
|
index.wait_task(2).await;
|
|
let (task, _) = index.get_task(2).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 2,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "indexDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"deletedDocuments": 1
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_index_update() {
|
|
let server = Server::new().await;
|
|
let index = server.index("test");
|
|
// If the index doesn't exist yet, we should get errors with or without the primary key.
|
|
index.update(None).await;
|
|
index.wait_task(0).await;
|
|
let (task, _) = index.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "indexUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": null
|
|
},
|
|
"error": {
|
|
"message": "Index `test` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.update(Some("bones")).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": "test",
|
|
"status": "failed",
|
|
"type": "indexUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": "bones"
|
|
},
|
|
"error": {
|
|
"message": "Index `test` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
// And run the same two tests once the index do exists.
|
|
index.create(None).await;
|
|
|
|
index.update(None).await;
|
|
index.wait_task(3).await;
|
|
let (task, _) = index.get_task(3).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 3,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "indexUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": null
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
index.update(Some("bones")).await;
|
|
index.wait_task(4).await;
|
|
let (task, _) = index.get_task(4).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 4,
|
|
"indexUid": "test",
|
|
"status": "succeeded",
|
|
"type": "indexUpdate",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"primaryKey": "bones"
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_index_swap() {
|
|
let server = Server::new().await;
|
|
server
|
|
.index_swap(json!([
|
|
{ "indexes": ["doggos", "cattos"] }
|
|
]))
|
|
.await;
|
|
server.wait_task(0).await;
|
|
let (task, _) = server.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": null,
|
|
"status": "failed",
|
|
"type": "indexSwap",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"swaps": [
|
|
{
|
|
"indexes": [
|
|
"doggos",
|
|
"cattos"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"error": {
|
|
"message": "Indexes `cattos`, `doggos` not found.",
|
|
"code": "index_not_found",
|
|
"type": "invalid_request",
|
|
"link": "https://docs.meilisearch.com/errors#index_not_found"
|
|
},
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
|
|
server.index("doggos").create(None).await;
|
|
server.index("cattos").create(None).await;
|
|
server
|
|
.index_swap(json!([
|
|
{ "indexes": ["doggos", "cattos"] }
|
|
]))
|
|
.await;
|
|
server.wait_task(3).await;
|
|
let (task, _) = server.get_task(3).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 3,
|
|
"indexUid": null,
|
|
"status": "succeeded",
|
|
"type": "indexSwap",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"swaps": [
|
|
{
|
|
"indexes": [
|
|
"doggos",
|
|
"cattos"
|
|
]
|
|
}
|
|
]
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_task_cancelation() {
|
|
let server = Server::new().await;
|
|
let index = server.index("doggos");
|
|
// to avoid being flaky we're only going to cancel an already finished task :(
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
server.cancel_tasks(json!({ "uids": [0] })).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": null,
|
|
"status": "succeeded",
|
|
"type": "taskCancelation",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"matchedTasks": 1,
|
|
"canceledTasks": 0,
|
|
"originalFilter": "?uids=0"
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_task_deletion() {
|
|
let server = Server::new().await;
|
|
let index = server.index("doggos");
|
|
// to avoid being flaky we're only going to delete an already finished task :(
|
|
index.create(None).await;
|
|
index.wait_task(0).await;
|
|
server.delete_tasks(json!({ "uids": [0] })).await;
|
|
index.wait_task(1).await;
|
|
let (task, _) = index.get_task(1).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 1,
|
|
"indexUid": null,
|
|
"status": "succeeded",
|
|
"type": "taskDeletion",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"matchedTasks": 1,
|
|
"deletedTasks": 1,
|
|
"originalFilter": "?uids=0"
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|
|
|
|
#[actix_web::test]
|
|
async fn test_summarized_dump_creation() {
|
|
let server = Server::new().await;
|
|
server.create_dump().await;
|
|
server.wait_task(0).await;
|
|
let (task, _) = server.get_task(0).await;
|
|
assert_json_snapshot!(task,
|
|
{ ".details.dumpUid" => "[dumpUid]", ".duration" => "[duration]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]" },
|
|
@r###"
|
|
{
|
|
"uid": 0,
|
|
"indexUid": null,
|
|
"status": "succeeded",
|
|
"type": "dumpCreation",
|
|
"canceledBy": null,
|
|
"details": {
|
|
"dumpUid": "[dumpUid]"
|
|
},
|
|
"error": null,
|
|
"duration": "[duration]",
|
|
"enqueuedAt": "[date]",
|
|
"startedAt": "[date]",
|
|
"finishedAt": "[date]"
|
|
}
|
|
"###);
|
|
}
|