mirror of
				https://github.com/meilisearch/meilisearch.git
				synced 2025-10-30 23:46:28 +00:00 
			
		
		
		
	3370: make the swap indexes not found errors return an IndexNotFound error-code r=irevoire a=irevoire Fix https://github.com/meilisearch/meilisearch/issues/3368 3373: fix a wrong error code and add tests on the document resource r=irevoire a=irevoire Fix https://github.com/meilisearch/meilisearch/issues/3371 3375: Avoid deleting all task invalid canceled by r=irevoire a=Kerollmops Fixes #3369 by making sure that at least one `canceledBy` task filter parameter matches something. Co-authored-by: Tamo <tamo@meilisearch.com> Co-authored-by: Kerollmops <clement@meilisearch.com>
This commit is contained in:
		| @@ -141,8 +141,8 @@ impl ErrorCode for Error { | ||||
|             Error::IndexAlreadyExists(_) => Code::IndexAlreadyExists, | ||||
|             Error::SwapDuplicateIndexesFound(_) => Code::InvalidSwapDuplicateIndexFound, | ||||
|             Error::SwapDuplicateIndexFound(_) => Code::InvalidSwapDuplicateIndexFound, | ||||
|             Error::SwapIndexNotFound(_) => Code::InvalidSwapIndexes, | ||||
|             Error::SwapIndexesNotFound(_) => Code::InvalidSwapIndexes, | ||||
|             Error::SwapIndexNotFound(_) => Code::IndexNotFound, | ||||
|             Error::SwapIndexesNotFound(_) => Code::IndexNotFound, | ||||
|             Error::InvalidTaskDate { field, .. } => (*field).into(), | ||||
|             Error::InvalidTaskUids { .. } => Code::InvalidTaskUids, | ||||
|             Error::InvalidTaskStatuses { .. } => Code::InvalidTaskStatuses, | ||||
|   | ||||
| @@ -502,13 +502,22 @@ impl IndexScheduler { | ||||
|         } | ||||
|  | ||||
|         if let Some(canceled_by) = &query.canceled_by { | ||||
|             let mut all_canceled_tasks = RoaringBitmap::new(); | ||||
|             for cancel_task_uid in canceled_by { | ||||
|                 if let Some(canceled_by_uid) = | ||||
|                     self.canceled_by.get(rtxn, &BEU32::new(*cancel_task_uid))? | ||||
|                 { | ||||
|                     tasks &= canceled_by_uid; | ||||
|                     all_canceled_tasks |= canceled_by_uid; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // if the canceled_by has been specified but no task | ||||
|             // matches then we prefer matching zero than all tasks. | ||||
|             if all_canceled_tasks.is_empty() { | ||||
|                 return Ok(RoaringBitmap::new()); | ||||
|             } else { | ||||
|                 tasks &= all_canceled_tasks; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if let Some(kind) = &query.types { | ||||
|   | ||||
| @@ -10,7 +10,7 @@ source: index-scheduler/src/lib.rs | ||||
| 1 {uid: 1, status: succeeded, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "b", primary_key: Some("id") }} | ||||
| 2 {uid: 2, status: succeeded, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "c", primary_key: Some("id") }} | ||||
| 3 {uid: 3, status: succeeded, details: { primary_key: Some("id") }, kind: IndexCreation { index_uid: "d", primary_key: Some("id") }} | ||||
| 4 {uid: 4, status: failed, error: ResponseError { code: 200, message: "Indexes `e`, `f` not found.", error_code: "invalid_swap_indexes", error_type: "invalid_request", error_link: "https://docs.meilisearch.com/errors#invalid-swap-indexes" }, details: { swaps: [IndexSwap { indexes: ("a", "b") }, IndexSwap { indexes: ("c", "e") }, IndexSwap { indexes: ("d", "f") }] }, kind: IndexSwap { swaps: [IndexSwap { indexes: ("a", "b") }, IndexSwap { indexes: ("c", "e") }, IndexSwap { indexes: ("d", "f") }] }} | ||||
| 4 {uid: 4, status: failed, error: ResponseError { code: 200, message: "Indexes `e`, `f` not found.", error_code: "index_not_found", error_type: "invalid_request", error_link: "https://docs.meilisearch.com/errors#index-not-found" }, details: { swaps: [IndexSwap { indexes: ("a", "b") }, IndexSwap { indexes: ("c", "e") }, IndexSwap { indexes: ("d", "f") }] }, kind: IndexSwap { swaps: [IndexSwap { indexes: ("a", "b") }, IndexSwap { indexes: ("c", "e") }, IndexSwap { indexes: ("d", "f") }] }} | ||||
| ---------------------------------------------------------------------- | ||||
| ### Status: | ||||
| enqueued [] | ||||
|   | ||||
| @@ -128,11 +128,11 @@ pub async fn delete_document( | ||||
| #[derive(Debug, DeserializeFromValue)] | ||||
| #[deserr(error = DeserrQueryParamError, rename_all = camelCase, deny_unknown_fields)] | ||||
| pub struct BrowseQuery { | ||||
|     #[deserr(default, error = DeserrQueryParamError<InvalidDocumentFields>)] | ||||
|     #[deserr(default, error = DeserrQueryParamError<InvalidDocumentOffset>)] | ||||
|     offset: Param<usize>, | ||||
|     #[deserr(default = Param(PAGINATION_DEFAULT_LIMIT), error = DeserrQueryParamError<InvalidDocumentLimit>)] | ||||
|     limit: Param<usize>, | ||||
|     #[deserr(default, error = DeserrQueryParamError<InvalidDocumentLimit>)] | ||||
|     #[deserr(default, error = DeserrQueryParamError<InvalidDocumentFields>)] | ||||
|     fields: OptionStarOrList<String>, | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -132,7 +132,12 @@ impl Index<'_> { | ||||
|         self.service.get(url).await | ||||
|     } | ||||
|  | ||||
|     pub async fn filtered_tasks(&self, types: &[&str], statuses: &[&str]) -> (Value, StatusCode) { | ||||
|     pub async fn filtered_tasks( | ||||
|         &self, | ||||
|         types: &[&str], | ||||
|         statuses: &[&str], | ||||
|         canceled_by: &[&str], | ||||
|     ) -> (Value, StatusCode) { | ||||
|         let mut url = format!("/tasks?indexUids={}", self.uid); | ||||
|         if !types.is_empty() { | ||||
|             let _ = write!(url, "&types={}", types.join(",")); | ||||
| @@ -140,6 +145,9 @@ impl Index<'_> { | ||||
|         if !statuses.is_empty() { | ||||
|             let _ = write!(url, "&statuses={}", statuses.join(",")); | ||||
|         } | ||||
|         if !canceled_by.is_empty() { | ||||
|             let _ = write!(url, "&canceledBy={}", canceled_by.join(",")); | ||||
|         } | ||||
|         self.service.get(url).await | ||||
|     } | ||||
|  | ||||
| @@ -155,6 +163,11 @@ impl Index<'_> { | ||||
|         self.service.get(url).await | ||||
|     } | ||||
|  | ||||
|     pub async fn get_all_documents_raw(&self, options: &str) -> (Value, StatusCode) { | ||||
|         let url = format!("/indexes/{}/documents{}", urlencode(self.uid.as_ref()), options); | ||||
|         self.service.get(url).await | ||||
|     } | ||||
|  | ||||
|     pub async fn get_all_documents(&self, options: GetAllDocumentsOptions) -> (Value, StatusCode) { | ||||
|         let mut url = format!("/indexes/{}/documents?", urlencode(self.uid.as_ref())); | ||||
|         if let Some(limit) = options.limit { | ||||
| @@ -187,6 +200,11 @@ impl Index<'_> { | ||||
|         self.service.post_encoded(url, serde_json::to_value(&ids).unwrap(), self.encoder).await | ||||
|     } | ||||
|  | ||||
|     pub async fn delete_batch_raw(&self, body: Value) -> (Value, StatusCode) { | ||||
|         let url = format!("/indexes/{}/documents/delete-batch", urlencode(self.uid.as_ref())); | ||||
|         self.service.post_encoded(url, body, self.encoder).await | ||||
|     } | ||||
|  | ||||
|     pub async fn settings(&self) -> (Value, StatusCode) { | ||||
|         let url = format!("/indexes/{}/settings", urlencode(self.uid.as_ref())); | ||||
|         self.service.get(url).await | ||||
|   | ||||
| @@ -1077,7 +1077,7 @@ async fn batch_several_documents_addition() { | ||||
|     futures::future::join_all(waiter).await; | ||||
|     index.wait_task(9).await; | ||||
|  | ||||
|     let (response, _code) = index.filtered_tasks(&[], &["failed"]).await; | ||||
|     let (response, _code) = index.filtered_tasks(&[], &["failed"], &[]).await; | ||||
|  | ||||
|     // Check if only the 6th task failed | ||||
|     println!("{}", &response); | ||||
|   | ||||
							
								
								
									
										99
									
								
								meilisearch/tests/documents/errors.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								meilisearch/tests/documents/errors.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| use meili_snap::*; | ||||
| use serde_json::json; | ||||
|  | ||||
| use crate::common::Server; | ||||
|  | ||||
| #[actix_rt::test] | ||||
| async fn get_all_documents_bad_offset() { | ||||
|     let server = Server::new().await; | ||||
|     let index = server.index("test"); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?offset").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `offset`: could not parse `` as a positive integer", | ||||
|       "code": "invalid_document_offset", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-offset" | ||||
|     } | ||||
|     "###); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?offset=doggo").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `offset`: could not parse `doggo` as a positive integer", | ||||
|       "code": "invalid_document_offset", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-offset" | ||||
|     } | ||||
|     "###); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?offset=-1").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `offset`: could not parse `-1` as a positive integer", | ||||
|       "code": "invalid_document_offset", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-offset" | ||||
|     } | ||||
|     "###); | ||||
| } | ||||
|  | ||||
| #[actix_rt::test] | ||||
| async fn get_all_documents_bad_limit() { | ||||
|     let server = Server::new().await; | ||||
|     let index = server.index("test"); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?limit").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `limit`: could not parse `` as a positive integer", | ||||
|       "code": "invalid_document_limit", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-limit" | ||||
|     } | ||||
|     "###); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?limit=doggo").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `limit`: could not parse `doggo` as a positive integer", | ||||
|       "code": "invalid_document_limit", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-limit" | ||||
|     } | ||||
|     "###); | ||||
|  | ||||
|     let (response, code) = index.get_all_documents_raw("?limit=-1").await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Invalid value in parameter `limit`: could not parse `-1` as a positive integer", | ||||
|       "code": "invalid_document_limit", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#invalid-document-limit" | ||||
|     } | ||||
|     "###); | ||||
| } | ||||
|  | ||||
| #[actix_rt::test] | ||||
| async fn delete_documents_batch() { | ||||
|     let server = Server::new().await; | ||||
|     let index = server.index("test"); | ||||
|  | ||||
|     let (response, code) = index.delete_batch_raw(json!("doggo")).await; | ||||
|     snapshot!(code, @"400 Bad Request"); | ||||
|     snapshot!(json_string!(response), @r###" | ||||
|     { | ||||
|       "message": "Json deserialize error: invalid type: string \"doggo\", expected a sequence at line 1 column 7", | ||||
|       "code": "bad_request", | ||||
|       "type": "invalid_request", | ||||
|       "link": "https://docs.meilisearch.com/errors#bad-request" | ||||
|     } | ||||
|     "###); | ||||
| } | ||||
| @@ -1,4 +1,5 @@ | ||||
| mod add_documents; | ||||
| mod delete_documents; | ||||
| mod errors; | ||||
| mod get_documents; | ||||
| mod update_documents; | ||||
|   | ||||
| @@ -115,7 +115,7 @@ async fn list_tasks_status_filtered() { | ||||
|         .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) | ||||
|         .await; | ||||
|  | ||||
|     let (response, code) = index.filtered_tasks(&[], &["succeeded"]).await; | ||||
|     let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; | ||||
|     assert_eq!(code, 200, "{}", response); | ||||
|     assert_eq!(response["results"].as_array().unwrap().len(), 1); | ||||
|  | ||||
| @@ -126,7 +126,7 @@ async fn list_tasks_status_filtered() { | ||||
|  | ||||
|     index.wait_task(1).await; | ||||
|  | ||||
|     let (response, code) = index.filtered_tasks(&[], &["succeeded"]).await; | ||||
|     let (response, code) = index.filtered_tasks(&[], &["succeeded"], &[]).await; | ||||
|     assert_eq!(code, 200, "{}", response); | ||||
|     assert_eq!(response["results"].as_array().unwrap().len(), 2); | ||||
| } | ||||
| @@ -141,16 +141,31 @@ async fn list_tasks_type_filtered() { | ||||
|         .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) | ||||
|         .await; | ||||
|  | ||||
|     let (response, code) = index.filtered_tasks(&["indexCreation"], &[]).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; | ||||
|         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_invalid_canceled_by_filter() { | ||||
|     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(&[], &[], &["0"]).await; | ||||
|     assert_eq!(code, 200, "{}", response); | ||||
|     assert_eq!(response["results"].as_array().unwrap().len(), 0); | ||||
| } | ||||
|  | ||||
| #[actix_rt::test] | ||||
| async fn list_tasks_status_and_type_filtered() { | ||||
|     let server = Server::new().await; | ||||
| @@ -161,7 +176,7 @@ async fn list_tasks_status_and_type_filtered() { | ||||
|         .add_documents(serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), None) | ||||
|         .await; | ||||
|  | ||||
|     let (response, code) = index.filtered_tasks(&["indexCreation"], &["failed"]).await; | ||||
|     let (response, code) = index.filtered_tasks(&["indexCreation"], &["failed"], &[]).await; | ||||
|     assert_eq!(code, 200, "{}", response); | ||||
|     assert_eq!(response["results"].as_array().unwrap().len(), 0); | ||||
|  | ||||
| @@ -169,6 +184,7 @@ async fn list_tasks_status_and_type_filtered() { | ||||
|         .filtered_tasks( | ||||
|             &["indexCreation", "documentAdditionOrUpdate"], | ||||
|             &["succeeded", "processing", "enqueued"], | ||||
|             &[], | ||||
|         ) | ||||
|         .await; | ||||
|     assert_eq!(code, 200, "{}", response); | ||||
| @@ -844,9 +860,9 @@ async fn test_summarized_index_swap() { | ||||
|       }, | ||||
|       "error": { | ||||
|         "message": "Indexes `cattos`, `doggos` not found.", | ||||
|         "code": "invalid_swap_indexes", | ||||
|         "code": "index_not_found", | ||||
|         "type": "invalid_request", | ||||
|         "link": "https://docs.meilisearch.com/errors#invalid-swap-indexes" | ||||
|         "link": "https://docs.meilisearch.com/errors#index-not-found" | ||||
|       }, | ||||
|       "duration": "[duration]", | ||||
|       "enqueuedAt": "[date]", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user