From 588add8beca74004cbc9270760b8bd179aa833f3 Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 17:48:37 +0100 Subject: [PATCH 01/26] rename update fields to camel case --- src/data/mod.rs | 2 +- .../local_index_controller/mod.rs | 18 +++++++++--------- src/index_controller/mod.rs | 10 +++++----- src/index_controller/updates.rs | 3 ++- src/option.rs | 1 - src/routes/index.rs | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/data/mod.rs b/src/data/mod.rs index 656d19880..ed5ce4952 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -122,7 +122,7 @@ impl Data { Ok(self .list_indexes()? .into_iter() - .find(|i| i.name == name.as_ref())) + .find(|i| i.uid == name.as_ref())) } pub fn create_index(&self, name: impl AsRef, primary_key: Option>) -> anyhow::Result { diff --git a/src/index_controller/local_index_controller/mod.rs b/src/index_controller/local_index_controller/mod.rs index 47de1a370..14efe42c7 100644 --- a/src/index_controller/local_index_controller/mod.rs +++ b/src/index_controller/local_index_controller/mod.rs @@ -70,7 +70,7 @@ impl IndexController for LocalIndexController { } let meta = IndexMetadata { - name: index_name, + uid: index_name, uuid: meta.uuid.clone(), created_at: meta.created_at, updated_at: meta.created_at, @@ -124,18 +124,18 @@ impl IndexController for LocalIndexController { fn list_indexes(&self) -> anyhow::Result> { let metas = self.indexes.list_indexes()?; let mut output_meta = Vec::new(); - for (name, meta, primary_key) in metas { + for (uid, meta, primary_key) in metas { let created_at = meta.created_at; let uuid = meta.uuid; let updated_at = self - .all_update_status(&name)? + .all_update_status(&uid)? .iter() .filter_map(|u| u.processed().map(|u| u.processed_at)) .max() .unwrap_or(created_at); let index_meta = IndexMetadata { - name, + uid, created_at, updated_at, uuid, @@ -146,7 +146,7 @@ impl IndexController for LocalIndexController { Ok(output_meta) } - fn update_index(&self, name: impl AsRef, index_settings: IndexSettings) -> anyhow::Result { + fn update_index(&self, uid: impl AsRef, index_settings: IndexSettings) -> anyhow::Result { if index_settings.name.is_some() { bail!("can't udpate an index name.") } @@ -154,7 +154,7 @@ impl IndexController for LocalIndexController { let (primary_key, meta) = match index_settings.primary_key { Some(ref primary_key) => { self.indexes - .update_index(&name, |index| { + .update_index(&uid, |index| { let mut txn = index.write_txn()?; if index.primary_key(&txn)?.is_some() { bail!("primary key already exists.") @@ -166,8 +166,8 @@ impl IndexController for LocalIndexController { }, None => { let (index, meta) = self.indexes - .index_with_meta(&name)? - .with_context(|| format!("index {:?} doesn't exist.", name.as_ref()))?; + .index_with_meta(&uid)? + .with_context(|| format!("index {:?} doesn't exist.", uid.as_ref()))?; let primary_key = index .primary_key(&index.read_txn()?)? .map(String::from); @@ -176,7 +176,7 @@ impl IndexController for LocalIndexController { }; Ok(IndexMetadata { - name: name.as_ref().to_string(), + uid: uid.as_ref().to_string(), uuid: meta.uuid.clone(), created_at: meta.created_at, updated_at: meta.updated_at, diff --git a/src/index_controller/mod.rs b/src/index_controller/mod.rs index 5bdaf8737..b20e43749 100644 --- a/src/index_controller/mod.rs +++ b/src/index_controller/mod.rs @@ -21,7 +21,7 @@ pub type UpdateStatus = updates::UpdateStatus; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct IndexMetadata { - pub name: String, + pub uid: String, uuid: Uuid, created_at: DateTime, updated_at: DateTime, @@ -223,8 +223,8 @@ pub(crate) mod test { let indexes = controller.list_indexes().unwrap(); assert_eq!(indexes.len(), 2); - assert_eq!(indexes[0].name, "test_index"); - assert_eq!(indexes[1].name, "test_index2"); + assert_eq!(indexes[0].uid, "test_index"); + assert_eq!(indexes[1].uid, "test_index2"); assert_eq!(indexes[1].primary_key.clone().unwrap(), "foo"); } @@ -252,7 +252,7 @@ pub(crate) mod test { }; let result = controller.update_index("test", settings).unwrap(); - assert_eq!(result.name, "test"); + assert_eq!(result.uid, "test"); assert_eq!(result.created_at, result.updated_at); assert!(result.primary_key.is_none()); @@ -271,7 +271,7 @@ pub(crate) mod test { }; let result = controller.update_index("test", settings.clone()).unwrap(); - assert_eq!(result.name, "test"); + assert_eq!(result.uid, "test"); assert!(result.created_at < result.updated_at); assert_eq!(result.primary_key.unwrap(), "foo"); diff --git a/src/index_controller/updates.rs b/src/index_controller/updates.rs index 900987ba6..b8f1e31f4 100644 --- a/src/index_controller/updates.rs +++ b/src/index_controller/updates.rs @@ -2,6 +2,7 @@ use chrono::{Utc, DateTime}; use serde::{Serialize, Deserialize}; #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Pending { pub update_id: u64, pub meta: M, @@ -115,7 +116,7 @@ impl Failed { } #[derive(Debug, PartialEq, Eq, Hash, Serialize)] -#[serde(tag = "status")] +#[serde(tag = "status", rename_all = "camelCase")] pub enum UpdateStatus { Processing(Processing), Pending(Pending), diff --git a/src/option.rs b/src/option.rs index 38f99880e..c88110ccd 100644 --- a/src/option.rs +++ b/src/option.rs @@ -64,7 +64,6 @@ pub struct IndexerOpts { pub indexing_jobs: Option, } -#[cfg(test)] impl Default for IndexerOpts { fn default() -> Self { Self { diff --git a/src/routes/index.rs b/src/routes/index.rs index 62684ddaa..2c478432b 100644 --- a/src/routes/index.rs +++ b/src/routes/index.rs @@ -52,7 +52,7 @@ async fn get_index( #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] struct IndexCreateRequest { - name: String, + uid: String, primary_key: Option, } @@ -61,7 +61,7 @@ async fn create_index( data: web::Data, body: web::Json, ) -> Result { - match data.create_index(&body.name, body.primary_key.clone()) { + match data.create_index(&body.uid, body.primary_key.clone()) { Ok(meta) => { let json = serde_json::to_string(&meta).unwrap(); Ok(HttpResponse::Ok().body(json)) From 72eed0e369d87dba70e52a010b4018b0186e02f1 Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 19:50:52 +0100 Subject: [PATCH 02/26] test create index --- tests/common/index.rs | 27 ++ tests/common/mod.rs | 30 ++ tests/common/server.rs | 537 ++++++++++++++++++++++++++++++++++++ tests/common/service.rs | 39 +++ tests/index/create_index.rs | 48 ++++ tests/index/mod.rs | 2 + tests/integration.rs | 3 + tests/search/mod.rs | 3 + 8 files changed, 689 insertions(+) create mode 100644 tests/common/index.rs create mode 100644 tests/common/mod.rs create mode 100644 tests/common/server.rs create mode 100644 tests/common/service.rs create mode 100644 tests/index/create_index.rs create mode 100644 tests/index/mod.rs create mode 100644 tests/integration.rs create mode 100644 tests/search/mod.rs diff --git a/tests/common/index.rs b/tests/common/index.rs new file mode 100644 index 000000000..69b383b4a --- /dev/null +++ b/tests/common/index.rs @@ -0,0 +1,27 @@ +use actix_web::http::StatusCode; +use serde_json::{json, Value}; + +use super::service::Service; + +pub struct Index<'a> { + pub uid: String, + pub service: &'a Service, +} + +impl Index<'_> { + pub async fn get(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}", self.uid); + self.service.get(url).await + } + + pub async fn create<'a>( + &'a self, + primary_key: Option<&str>, + ) -> (Value, StatusCode) { + let body = json!({ + "uid": self.uid, + "primaryKey": primary_key, + }); + self.service.post("/indexes", body).await + } +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs new file mode 100644 index 000000000..36c7e8190 --- /dev/null +++ b/tests/common/mod.rs @@ -0,0 +1,30 @@ +mod index; +mod server; +mod service; + +pub use server::Server; + +/// Performs a search test on both post and get routes +#[macro_export] +macro_rules! test_post_get_search { + ($server:expr, $query:expr, |$response:ident, $status_code:ident | $block:expr) => { + let post_query: meilisearch_http::routes::search::SearchQueryPost = + serde_json::from_str(&$query.clone().to_string()).unwrap(); + let get_query: meilisearch_http::routes::search::SearchQuery = post_query.into(); + let get_query = ::serde_url_params::to_string(&get_query).unwrap(); + let ($response, $status_code) = $server.search_get(&get_query).await; + let _ = ::std::panic::catch_unwind(|| $block).map_err(|e| { + panic!( + "panic in get route: {:?}", + e.downcast_ref::<&str>().unwrap() + ) + }); + let ($response, $status_code) = $server.search_post($query).await; + let _ = ::std::panic::catch_unwind(|| $block).map_err(|e| { + panic!( + "panic in post route: {:?}", + e.downcast_ref::<&str>().unwrap() + ) + }); + }; +} diff --git a/tests/common/server.rs b/tests/common/server.rs new file mode 100644 index 000000000..5982af973 --- /dev/null +++ b/tests/common/server.rs @@ -0,0 +1,537 @@ +use tempdir::TempDir; +use byte_unit::{Byte, ByteUnit}; + +use meilisearch_http::data::Data; +use meilisearch_http::option::{Opt, IndexerOpts}; + +use super::index::Index; +use super::service::Service; + +pub struct Server { + service: Service, +} + +impl Server { + pub async fn new() -> Self { + let tmp_dir = TempDir::new("meilisearch").unwrap(); + + let opt = Opt { + db_path: tmp_dir.path().join("db"), + dumps_dir: tmp_dir.path().join("dump"), + dump_batch_size: 16, + http_addr: "127.0.0.1:7700".to_owned(), + master_key: None, + env: "development".to_owned(), + no_analytics: true, + max_mdb_size: Byte::from_unit(4.0, ByteUnit::GiB).unwrap(), + max_udb_size: Byte::from_unit(4.0, ByteUnit::GiB).unwrap(), + http_payload_size_limit: Byte::from_unit(10.0, ByteUnit::MiB).unwrap(), + ssl_cert_path: None, + ssl_key_path: None, + ssl_auth_path: None, + ssl_ocsp_path: None, + ssl_require_auth: false, + ssl_resumption: false, + ssl_tickets: false, + import_snapshot: None, + ignore_missing_snapshot: false, + ignore_snapshot_if_db_exists: false, + snapshot_dir: ".".into(), + schedule_snapshot: false, + snapshot_interval_sec: None, + import_dump: None, + indexer_options: IndexerOpts::default(), + }; + + let data = Data::new(opt).unwrap(); + let service = Service(data); + + Server { + service, + } + } + + //pub async fn test_server() -> Self { + //let mut server = Self::new(); + + //let body = json!({ + //"uid": "test", + //"primaryKey": "id", + //}); + + //server.create_index(body).await; + + //let body = json!({ + ////"rankingRules": [ + ////"typo", + ////"words", + ////"proximity", + ////"attribute", + ////"wordsPosition", + ////"exactness", + ////], + //"searchableAttributes": [ + //"balance", + //"picture", + //"age", + //"color", + //"name", + //"gender", + //"email", + //"phone", + //"address", + //"about", + //"registered", + //"latitude", + //"longitude", + //"tags", + //], + //"displayedAttributes": [ + //"id", + //"isActive", + //"balance", + //"picture", + //"age", + //"color", + //"name", + //"gender", + //"email", + //"phone", + //"address", + //"about", + //"registered", + //"latitude", + //"longitude", + //"tags", + //], + //}); + + //server.update_all_settings(body).await; + + //let dataset = include_bytes!("../assets/test_set.json"); + + //let body: Value = serde_json::from_slice(dataset).unwrap(); + + //server.add_or_replace_multiple_documents(body).await; + //server + //} + + //pub fn data(&self) -> &Data { + //&self.data + //} + + //pub async fn wait_update_id(&mut self, update_id: u64) { + //// try 10 times to get status, or panic to not wait forever + //for _ in 0..10 { + //let (response, status_code) = self.get_update_status(update_id).await; + //assert_eq!(status_code, 200); + + //if response["status"] == "processed" || response["status"] == "failed" { + //// eprintln!("{:#?}", response); + //return; + //} + + //delay_for(Duration::from_secs(1)).await; + //} + //panic!("Timeout waiting for update id"); + //} + + // Global Http request GET/POST/DELETE async or sync + + //pub async fn get_request(&mut self, url: &str) -> (Value, StatusCode) { + //eprintln!("get_request: {}", url); + + //let mut app = + //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; + + //let req = test::TestRequest::get().uri(url).to_request(); + //let res = test::call_service(&mut app, req).await; + //let status_code = res.status(); + + //let body = test::read_body(res).await; + //let response = serde_json::from_slice(&body).unwrap_or_default(); + //(response, status_code) + //} + + + //pub async fn post_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { + //eprintln!("post_request_async: {}", url); + + //let (response, status_code) = self.post_request(url, body).await; + //eprintln!("response: {}", response); + //assert!(response["updateId"].as_u64().is_some()); + //self.wait_update_id(response["updateId"].as_u64().unwrap()) + //.await; + //(response, status_code) + //} + + //pub async fn put_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) { + //eprintln!("put_request: {}", url); + + //let mut app = + //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; + + //let req = test::TestRequest::put() + //.uri(url) + //.set_json(&body) + //.to_request(); + //let res = test::call_service(&mut app, req).await; + //let status_code = res.status(); + + //let body = test::read_body(res).await; + //let response = serde_json::from_slice(&body).unwrap_or_default(); + //(response, status_code) + //} + + //pub async fn put_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { + //eprintln!("put_request_async: {}", url); + + //let (response, status_code) = self.put_request(url, body).await; + //assert!(response["updateId"].as_u64().is_some()); + //assert_eq!(status_code, 202); + //self.wait_update_id(response["updateId"].as_u64().unwrap()) + //.await; + //(response, status_code) + //} + + //pub async fn delete_request(&mut self, url: &str) -> (Value, StatusCode) { + //eprintln!("delete_request: {}", url); + + //let mut app = + //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; + + //let req = test::TestRequest::delete().uri(url).to_request(); + //let res = test::call_service(&mut app, req).await; + //let status_code = res.status(); + + //let body = test::read_body(res).await; + //let response = serde_json::from_slice(&body).unwrap_or_default(); + //(response, status_code) + //} + + //pub async fn delete_request_async(&mut self, url: &str) -> (Value, StatusCode) { + //eprintln!("delete_request_async: {}", url); + + //let (response, status_code) = self.delete_request(url).await; + //assert!(response["updateId"].as_u64().is_some()); + //assert_eq!(status_code, 202); + //self.wait_update_id(response["updateId"].as_u64().unwrap()) + //.await; + //(response, status_code) + //} + + // All Routes + + //pub async fn list_indexes(&mut self) -> (Value, StatusCode) { + //self.get_request("/indexes").await + //} + + /// Returns a view to an index. There is no guarantee that the index exists. + pub fn index<'a>(&'a self, uid: impl AsRef) -> Index<'a> { + Index { + uid: uid.as_ref().to_string(), + service: &self.service, + } + } + //pub async fn search_multi_index(&mut self, query: &str) -> (Value, StatusCode) { + //let url = format!("/indexes/search?{}", query); + //self.get_request(&url).await + //} + + //pub async fn get_index(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_index(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}", self.uid); + //self.put_request(&url, body).await + //} + + //pub async fn delete_index(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}", self.uid); + //self.delete_request(&url).await + //} + + //pub async fn search_get(&mut self, query: &str) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/search?{}", self.uid, query); + //self.get_request(&url).await + //} + + //pub async fn search_post(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/search", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn get_all_updates_status(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/updates", self.uid); + //self.get_request(&url).await + //} + + //pub async fn get_update_status(&mut self, update_id: u64) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/updates/{}", self.uid, update_id); + //self.get_request(&url).await + //} + + //pub async fn get_all_documents(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/documents", self.uid); + //self.get_request(&url).await + //} + + //pub async fn add_or_replace_multiple_documents(&mut self, body: Value) { + //let url = format!("/indexes/{}/documents", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn add_or_replace_multiple_documents_sync( + //&mut self, + //body: Value, + //) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/documents", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn add_or_update_multiple_documents(&mut self, body: Value) { + //let url = format!("/indexes/{}/documents", self.uid); + //self.put_request_async(&url, body).await; + //} + + //pub async fn clear_all_documents(&mut self) { + //let url = format!("/indexes/{}/documents", self.uid); + //self.delete_request_async(&url).await; + //} + + //pub async fn get_document(&mut self, document_id: impl ToString) -> (Value, StatusCode) { + //let url = format!( + //"/indexes/{}/documents/{}", + //self.uid, + //document_id.to_string() + //); + //self.get_request(&url).await + //} + + //pub async fn delete_document(&mut self, document_id: impl ToString) -> (Value, StatusCode) { + //let url = format!( + //"/indexes/{}/documents/{}", + //self.uid, + //document_id.to_string() + //); + //self.delete_request_async(&url).await + //} + + //pub async fn delete_multiple_documents(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/documents/delete-batch", self.uid); + //self.post_request_async(&url, body).await + //} + + //pub async fn get_all_settings(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_all_settings(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_all_settings_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_all_settings(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_ranking_rules(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_ranking_rules(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_ranking_rules_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_ranking_rules(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_distinct_attribute(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_distinct_attribute(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_distinct_attribute_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_distinct_attribute(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_primary_key(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/primary_key", self.uid); + //self.get_request(&url).await + //} + + //pub async fn get_searchable_attributes(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_searchable_attributes(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_searchable_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_searchable_attributes(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_displayed_attributes(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_displayed_attributes(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_displayed_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_displayed_attributes(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_attributes_for_faceting(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_attributes_for_faceting(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_attributes_for_faceting_sync( + //&mut self, + //body: Value, + //) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_attributes_for_faceting(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_synonyms(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/synonyms", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_synonyms(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/synonyms", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_synonyms_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/synonyms", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_synonyms(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/synonyms", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_stop_words(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/stop-words", self.uid); + //self.get_request(&url).await + //} + + //pub async fn update_stop_words(&mut self, body: Value) { + //let url = format!("/indexes/{}/settings/stop-words", self.uid); + //self.post_request_async(&url, body).await; + //} + + //pub async fn update_stop_words_sync(&mut self, body: Value) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/stop-words", self.uid); + //self.post_request(&url, body).await + //} + + //pub async fn delete_stop_words(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/settings/stop-words", self.uid); + //self.delete_request_async(&url).await + //} + + //pub async fn get_index_stats(&mut self) -> (Value, StatusCode) { + //let url = format!("/indexes/{}/stats", self.uid); + //self.get_request(&url).await + //} + + //pub async fn list_keys(&mut self) -> (Value, StatusCode) { + //self.get_request("/keys").await + //} + + //pub async fn get_health(&mut self) -> (Value, StatusCode) { + //self.get_request("/health").await + //} + + //pub async fn update_health(&mut self, body: Value) -> (Value, StatusCode) { + //self.put_request("/health", body).await + //} + + //pub async fn get_version(&mut self) -> (Value, StatusCode) { + //self.get_request("/version").await + //} + + //pub async fn get_sys_info(&mut self) -> (Value, StatusCode) { + //self.get_request("/sys-info").await + //} + + //pub async fn get_sys_info_pretty(&mut self) -> (Value, StatusCode) { + //self.get_request("/sys-info/pretty").await + //} + + //pub async fn trigger_dump(&self) -> (Value, StatusCode) { + //self.post_request("/dumps", Value::Null).await + //} + + //pub async fn get_dump_status(&mut self, dump_uid: &str) -> (Value, StatusCode) { + //let url = format!("/dumps/{}/status", dump_uid); + //self.get_request(&url).await + //} + + //pub async fn trigger_dump_importation(&mut self, dump_uid: &str) -> (Value, StatusCode) { + //let url = format!("/dumps/{}/import", dump_uid); + //self.get_request(&url).await + //} +} diff --git a/tests/common/service.rs b/tests/common/service.rs new file mode 100644 index 000000000..21442cf64 --- /dev/null +++ b/tests/common/service.rs @@ -0,0 +1,39 @@ +use actix_web::{http::StatusCode, test}; +use serde_json::Value; + +use meilisearch_http::data::Data; +use meilisearch_http::helpers::NormalizePath; + +pub struct Service(pub Data); + +impl Service { + pub async fn post(&self, url: impl AsRef, body: Value) -> (Value, StatusCode) { + let mut app = + test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; + + let req = test::TestRequest::post() + .uri(url.as_ref()) + .set_json(&body) + .to_request(); + let res = test::call_service(&mut app, req).await; + let status_code = res.status(); + + let body = test::read_body(res).await; + let response = serde_json::from_slice(&body).unwrap_or_default(); + (response, status_code) + } + + pub async fn get(&self, url: impl AsRef) -> (Value, StatusCode) { + let mut app = + test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; + + let req = test::TestRequest::get().uri(url.as_ref()).to_request(); + let res = test::call_service(&mut app, req).await; + let status_code = res.status(); + + let body = test::read_body(res).await; + let response = serde_json::from_slice(&body).unwrap_or_default(); + (response, status_code) + } +} + diff --git a/tests/index/create_index.rs b/tests/index/create_index.rs new file mode 100644 index 000000000..b7bce4e26 --- /dev/null +++ b/tests/index/create_index.rs @@ -0,0 +1,48 @@ +use crate::common::Server; +use serde_json::Value; + +#[actix_rt::test] +async fn create_index_no_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + let (response, code) = index.create(None).await; + + assert_eq!(code, 200); + assert_eq!(response["uid"], "test"); + assert!(response.get("uuid").is_some()); + assert!(response.get("createdAt").is_some()); + assert!(response.get("updatedAt").is_some()); + assert_eq!(response["createdAt"], response["updatedAt"]); + assert_eq!(response["primaryKey"], Value::Null); + assert_eq!(response.as_object().unwrap().len(), 5); +} + +#[actix_rt::test] +async fn create_index_with_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + let (response, code) = index.create(Some("primary")).await; + + assert_eq!(code, 200); + assert_eq!(response["uid"], "test"); + assert!(response.get("uuid").is_some()); + assert!(response.get("createdAt").is_some()); + assert!(response.get("updatedAt").is_some()); + assert_eq!(response["createdAt"], response["updatedAt"]); + assert_eq!(response["primaryKey"], "primary"); + assert_eq!(response.as_object().unwrap().len(), 5); +} + +// TODO: partial test since we are testing error, amd error is not yet fully implemented in +// transplant +#[actix_rt::test] +async fn create_existing_index() { + let server = Server::new().await; + let index = server.index("test"); + let (_, code) = index.create(Some("primary")).await; + + assert_eq!(code, 200); + + let (_response, code) = index.create(Some("primary")).await; + assert_eq!(code, 400); +} diff --git a/tests/index/mod.rs b/tests/index/mod.rs new file mode 100644 index 000000000..cd3203e6b --- /dev/null +++ b/tests/index/mod.rs @@ -0,0 +1,2 @@ +mod create_index; +mod get_index; diff --git a/tests/integration.rs b/tests/integration.rs new file mode 100644 index 000000000..2b8dc5612 --- /dev/null +++ b/tests/integration.rs @@ -0,0 +1,3 @@ +mod common; +mod search; +mod index; diff --git a/tests/search/mod.rs b/tests/search/mod.rs new file mode 100644 index 000000000..735a3478f --- /dev/null +++ b/tests/search/mod.rs @@ -0,0 +1,3 @@ +// 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. + From 68692a256e726004a647927f66464fde8666fd35 Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 19:52:00 +0100 Subject: [PATCH 03/26] test get index --- tests/index/create_index.rs | 10 ++++++++++ tests/index/get_index.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/index/get_index.rs diff --git a/tests/index/create_index.rs b/tests/index/create_index.rs index b7bce4e26..c118d5566 100644 --- a/tests/index/create_index.rs +++ b/tests/index/create_index.rs @@ -46,3 +46,13 @@ async fn create_existing_index() { let (_response, code) = index.create(Some("primary")).await; assert_eq!(code, 400); } + +// test fails (issue #46) +#[actix_rt::test] +#[ignore] +async fn create_with_invalid_index_uid() { + let server = Server::new().await; + let index = server.index("test test"); + let (_, code) = index.create(None).await; + assert_eq!(code, 400); +} diff --git a/tests/index/get_index.rs b/tests/index/get_index.rs new file mode 100644 index 000000000..8b0f27441 --- /dev/null +++ b/tests/index/get_index.rs @@ -0,0 +1,34 @@ +use crate::common::Server; +use serde_json::Value; + +#[actix_rt::test] +async fn create_and_get_index() { + let server = Server::new().await; + let index = server.index("test"); + let (_, code) = index.create(None).await; + + assert_eq!(code, 200); + + let (response, code) = index.get().await; + + assert_eq!(code, 200); + assert_eq!(response["uid"], "test"); + assert!(response.get("uuid").is_some()); + assert!(response.get("createdAt").is_some()); + assert!(response.get("updatedAt").is_some()); + assert_eq!(response["createdAt"], response["updatedAt"]); + assert_eq!(response["primaryKey"], Value::Null); + assert_eq!(response.as_object().unwrap().len(), 5); +} + +// TODO: partial test since we are testing error, amd error is not yet fully implemented in +// transplant +#[actix_rt::test] +async fn get_unexisting_index() { + let server = Server::new().await; + let index = server.index("test"); + + let (_response, code) = index.get().await; + + assert_eq!(code, 400); +} From 4c5effe714764ac4be1e240157f35cb150259009 Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 20:28:10 +0100 Subject: [PATCH 04/26] test index update --- src/data/updates.rs | 6 +++--- tests/common/index.rs | 9 +++++++++ tests/common/server.rs | 17 ----------------- tests/common/service.rs | 16 ++++++++++++++++ tests/index/mod.rs | 1 + 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/data/updates.rs b/src/data/updates.rs index 92d682b1d..fbb9be801 100644 --- a/src/data/updates.rs +++ b/src/data/updates.rs @@ -1,13 +1,13 @@ use std::ops::Deref; -use milli::update::{IndexDocumentsMethod, UpdateFormat}; use async_compression::tokio_02::write::GzipEncoder; use futures_util::stream::StreamExt; +use milli::update::{IndexDocumentsMethod, UpdateFormat}; use tokio::io::AsyncWriteExt; -use super::Data; -use crate::index_controller::{IndexController, Settings, IndexSettings, IndexMetadata}; use crate::index_controller::UpdateStatus; +use crate::index_controller::{IndexController, Settings, IndexSettings, IndexMetadata}; +use super::Data; impl Data { pub async fn add_documents( diff --git a/tests/common/index.rs b/tests/common/index.rs index 69b383b4a..5f297bbb5 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -24,4 +24,13 @@ impl Index<'_> { }); self.service.post("/indexes", body).await } + + pub async fn update(&self, primary_key: Option<&str>) -> (Value, StatusCode) { + let body = json!({ + "primaryKey": primary_key, + }); + let url = format!("/indexes/{}", self.uid); + + self.service.put(url, body).await + } } diff --git a/tests/common/server.rs b/tests/common/server.rs index 5982af973..23aba5010 100644 --- a/tests/common/server.rs +++ b/tests/common/server.rs @@ -165,23 +165,6 @@ impl Server { //(response, status_code) //} - //pub async fn put_request(&mut self, url: &str, body: Value) -> (Value, StatusCode) { - //eprintln!("put_request: {}", url); - - //let mut app = - //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; - - //let req = test::TestRequest::put() - //.uri(url) - //.set_json(&body) - //.to_request(); - //let res = test::call_service(&mut app, req).await; - //let status_code = res.status(); - - //let body = test::read_body(res).await; - //let response = serde_json::from_slice(&body).unwrap_or_default(); - //(response, status_code) - //} //pub async fn put_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { //eprintln!("put_request_async: {}", url); diff --git a/tests/common/service.rs b/tests/common/service.rs index 21442cf64..0ff1320df 100644 --- a/tests/common/service.rs +++ b/tests/common/service.rs @@ -35,5 +35,21 @@ impl Service { let response = serde_json::from_slice(&body).unwrap_or_default(); (response, status_code) } + + pub async fn put(&self, url: impl AsRef, body: Value) -> (Value, StatusCode) { + let mut app = + test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; + + let req = test::TestRequest::put() + .uri(url.as_ref()) + .set_json(&body) + .to_request(); + let res = test::call_service(&mut app, req).await; + let status_code = res.status(); + + let body = test::read_body(res).await; + let response = serde_json::from_slice(&body).unwrap_or_default(); + (response, status_code) + } } diff --git a/tests/index/mod.rs b/tests/index/mod.rs index cd3203e6b..2aefd99c2 100644 --- a/tests/index/mod.rs +++ b/tests/index/mod.rs @@ -1,2 +1,3 @@ mod create_index; mod get_index; +mod update_index; From ed3f8f5cc027ade2bc51cd6a3873a61423eff3ae Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 20:32:34 +0100 Subject: [PATCH 05/26] test create multiple indexes --- tests/index/create_index.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/index/create_index.rs b/tests/index/create_index.rs index c118d5566..3ff452c33 100644 --- a/tests/index/create_index.rs +++ b/tests/index/create_index.rs @@ -56,3 +56,21 @@ async fn create_with_invalid_index_uid() { let (_, code) = index.create(None).await; assert_eq!(code, 400); } + +#[actix_rt::test] +async fn test_create_multiple_indexes() { + let server = Server::new().await; + let index1 = server.index("test1"); + let index2 = server.index("test2"); + let index3 = server.index("test3"); + let index4 = server.index("test4"); + + index1.create(None).await; + index2.create(None).await; + index3.create(None).await; + + assert_eq!(index1.get().await.1, 200); + assert_eq!(index2.get().await.1, 200); + assert_eq!(index3.get().await.1, 200); + assert_eq!(index4.get().await.1, 400); +} From b293948d36f99bdd879d67e975cbc7cb67e522d7 Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 20:44:33 +0100 Subject: [PATCH 06/26] test index delete --- tests/common/index.rs | 5 +++++ tests/common/server.rs | 30 ------------------------------ tests/common/service.rs | 13 +++++++++++++ tests/index/mod.rs | 1 + tests/integration.rs | 6 ++++++ 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/tests/common/index.rs b/tests/common/index.rs index 5f297bbb5..0b80f3fde 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -33,4 +33,9 @@ impl Index<'_> { self.service.put(url, body).await } + + pub async fn delete(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}", self.uid); + self.service.delete(url).await + } } diff --git a/tests/common/server.rs b/tests/common/server.rs index 23aba5010..30d6c40fd 100644 --- a/tests/common/server.rs +++ b/tests/common/server.rs @@ -138,22 +138,6 @@ impl Server { // Global Http request GET/POST/DELETE async or sync - //pub async fn get_request(&mut self, url: &str) -> (Value, StatusCode) { - //eprintln!("get_request: {}", url); - - //let mut app = - //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; - - //let req = test::TestRequest::get().uri(url).to_request(); - //let res = test::call_service(&mut app, req).await; - //let status_code = res.status(); - - //let body = test::read_body(res).await; - //let response = serde_json::from_slice(&body).unwrap_or_default(); - //(response, status_code) - //} - - //pub async fn post_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { //eprintln!("post_request_async: {}", url); @@ -177,20 +161,6 @@ impl Server { //(response, status_code) //} - //pub async fn delete_request(&mut self, url: &str) -> (Value, StatusCode) { - //eprintln!("delete_request: {}", url); - - //let mut app = - //test::init_service(meilisearch_http::create_app(&self.data, true).wrap(NormalizePath)).await; - - //let req = test::TestRequest::delete().uri(url).to_request(); - //let res = test::call_service(&mut app, req).await; - //let status_code = res.status(); - - //let body = test::read_body(res).await; - //let response = serde_json::from_slice(&body).unwrap_or_default(); - //(response, status_code) - //} //pub async fn delete_request_async(&mut self, url: &str) -> (Value, StatusCode) { //eprintln!("delete_request_async: {}", url); diff --git a/tests/common/service.rs b/tests/common/service.rs index 0ff1320df..b00552562 100644 --- a/tests/common/service.rs +++ b/tests/common/service.rs @@ -51,5 +51,18 @@ impl Service { let response = serde_json::from_slice(&body).unwrap_or_default(); (response, status_code) } + + pub async fn delete(&self, url: impl AsRef) -> (Value, StatusCode) { + let mut app = + test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; + + let req = test::TestRequest::delete().uri(url.as_ref()).to_request(); + let res = test::call_service(&mut app, req).await; + let status_code = res.status(); + + let body = test::read_body(res).await; + let response = serde_json::from_slice(&body).unwrap_or_default(); + (response, status_code) + } } diff --git a/tests/index/mod.rs b/tests/index/mod.rs index 2aefd99c2..253afcfc4 100644 --- a/tests/index/mod.rs +++ b/tests/index/mod.rs @@ -1,3 +1,4 @@ mod create_index; mod get_index; mod update_index; +mod delete_index; diff --git a/tests/integration.rs b/tests/integration.rs index 2b8dc5612..9d9ba64e3 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,3 +1,9 @@ mod common; mod search; mod index; + +// Tests are isolated by features in different modules to allow better readability, test +// targetability, and improved incremental compilation times. +// +// All the integration tests live in the same root module so only one test executable is generated, +// thus improving linking time. From b1226be2c870d11b61290f34bd0939c65c73d6ed Mon Sep 17 00:00:00 2001 From: mpostma Date: Thu, 18 Feb 2021 22:10:50 +0100 Subject: [PATCH 07/26] test document addition --- src/index_controller/updates.rs | 4 +++ tests/common/index.rs | 47 ++++++++++++++++++++++++++++++--- tests/common/service.rs | 1 + tests/integration.rs | 4 ++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/index_controller/updates.rs b/src/index_controller/updates.rs index b8f1e31f4..b15593b58 100644 --- a/src/index_controller/updates.rs +++ b/src/index_controller/updates.rs @@ -42,6 +42,7 @@ impl Pending { } #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Processed { pub success: N, pub processed_at: DateTime, @@ -56,6 +57,7 @@ impl Processed { } #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Processing { #[serde(flatten)] pub from: Pending, @@ -89,6 +91,7 @@ impl Processing { } #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Aborted { #[serde(flatten)] from: Pending, @@ -102,6 +105,7 @@ impl Aborted { } #[derive(Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] pub struct Failed { #[serde(flatten)] from: Processing, diff --git a/tests/common/index.rs b/tests/common/index.rs index 0b80f3fde..182f9e238 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -1,5 +1,8 @@ +use std::time::Duration; + use actix_web::http::StatusCode; use serde_json::{json, Value}; +use tokio::time::delay_for; use super::service::Service; @@ -14,10 +17,7 @@ impl Index<'_> { self.service.get(url).await } - pub async fn create<'a>( - &'a self, - primary_key: Option<&str>, - ) -> (Value, StatusCode) { + pub async fn create<'a>(&'a self, primary_key: Option<&str>) -> (Value, StatusCode) { let body = json!({ "uid": self.uid, "primaryKey": primary_key, @@ -38,4 +38,43 @@ impl Index<'_> { let url = format!("/indexes/{}", self.uid); self.service.delete(url).await } + + pub async fn add_documents( + &self, + documents: Value, + primary_key: Option<&str>, + ) -> (Value, StatusCode) { + let url = match primary_key { + Some(key) => format!("/indexes/{}/documents?primaryKey={}", self.uid, key), + None => format!("/indexes/{}/documents", self.uid), + }; + self.service.post(url, documents).await + } + + pub async fn wait_update_id(&self, update_id: u64) { + // try 10 times to get status, or panic to not wait forever + let url = format!("/indexes/{}/updates/{}", self.uid, update_id); + for _ in 0..10 { + let (response, status_code) = self.service.get(&url).await; + assert_eq!(status_code, 200); + + if response["status"] == "processed" || response["status"] == "failed" { + return; + } + + delay_for(Duration::from_secs(1)).await; + } + panic!("Timeout waiting for update id"); + } + + pub async fn get_update(&self, udpate_id: usize) -> (Value, StatusCode) { + let url = format!("/indexes/{}/updates/{}", self.uid, udpate_id); + self.service.get(url).await + } + + #[allow(dead_code)] + pub async fn list_updates(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/updates", self.uid); + self.service.get(url).await + } } diff --git a/tests/common/service.rs b/tests/common/service.rs index b00552562..8d19c4a49 100644 --- a/tests/common/service.rs +++ b/tests/common/service.rs @@ -64,5 +64,6 @@ impl Service { let response = serde_json::from_slice(&body).unwrap_or_default(); (response, status_code) } + } diff --git a/tests/integration.rs b/tests/integration.rs index 9d9ba64e3..34fbde4b6 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,6 +1,8 @@ mod common; -mod search; mod index; +mod search; +mod settings; +mod documents; // Tests are isolated by features in different modules to allow better readability, test // targetability, and improved incremental compilation times. From 556ba956b89de3069db89198d3ade95f509df625 Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:14:25 +0100 Subject: [PATCH 08/26] test get empty index list --- tests/common/server.rs | 433 +-------------------------------------- tests/index/get_index.rs | 9 + 2 files changed, 14 insertions(+), 428 deletions(-) diff --git a/tests/common/server.rs b/tests/common/server.rs index 30d6c40fd..630bb2791 100644 --- a/tests/common/server.rs +++ b/tests/common/server.rs @@ -1,5 +1,7 @@ use tempdir::TempDir; use byte_unit::{Byte, ByteUnit}; +use serde_json::Value; +use actix_web::http::StatusCode; use meilisearch_http::data::Data; use meilisearch_http::option::{Opt, IndexerOpts}; @@ -51,134 +53,6 @@ impl Server { } } - //pub async fn test_server() -> Self { - //let mut server = Self::new(); - - //let body = json!({ - //"uid": "test", - //"primaryKey": "id", - //}); - - //server.create_index(body).await; - - //let body = json!({ - ////"rankingRules": [ - ////"typo", - ////"words", - ////"proximity", - ////"attribute", - ////"wordsPosition", - ////"exactness", - ////], - //"searchableAttributes": [ - //"balance", - //"picture", - //"age", - //"color", - //"name", - //"gender", - //"email", - //"phone", - //"address", - //"about", - //"registered", - //"latitude", - //"longitude", - //"tags", - //], - //"displayedAttributes": [ - //"id", - //"isActive", - //"balance", - //"picture", - //"age", - //"color", - //"name", - //"gender", - //"email", - //"phone", - //"address", - //"about", - //"registered", - //"latitude", - //"longitude", - //"tags", - //], - //}); - - //server.update_all_settings(body).await; - - //let dataset = include_bytes!("../assets/test_set.json"); - - //let body: Value = serde_json::from_slice(dataset).unwrap(); - - //server.add_or_replace_multiple_documents(body).await; - //server - //} - - //pub fn data(&self) -> &Data { - //&self.data - //} - - //pub async fn wait_update_id(&mut self, update_id: u64) { - //// try 10 times to get status, or panic to not wait forever - //for _ in 0..10 { - //let (response, status_code) = self.get_update_status(update_id).await; - //assert_eq!(status_code, 200); - - //if response["status"] == "processed" || response["status"] == "failed" { - //// eprintln!("{:#?}", response); - //return; - //} - - //delay_for(Duration::from_secs(1)).await; - //} - //panic!("Timeout waiting for update id"); - //} - - // Global Http request GET/POST/DELETE async or sync - - //pub async fn post_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { - //eprintln!("post_request_async: {}", url); - - //let (response, status_code) = self.post_request(url, body).await; - //eprintln!("response: {}", response); - //assert!(response["updateId"].as_u64().is_some()); - //self.wait_update_id(response["updateId"].as_u64().unwrap()) - //.await; - //(response, status_code) - //} - - - //pub async fn put_request_async(&mut self, url: &str, body: Value) -> (Value, StatusCode) { - //eprintln!("put_request_async: {}", url); - - //let (response, status_code) = self.put_request(url, body).await; - //assert!(response["updateId"].as_u64().is_some()); - //assert_eq!(status_code, 202); - //self.wait_update_id(response["updateId"].as_u64().unwrap()) - //.await; - //(response, status_code) - //} - - - //pub async fn delete_request_async(&mut self, url: &str) -> (Value, StatusCode) { - //eprintln!("delete_request_async: {}", url); - - //let (response, status_code) = self.delete_request(url).await; - //assert!(response["updateId"].as_u64().is_some()); - //assert_eq!(status_code, 202); - //self.wait_update_id(response["updateId"].as_u64().unwrap()) - //.await; - //(response, status_code) - //} - - // All Routes - - //pub async fn list_indexes(&mut self) -> (Value, StatusCode) { - //self.get_request("/indexes").await - //} - /// Returns a view to an index. There is no guarantee that the index exists. pub fn index<'a>(&'a self, uid: impl AsRef) -> Index<'a> { Index { @@ -186,305 +60,8 @@ impl Server { service: &self.service, } } - //pub async fn search_multi_index(&mut self, query: &str) -> (Value, StatusCode) { - //let url = format!("/indexes/search?{}", query); - //self.get_request(&url).await - //} - //pub async fn get_index(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_index(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}", self.uid); - //self.put_request(&url, body).await - //} - - //pub async fn delete_index(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}", self.uid); - //self.delete_request(&url).await - //} - - //pub async fn search_get(&mut self, query: &str) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/search?{}", self.uid, query); - //self.get_request(&url).await - //} - - //pub async fn search_post(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/search", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn get_all_updates_status(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/updates", self.uid); - //self.get_request(&url).await - //} - - //pub async fn get_update_status(&mut self, update_id: u64) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/updates/{}", self.uid, update_id); - //self.get_request(&url).await - //} - - //pub async fn get_all_documents(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/documents", self.uid); - //self.get_request(&url).await - //} - - //pub async fn add_or_replace_multiple_documents(&mut self, body: Value) { - //let url = format!("/indexes/{}/documents", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn add_or_replace_multiple_documents_sync( - //&mut self, - //body: Value, - //) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/documents", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn add_or_update_multiple_documents(&mut self, body: Value) { - //let url = format!("/indexes/{}/documents", self.uid); - //self.put_request_async(&url, body).await; - //} - - //pub async fn clear_all_documents(&mut self) { - //let url = format!("/indexes/{}/documents", self.uid); - //self.delete_request_async(&url).await; - //} - - //pub async fn get_document(&mut self, document_id: impl ToString) -> (Value, StatusCode) { - //let url = format!( - //"/indexes/{}/documents/{}", - //self.uid, - //document_id.to_string() - //); - //self.get_request(&url).await - //} - - //pub async fn delete_document(&mut self, document_id: impl ToString) -> (Value, StatusCode) { - //let url = format!( - //"/indexes/{}/documents/{}", - //self.uid, - //document_id.to_string() - //); - //self.delete_request_async(&url).await - //} - - //pub async fn delete_multiple_documents(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/documents/delete-batch", self.uid); - //self.post_request_async(&url, body).await - //} - - //pub async fn get_all_settings(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_all_settings(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_all_settings_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_all_settings(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_ranking_rules(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_ranking_rules(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_ranking_rules_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_ranking_rules(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/ranking-rules", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_distinct_attribute(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_distinct_attribute(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_distinct_attribute_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_distinct_attribute(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/distinct-attribute", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_primary_key(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/primary_key", self.uid); - //self.get_request(&url).await - //} - - //pub async fn get_searchable_attributes(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_searchable_attributes(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_searchable_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_searchable_attributes(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/searchable-attributes", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_displayed_attributes(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_displayed_attributes(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_displayed_attributes_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_displayed_attributes(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/displayed-attributes", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_attributes_for_faceting(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_attributes_for_faceting(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_attributes_for_faceting_sync( - //&mut self, - //body: Value, - //) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_attributes_for_faceting(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/attributes-for-faceting", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_synonyms(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/synonyms", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_synonyms(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/synonyms", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_synonyms_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/synonyms", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_synonyms(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/synonyms", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_stop_words(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/stop-words", self.uid); - //self.get_request(&url).await - //} - - //pub async fn update_stop_words(&mut self, body: Value) { - //let url = format!("/indexes/{}/settings/stop-words", self.uid); - //self.post_request_async(&url, body).await; - //} - - //pub async fn update_stop_words_sync(&mut self, body: Value) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/stop-words", self.uid); - //self.post_request(&url, body).await - //} - - //pub async fn delete_stop_words(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/settings/stop-words", self.uid); - //self.delete_request_async(&url).await - //} - - //pub async fn get_index_stats(&mut self) -> (Value, StatusCode) { - //let url = format!("/indexes/{}/stats", self.uid); - //self.get_request(&url).await - //} - - //pub async fn list_keys(&mut self) -> (Value, StatusCode) { - //self.get_request("/keys").await - //} - - //pub async fn get_health(&mut self) -> (Value, StatusCode) { - //self.get_request("/health").await - //} - - //pub async fn update_health(&mut self, body: Value) -> (Value, StatusCode) { - //self.put_request("/health", body).await - //} - - //pub async fn get_version(&mut self) -> (Value, StatusCode) { - //self.get_request("/version").await - //} - - //pub async fn get_sys_info(&mut self) -> (Value, StatusCode) { - //self.get_request("/sys-info").await - //} - - //pub async fn get_sys_info_pretty(&mut self) -> (Value, StatusCode) { - //self.get_request("/sys-info/pretty").await - //} - - //pub async fn trigger_dump(&self) -> (Value, StatusCode) { - //self.post_request("/dumps", Value::Null).await - //} - - //pub async fn get_dump_status(&mut self, dump_uid: &str) -> (Value, StatusCode) { - //let url = format!("/dumps/{}/status", dump_uid); - //self.get_request(&url).await - //} - - //pub async fn trigger_dump_importation(&mut self, dump_uid: &str) -> (Value, StatusCode) { - //let url = format!("/dumps/{}/import", dump_uid); - //self.get_request(&url).await - //} + pub async fn list_indexes(&self) -> (Value, StatusCode) { + self.service.get("/indexes").await + } } diff --git a/tests/index/get_index.rs b/tests/index/get_index.rs index 8b0f27441..c69f4b2a8 100644 --- a/tests/index/get_index.rs +++ b/tests/index/get_index.rs @@ -32,3 +32,12 @@ async fn get_unexisting_index() { assert_eq!(code, 400); } + +#[actix_rt::test] +async fn no_index_return_empty_list() { + let server = Server::new().await; + let (response, code) = server.list_indexes().await; + assert_eq!(code, 200); + assert!(response.is_array()); + assert!(response.as_array().unwrap().is_empty()); +} From 2bb695d60f55ddbc9095c208377caf8f60ed315b Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:23:58 +0100 Subject: [PATCH 09/26] test list all indexes --- tests/index/get_index.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/index/get_index.rs b/tests/index/get_index.rs index c69f4b2a8..3b8390551 100644 --- a/tests/index/get_index.rs +++ b/tests/index/get_index.rs @@ -41,3 +41,19 @@ async fn no_index_return_empty_list() { assert!(response.is_array()); assert!(response.as_array().unwrap().is_empty()); } + +#[actix_rt::test] +async fn list_multiple_indexes() { + let server = Server::new().await; + server.index("test").create(None).await; + server.index("test1").create(Some("key")).await; + + let (response, code) = server.list_indexes().await; + assert_eq!(code, 200); + assert!(response.is_array()); + let arr = response.as_array().unwrap(); + assert_eq!(arr.len(), 2); + assert!(arr.iter().find(|entry| entry["uid"] == "test" && entry["primaryKey"] == Value::Null).is_some()); + assert!(arr.iter().find(|entry| entry["uid"] == "test1" && entry["primaryKey"] == "key").is_some()); + +} From 5270cc0eae1d4f57b8775668fbba3b3ce3afc408 Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:26:42 +0100 Subject: [PATCH 10/26] test update index --- tests/index/update_index.rs | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/index/update_index.rs diff --git a/tests/index/update_index.rs b/tests/index/update_index.rs new file mode 100644 index 000000000..0078ad892 --- /dev/null +++ b/tests/index/update_index.rs @@ -0,0 +1,64 @@ +use crate::common::Server; +use chrono::DateTime; + +#[actix_rt::test] +async fn update_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + let (_, code) = index.create(None).await; + + assert_eq!(code, 200); + + let (response, code) = index.update(Some("primary")).await; + + assert_eq!(code, 200); + assert_eq!(response["uid"], "test"); + assert!(response.get("uuid").is_some()); + assert!(response.get("createdAt").is_some()); + assert!(response.get("updatedAt").is_some()); + + let created_at = DateTime::parse_from_rfc3339(response["createdAt"].as_str().unwrap()).unwrap(); + let updated_at = DateTime::parse_from_rfc3339(response["updatedAt"].as_str().unwrap()).unwrap(); + assert!(created_at < updated_at); + + assert_eq!(response["primaryKey"], "primary"); + assert_eq!(response.as_object().unwrap().len(), 5); +} + +#[actix_rt::test] +async fn update_nothing() { + let server = Server::new().await; + let index = server.index("test"); + let (response, code) = index.create(None).await; + + assert_eq!(code, 200); + + let (update, code) = index.update(None).await; + + assert_eq!(code, 200); + assert_eq!(response, update); +} + +// TODO: partial test since we are testing error, amd error is not yet fully implemented in +// transplant +#[actix_rt::test] +async fn update_existing_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.create(Some("primary")).await; + + assert_eq!(code, 200); + + let (_update, code) = index.update(Some("primary2")).await; + + assert_eq!(code, 400); +} + +// TODO: partial test since we are testing error, amd error is not yet fully implemented in +// transplant +#[actix_rt::test] +async fn test_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").update(None).await; + assert_eq!(code, 400); +} From ba2cfcc72d3f56e7221daeae005905f8b4c3d4ec Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:26:56 +0100 Subject: [PATCH 11/26] test delete index --- tests/index/delete_index.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/index/delete_index.rs diff --git a/tests/index/delete_index.rs b/tests/index/delete_index.rs new file mode 100644 index 000000000..39e79daaf --- /dev/null +++ b/tests/index/delete_index.rs @@ -0,0 +1,25 @@ +use crate::common::Server; + +#[actix_rt::test] +async fn create_and_delete_index() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.create(None).await; + + assert_eq!(code, 200); + + let (_response, code) = index.delete().await; + + assert_eq!(code, 200); + + assert_eq!(index.get().await.1, 400); +} + +#[actix_rt::test] +async fn delete_unexisting_index() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.delete().await; + + assert_eq!(code, 400); +} From ec9dcd3285de83a7e562dac1c7ad0ab3770db8de Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:43:32 +0100 Subject: [PATCH 12/26] test get add documents --- tests/documents/add_documents.rs | 210 +++++++++++++++++++++++++++++++ tests/documents/get_documents.rs | 24 ++++ tests/documents/mod.rs | 2 + 3 files changed, 236 insertions(+) create mode 100644 tests/documents/add_documents.rs create mode 100644 tests/documents/get_documents.rs create mode 100644 tests/documents/mod.rs diff --git a/tests/documents/add_documents.rs b/tests/documents/add_documents.rs new file mode 100644 index 000000000..c17828641 --- /dev/null +++ b/tests/documents/add_documents.rs @@ -0,0 +1,210 @@ +use serde_json::{json, Value}; +use chrono::DateTime; + +use crate::common::Server; + +#[actix_rt::test] +async fn add_documents_no_index_creation() { + let server = Server::new().await; + let index = server.index("test"); + + let documents = json!([ + { + "id": 1, + "content": "foo", + } + ]); + + let (response, code) = index.add_documents(documents, None).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "pending"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["meta"]["type"], "DocumentsAddition"); + assert_eq!(response["meta"]["format"], "Json"); + assert_eq!(response["meta"]["primaryKey"], Value::Null); + assert!(response.get("enqueuedAt").is_some()); + + index.wait_update_id(0).await; + + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + println!("response: {}", response); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 1); + + let processed_at = DateTime::parse_from_rfc3339(response["processedAt"].as_str().unwrap()).unwrap(); + let enqueued_at = DateTime::parse_from_rfc3339(response["enqueuedAt"].as_str().unwrap()).unwrap(); + let started_processing_at = DateTime::parse_from_rfc3339(response["startedProcessingAt"].as_str().unwrap()).unwrap(); + assert!(processed_at > started_processing_at); + assert!(started_processing_at > enqueued_at); + + // index was created, and primary key was infered. + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], "id"); +} + +#[actix_rt::test] +async fn document_addition_with_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + + let documents = json!([ + { + "primary": 1, + "content": "foo", + } + ]); + let (_response, code) = index.add_documents(documents, Some("primary")).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; + + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 1); + + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], "primary"); +} + +#[actix_rt::test] +async fn add_documents_with_primary_key_and_primary_key_already_exists() { + let server = Server::new().await; + let index = server.index("test"); + + index.create(Some("primary")).await; + let documents = json!([ + { + "id": 1, + "content": "foo", + } + ]); + + let (_response, code) = index.add_documents(documents, Some("id")).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; + + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 1); + + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], "primary"); +} + +#[actix_rt::test] +async fn replace_document() { + let server = Server::new().await; + let index = server.index("test"); + + let documents = json!([ + { + "doc_id": 1, + "content": "foo", + } + ]); + + let (_response, code) = index.add_documents(documents, None).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; + + let documents = json!([ + { + "doc_id": 1, + "other": "bar", + } + ]); + + let (_response, code) = index.add_documents(documents, None).await; + assert_eq!(code, 200); + + index.wait_update_id(1).await; + + let (response, code) = index.get_update(1).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + + let (response, code) = index.get_document(1, None).await; + assert_eq!(code, 200); + assert_eq!(response.to_string(), r##"{"doc_id":1,"other":"bar"}"##); +} + +// test broken, see issue milli#92 +#[actix_rt::test] +#[ignore] +async fn add_no_documents() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.add_documents(json!([]), None).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 0); + + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], Value::Null); +} + +#[actix_rt::test] +async fn update_document() { + let server = Server::new().await; + let index = server.index("test"); + + let documents = json!([ + { + "doc_id": 1, + "content": "foo", + } + ]); + + let (_response, code) = index.add_documents(documents, None).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; + + let documents = json!([ + { + "doc_id": 1, + "other": "bar", + } + ]); + + let (_response, code) = index.update_documents(documents, None).await; + assert_eq!(code, 200); + + index.wait_update_id(1).await; + + let (response, code) = index.get_update(1).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + + let (response, code) = index.get_document(1, None).await; + assert_eq!(code, 200); + assert_eq!(response.to_string(), r##"{"doc_id":1,"content":"foo","other":"bar"}"##); +} + +#[actix_rt::test] +async fn add_larger_dataset() { + let server = Server::new().await; + let index = server.index("test"); + let update_id = index.load_test_set().await; + let (response, code) = index.get_update(update_id).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 77); +} diff --git a/tests/documents/get_documents.rs b/tests/documents/get_documents.rs new file mode 100644 index 000000000..40748b555 --- /dev/null +++ b/tests/documents/get_documents.rs @@ -0,0 +1,24 @@ +use crate::common::Server; +use crate::common::GetAllDocumentsOptions; + +// TODO: partial test since we are testing error, amd error is not yet fully implemented in +// transplant +#[actix_rt::test] +async fn get_unexisting_index_single_document() { + let server = Server::new().await; + let (_response, code) = server + .index("test") + .get_document(1, None) + .await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn get_unexisting_index_all_documents() { + let server = Server::new().await; + let (_response, code) = server + .index("test") + .get_all_documents(GetAllDocumentsOptions::default()) + .await; + assert_eq!(code, 400); +} diff --git a/tests/documents/mod.rs b/tests/documents/mod.rs new file mode 100644 index 000000000..69c73e37a --- /dev/null +++ b/tests/documents/mod.rs @@ -0,0 +1,2 @@ +mod add_documents; +mod get_documents; From 27a7238d3fe8848de8123fc28fe3ce3df31b2811 Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:46:45 +0100 Subject: [PATCH 13/26] test list no documents --- tests/documents/get_documents.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/documents/get_documents.rs b/tests/documents/get_documents.rs index 40748b555..069d5fd90 100644 --- a/tests/documents/get_documents.rs +++ b/tests/documents/get_documents.rs @@ -22,3 +22,15 @@ async fn get_unexisting_index_all_documents() { .await; assert_eq!(code, 400); } + +#[actix_rt::test] +async fn get_no_documents() { + let server = Server::new().await; + let index = server.index("test"); + let (_, code) = index.create(None).await; + assert_eq!(code, 200); + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + assert!(response.as_array().unwrap().is_empty()); +} From b8b8cc13127240dcb8de942d4dae6da71fbb05c8 Mon Sep 17 00:00:00 2001 From: mpostma Date: Fri, 19 Feb 2021 19:55:00 +0100 Subject: [PATCH 14/26] get all documents, no options --- tests/common/index.rs | 34 +++++++++++++++++++++++++++++++- tests/documents/get_documents.rs | 12 +++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tests/common/index.rs b/tests/common/index.rs index 182f9e238..6e3dc2603 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -17,6 +17,15 @@ impl Index<'_> { self.service.get(url).await } + pub async fn load_test_set(&self) -> u64 { + let url = format!("/indexes/{}/documents", self.uid); + let (response, code) = self.service.post_str(url, include_str!("../assets/test_set.json")).await; + assert_eq!(code, 200); + let update_id = response["updateId"].as_i64().unwrap(); + self.wait_update_id(update_id as u64).await; + update_id as u64 + } + pub async fn create<'a>(&'a self, primary_key: Option<&str>) -> (Value, StatusCode) { let body = json!({ "uid": self.uid, @@ -51,6 +60,14 @@ impl Index<'_> { self.service.post(url, documents).await } + pub async fn update_documents(&self, documents: Value, primary_key: Option<&str>) -> (Value, StatusCode) { + let url = match primary_key { + Some(key) => format!("/indexes/{}/documents?primaryKey={}", self.uid, key), + None => format!("/indexes/{}/documents", self.uid), + }; + self.service.put(url, documents).await + } + pub async fn wait_update_id(&self, update_id: u64) { // try 10 times to get status, or panic to not wait forever let url = format!("/indexes/{}/updates/{}", self.uid, update_id); @@ -67,7 +84,7 @@ impl Index<'_> { panic!("Timeout waiting for update id"); } - pub async fn get_update(&self, udpate_id: usize) -> (Value, StatusCode) { + pub async fn get_update(&self, udpate_id: u64) -> (Value, StatusCode) { let url = format!("/indexes/{}/updates/{}", self.uid, udpate_id); self.service.get(url).await } @@ -77,4 +94,19 @@ impl Index<'_> { let url = format!("/indexes/{}/updates", self.uid); self.service.get(url).await } + + pub async fn get_document(&self, id: u64, _options: Option) -> (Value, StatusCode) { + let url = format!("/indexes/{}/documents/{}", self.uid, id); + self.service.get(url).await + } + + pub async fn get_all_documents(&self, _options: GetAllDocumentsOptions) -> (Value, StatusCode) { + let url = format!("/indexes/{}/documents", self.uid); + self.service.get(url).await + } } + +pub struct GetDocumentOptions; + +#[derive(Debug, Default)] +pub struct GetAllDocumentsOptions; diff --git a/tests/documents/get_documents.rs b/tests/documents/get_documents.rs index 069d5fd90..f5afc29e2 100644 --- a/tests/documents/get_documents.rs +++ b/tests/documents/get_documents.rs @@ -34,3 +34,15 @@ async fn get_no_documents() { assert_eq!(code, 200); assert!(response.as_array().unwrap().is_empty()); } + +#[actix_rt::test] +async fn get_all_documents_no_options() { + let server = Server::new().await; + let index = server.index("test"); + index.load_test_set().await; + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + let arr = response.as_array().unwrap(); + assert_eq!(arr.len(), 20); +} From 097cae90a7455b486808cb808f0be5d0f0157949 Mon Sep 17 00:00:00 2001 From: mpostma Date: Mon, 22 Feb 2021 14:23:17 +0100 Subject: [PATCH 15/26] tests get documents limit, offset, attr to retrieve --- tests/common/index.rs | 22 +++++++++-- tests/common/mod.rs | 1 + tests/common/service.rs | 20 +++++++++- tests/documents/get_documents.rs | 66 ++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/tests/common/index.rs b/tests/common/index.rs index 6e3dc2603..ed5e533a5 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -100,8 +100,20 @@ impl Index<'_> { self.service.get(url).await } - pub async fn get_all_documents(&self, _options: GetAllDocumentsOptions) -> (Value, StatusCode) { - let url = format!("/indexes/{}/documents", self.uid); + pub async fn get_all_documents(&self, options: GetAllDocumentsOptions) -> (Value, StatusCode) { + let mut url = format!("/indexes/{}/documents?", self.uid); + if let Some(limit) = options.limit { + url.push_str(&format!("limit={}&", limit)); + } + + if let Some(offset) = options.offset { + url.push_str(&format!("offset={}&", offset)); + } + + if let Some(attributes_to_retrieve) = options.attributes_to_retrieve { + url.push_str(&format!("attributesToRetrieve={}&", attributes_to_retrieve.join(","))); + } + self.service.get(url).await } } @@ -109,4 +121,8 @@ impl Index<'_> { pub struct GetDocumentOptions; #[derive(Debug, Default)] -pub struct GetAllDocumentsOptions; +pub struct GetAllDocumentsOptions { + pub limit: Option, + pub offset: Option, + pub attributes_to_retrieve: Option>, +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 36c7e8190..fd461e61c 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -3,6 +3,7 @@ mod server; mod service; pub use server::Server; +pub use index::{GetDocumentOptions, GetAllDocumentsOptions}; /// Performs a search test on both post and get routes #[macro_export] diff --git a/tests/common/service.rs b/tests/common/service.rs index 8d19c4a49..8e797c00d 100644 --- a/tests/common/service.rs +++ b/tests/common/service.rs @@ -23,6 +23,24 @@ impl Service { (response, status_code) } + /// Send a test post request from a text body, with a `content-type:application/json` header. + pub async fn post_str(&self, url: impl AsRef, body: impl AsRef) -> (Value, StatusCode) { + let mut app = + test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; + + let req = test::TestRequest::post() + .uri(url.as_ref()) + .set_payload(body.as_ref().to_string()) + .header("content-type", "application/json") + .to_request(); + let res = test::call_service(&mut app, req).await; + let status_code = res.status(); + + let body = test::read_body(res).await; + let response = serde_json::from_slice(&body).unwrap_or_default(); + (response, status_code) + } + pub async fn get(&self, url: impl AsRef) -> (Value, StatusCode) { let mut app = test::init_service(meilisearch_http::create_app(&self.0, true).wrap(NormalizePath)).await; @@ -64,6 +82,4 @@ impl Service { let response = serde_json::from_slice(&body).unwrap_or_default(); (response, status_code) } - } - diff --git a/tests/documents/get_documents.rs b/tests/documents/get_documents.rs index f5afc29e2..3b4581096 100644 --- a/tests/documents/get_documents.rs +++ b/tests/documents/get_documents.rs @@ -45,4 +45,70 @@ async fn get_all_documents_no_options() { assert_eq!(code, 200); let arr = response.as_array().unwrap(); assert_eq!(arr.len(), 20); + let first = serde_json::json!({ + "id":0, + "isActive":false, + "balance":"$2,668.55", + "picture":"http://placehold.it/32x32", + "age":36, + "color":"Green", + "name":"Lucas Hess", + "gender":"male", + "email":"lucashess@chorizon.com", + "phone":"+1 (998) 478-2597", + "address":"412 Losee Terrace, Blairstown, Georgia, 2825", + "about":"Mollit ad in exercitation quis. Anim est ut consequat fugiat duis magna aliquip velit nisi. Commodo eiusmod est consequat proident consectetur aliqua enim fugiat. Aliqua adipisicing laboris elit proident enim veniam laboris mollit. Incididunt fugiat minim ad nostrud deserunt tempor in. Id irure officia labore qui est labore nulla nisi. Magna sit quis tempor esse consectetur amet labore duis aliqua consequat.\r\n", + "registered":"2016-06-21T09:30:25 -02:00", + "latitude":-44.174957, + "longitude":-145.725388, + "tags":["bug" + ,"bug"]}); + assert_eq!(first, arr[0]); +} + +#[actix_rt::test] +async fn test_get_all_documents_limit() { + let server = Server::new().await; + let index = server.index("test"); + index.load_test_set().await; + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { limit: Some(5), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 5); + assert_eq!(response.as_array().unwrap()[0]["id"], 0); +} + +#[actix_rt::test] +async fn test_get_all_documents_offset() { + let server = Server::new().await; + let index = server.index("test"); + index.load_test_set().await; + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { offset: Some(5), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 20); + assert_eq!(response.as_array().unwrap()[0]["id"], 13); +} + +#[actix_rt::test] +async fn test_get_all_documents_attributes_to_retrieve() { + let server = Server::new().await; + let index = server.index("test"); + index.load_test_set().await; + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { attributes_to_retrieve: Some(vec!["name"]), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 20); + assert_eq!(response.as_array().unwrap()[0].as_object().unwrap().keys().count(), 1); + assert!(response.as_array().unwrap()[0].as_object().unwrap().get("name").is_some()); + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { attributes_to_retrieve: Some(vec![]), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 20); + assert_eq!(response.as_array().unwrap()[0].as_object().unwrap().keys().count(), 0); + + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { attributes_to_retrieve: Some(vec!["name", "tags"]), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 20); + assert_eq!(response.as_array().unwrap()[0].as_object().unwrap().keys().count(), 2); } From ded6483173ff052589831f44d39497dacfcbcf75 Mon Sep 17 00:00:00 2001 From: mpostma Date: Mon, 22 Feb 2021 14:32:48 +0100 Subject: [PATCH 16/26] tests get one document --- tests/documents/get_documents.rs | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/documents/get_documents.rs b/tests/documents/get_documents.rs index 3b4581096..5affb8a7a 100644 --- a/tests/documents/get_documents.rs +++ b/tests/documents/get_documents.rs @@ -13,6 +13,41 @@ async fn get_unexisting_index_single_document() { assert_eq!(code, 400); } +#[actix_rt::test] +async fn get_unexisting_document() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let (_response, code) = index + .get_document(1, None) + .await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn get_document() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let documents = serde_json::json!([ + { + "id": 0, + "content": "foobar", + } + ]); + let (_, code) = index.add_documents(documents, None).await; + assert_eq!(code, 200); + index.wait_update_id(0).await; + let (response, code) = index + .get_document(0, None) + .await; + assert_eq!(code, 200); + assert_eq!(response, serde_json::json!( { + "id": 0, + "content": "foobar", + })); +} + #[actix_rt::test] async fn get_unexisting_index_all_documents() { let server = Server::new().await; From 4bca26298ef615594c87049b75286ada871412af Mon Sep 17 00:00:00 2001 From: mpostma Date: Mon, 22 Feb 2021 14:55:40 +0100 Subject: [PATCH 17/26] test add document bad primary key --- tests/documents/add_documents.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/documents/add_documents.rs b/tests/documents/add_documents.rs index c17828641..568a3117e 100644 --- a/tests/documents/add_documents.rs +++ b/tests/documents/add_documents.rs @@ -208,3 +208,21 @@ async fn add_larger_dataset() { assert_eq!(response["status"], "processed"); assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 77); } + +#[actix_rt::test] +async fn add_documents_bad_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + index.create(Some("docid")).await; + let documents = json!([ + { + "docid": "foo & bar", + "content": "foobar" + } + ]); + index.add_documents(documents, None).await; + index.wait_update_id(0).await; + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "failed"); +} From c95bf0cdf02c46bf54c0e468095e553a817a74c8 Mon Sep 17 00:00:00 2001 From: mpostma Date: Mon, 22 Feb 2021 15:13:10 +0100 Subject: [PATCH 18/26] test badly formated primary key --- tests/documents/add_documents.rs | 94 +++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/tests/documents/add_documents.rs b/tests/documents/add_documents.rs index 568a3117e..70d6aab68 100644 --- a/tests/documents/add_documents.rs +++ b/tests/documents/add_documents.rs @@ -1,7 +1,7 @@ use serde_json::{json, Value}; use chrono::DateTime; -use crate::common::Server; +use crate::common::{Server, GetAllDocumentsOptions}; #[actix_rt::test] async fn add_documents_no_index_creation() { @@ -56,8 +56,33 @@ async fn document_addition_with_primary_key() { "content": "foo", } ]); - let (_response, code) = index.add_documents(documents, Some("primary")).await; + let (_response, code) = index.add_documents(documents, Some("primary")).await; assert_eq!(code, 200); + + index.wait_update_id(0).await; + + let (response, code) = index.get_update(0).await; assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 1); + + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], "primary"); +} + +#[actix_rt::test] +async fn document_update_with_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + + let documents = json!([ + { + "primary": 1, + "content": "foo", + } + ]); + let (_response, code) = index.update_documents(documents, Some("primary")).await; assert_eq!(code, 200); index.wait_update_id(0).await; @@ -101,6 +126,34 @@ async fn add_documents_with_primary_key_and_primary_key_already_exists() { assert_eq!(response["primaryKey"], "primary"); } +#[actix_rt::test] +async fn update_documents_with_primary_key_and_primary_key_already_exists() { + let server = Server::new().await; + let index = server.index("test"); + + index.create(Some("primary")).await; + let documents = json!([ + { + "id": 1, + "content": "foo", + } + ]); + + let (_response, code) = index.update_documents(documents, Some("id")).await; + assert_eq!(code, 200); + + index.wait_update_id(0).await; +let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["updateId"], 0); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 1); + + let (response, code) = index.get().await; + assert_eq!(code, 200); + assert_eq!(response["primaryKey"], "primary"); +} + #[actix_rt::test] async fn replace_document() { let server = Server::new().await; @@ -207,6 +260,25 @@ async fn add_larger_dataset() { assert_eq!(code, 200); assert_eq!(response["status"], "processed"); assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 77); + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { limit: Some(1000), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 77); +} + +#[actix_rt::test] +async fn update_larger_dataset() { + let server = Server::new().await; + let index = server.index("test"); + let documents = serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(); + index.update_documents(documents, None).await; + index.wait_update_id(0).await; + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "processed"); + assert_eq!(response["success"]["DocumentsAddition"]["nb_documents"], 77); + let (response, code) = index.get_all_documents(GetAllDocumentsOptions { limit: Some(1000), ..Default::default() }).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 77); } #[actix_rt::test] @@ -226,3 +298,21 @@ async fn add_documents_bad_primary_key() { assert_eq!(code, 200); assert_eq!(response["status"], "failed"); } + +#[actix_rt::test] +async fn update_documents_bad_primary_key() { + let server = Server::new().await; + let index = server.index("test"); + index.create(Some("docid")).await; + let documents = json!([ + { + "docid": "foo & bar", + "content": "foobar" + } + ]); + index.update_documents(documents, None).await; + index.wait_update_id(0).await; + let (response, code) = index.get_update(0).await; + assert_eq!(code, 200); + assert_eq!(response["status"], "failed"); +} From d3758b6f76d16dd8d0a506edf8a5a6a4a0949bc6 Mon Sep 17 00:00:00 2001 From: mpostma Date: Mon, 22 Feb 2021 16:03:17 +0100 Subject: [PATCH 19/26] test delete documents --- tests/common/index.rs | 14 +++++- tests/documents/delete_documents.rs | 72 +++++++++++++++++++++++++++++ tests/documents/mod.rs | 1 + 3 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 tests/documents/delete_documents.rs diff --git a/tests/common/index.rs b/tests/common/index.rs index ed5e533a5..8afe78a35 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -68,7 +68,7 @@ impl Index<'_> { self.service.put(url, documents).await } - pub async fn wait_update_id(&self, update_id: u64) { + pub async fn wait_update_id(&self, update_id: u64) -> Value { // try 10 times to get status, or panic to not wait forever let url = format!("/indexes/{}/updates/{}", self.uid, update_id); for _ in 0..10 { @@ -76,7 +76,7 @@ impl Index<'_> { assert_eq!(status_code, 200); if response["status"] == "processed" || response["status"] == "failed" { - return; + return response; } delay_for(Duration::from_secs(1)).await; @@ -116,6 +116,16 @@ impl Index<'_> { self.service.get(url).await } + + pub async fn delete_document(&self, id: u64) -> (Value, StatusCode) { + let url = format!("/indexes/{}/documents/{}", self.uid, id); + self.service.delete(url).await + } + + pub async fn clear_all_documents(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/documents", self.uid); + self.service.delete(url).await + } } pub struct GetDocumentOptions; diff --git a/tests/documents/delete_documents.rs b/tests/documents/delete_documents.rs new file mode 100644 index 000000000..149319308 --- /dev/null +++ b/tests/documents/delete_documents.rs @@ -0,0 +1,72 @@ +use serde_json::json; + +use crate::common::{Server, GetAllDocumentsOptions}; + +#[actix_rt::test] +async fn delete_one_document_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").delete_document(0).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn delete_one_unexisting_document() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let (_response, code) = index.delete_document(0).await; + assert_eq!(code, 200); + let update = index.wait_update_id(0).await; + assert_eq!(update["status"], "processed"); +} + +#[actix_rt::test] +async fn delete_one_document() { + let server = Server::new().await; + let index = server.index("test"); + index.add_documents(json!([{ "id": 0, "content": "foobar" }]), None).await; + index.wait_update_id(0).await; + let (_response, code) = server.index("test").delete_document(0).await; + assert_eq!(code, 200); + + let (_response, code) = index.get_document(0, None).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn clear_all_documents_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").clear_all_documents().await; + assert_eq!(code, 400); + +} + +#[actix_rt::test] +async fn clear_all_documents() { + let server = Server::new().await; + let index = server.index("test"); + index.add_documents(json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }]), None).await; + index.wait_update_id(0).await; + let (_response, code) = index.clear_all_documents().await; + assert_eq!(code, 200); + + let _update = index.wait_update_id(0).await; + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + assert!(response.as_array().unwrap().is_empty()); +} + +#[actix_rt::test] +async fn clear_all_documents_empty_index() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + + let (_response, code) = index.clear_all_documents().await; + assert_eq!(code, 200); + + let _update = index.wait_update_id(0).await; + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + assert!(response.as_array().unwrap().is_empty()); +} diff --git a/tests/documents/mod.rs b/tests/documents/mod.rs index 69c73e37a..ea0e39c69 100644 --- a/tests/documents/mod.rs +++ b/tests/documents/mod.rs @@ -1,2 +1,3 @@ mod add_documents; mod get_documents; +mod delete_documents; From 0a3e946726e0aa11b05c7399ddacb421ef1bd020 Mon Sep 17 00:00:00 2001 From: mpostma Date: Tue, 23 Feb 2021 14:13:43 +0100 Subject: [PATCH 20/26] test delete batches --- src/option.rs | 2 +- tests/common/index.rs | 5 ++++ tests/common/server.rs | 4 +++ tests/documents/delete_documents.rs | 42 ++++++++++++++++++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/option.rs b/src/option.rs index c88110ccd..0a1d494de 100644 --- a/src/option.rs +++ b/src/option.rs @@ -103,8 +103,8 @@ pub struct Opt { pub sentry_dsn: String, /// Disable Sentry error reporting. - #[cfg(all(not(debug_assertions), feature = "sentry"))] #[structopt(long, env = "MEILI_NO_SENTRY")] + #[cfg(all(not(debug_assertions), feature = "sentry"))] pub no_sentry: bool, /// This environment variable must be set to `production` if you are running in production. diff --git a/tests/common/index.rs b/tests/common/index.rs index 8afe78a35..a50f8e6a3 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -126,6 +126,11 @@ impl Index<'_> { let url = format!("/indexes/{}/documents", self.uid); self.service.delete(url).await } + + pub async fn delete_batch(&self, ids: Vec) -> (Value, StatusCode) { + let url = format!("/indexes/{}/documents/delete-batch", self.uid); + self.service.post(url, serde_json::to_value(&ids).unwrap()).await + } } pub struct GetDocumentOptions; diff --git a/tests/common/server.rs b/tests/common/server.rs index 630bb2791..de32a2045 100644 --- a/tests/common/server.rs +++ b/tests/common/server.rs @@ -43,6 +43,10 @@ impl Server { snapshot_interval_sec: None, import_dump: None, indexer_options: IndexerOpts::default(), + #[cfg(all(not(debug_assertions), feature = "sentry"))] + sentry_dsn: String::from(""), + #[cfg(all(not(debug_assertions), feature = "sentry"))] + no_sentry: true, }; let data = Data::new(opt).unwrap(); diff --git a/tests/documents/delete_documents.rs b/tests/documents/delete_documents.rs index 149319308..3dba7e6fd 100644 --- a/tests/documents/delete_documents.rs +++ b/tests/documents/delete_documents.rs @@ -28,6 +28,7 @@ async fn delete_one_document() { index.wait_update_id(0).await; let (_response, code) = server.index("test").delete_document(0).await; assert_eq!(code, 200); + index.wait_update_id(1).await; let (_response, code) = index.get_document(0, None).await; assert_eq!(code, 400); @@ -50,7 +51,7 @@ async fn clear_all_documents() { let (_response, code) = index.clear_all_documents().await; assert_eq!(code, 200); - let _update = index.wait_update_id(0).await; + let _update = index.wait_update_id(1).await; let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; assert_eq!(code, 200); assert!(response.as_array().unwrap().is_empty()); @@ -70,3 +71,42 @@ async fn clear_all_documents_empty_index() { assert_eq!(code, 200); assert!(response.as_array().unwrap().is_empty()); } + +#[actix_rt::test] +async fn delete_batch_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").delete_batch(vec![]).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn delete_batch() { + let server = Server::new().await; + let index = server.index("test"); + index.add_documents(json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }, { "id": 3, "content": "foobar" }]), Some("id")).await; + index.wait_update_id(0).await; + let (_response, code) = index.delete_batch(vec![1, 0]).await; + assert_eq!(code, 200); + + let _update = index.wait_update_id(1).await; + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 1); + assert_eq!(response.as_array().unwrap()[0]["id"], 3); +} + + +#[actix_rt::test] +async fn delete_no_document_batch() { + let server = Server::new().await; + let index = server.index("test"); + index.add_documents(json!([{ "id": 1, "content": "foobar" }, { "id": 0, "content": "foobar" }, { "id": 3, "content": "foobar" }]), Some("id")).await; + index.wait_update_id(0).await; + let (_response, code) = index.delete_batch(vec![]).await; + assert_eq!(code, 200); + + let _update = index.wait_update_id(1).await; + let (response, code) = index.get_all_documents(GetAllDocumentsOptions::default()).await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 3); +} From af2cbd0258e93864d646d1f5740fc9253ee4b5ce Mon Sep 17 00:00:00 2001 From: mpostma Date: Tue, 23 Feb 2021 19:15:42 +0100 Subject: [PATCH 21/26] test get updates --- tests/integration.rs | 1 + tests/updates/mod.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/updates/mod.rs diff --git a/tests/integration.rs b/tests/integration.rs index 34fbde4b6..7e54d8bbf 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -3,6 +3,7 @@ mod index; mod search; mod settings; mod documents; +mod updates; // Tests are isolated by features in different modules to allow better readability, test // targetability, and improved incremental compilation times. diff --git a/tests/updates/mod.rs b/tests/updates/mod.rs new file mode 100644 index 000000000..3fff2d911 --- /dev/null +++ b/tests/updates/mod.rs @@ -0,0 +1,67 @@ +use crate::common::Server; + +#[actix_rt::test] +async fn get_update_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").get_update(0).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn get_unexisting_udpate_status() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let (_response, code) = index.get_update(0).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn get_update_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; + let (_response, code) = index.get_update(0).await; + assert_eq!(code, 200); + // TODO check resonse format, as per #48 +} + +#[actix_rt::test] +async fn list_updates_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").list_updates().await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn list_no_updates() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let (response, code) = index.list_updates().await; + assert_eq!(code, 200); + assert!(response.as_array().unwrap().is_empty()); +} + +// TODO: fix #32 +#[actix_rt::test] +#[ignore] +async fn list_updates() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + index.add_documents( + serde_json::from_str(include_str!("../assets/test_set.json")).unwrap(), + None + ).await; + let (response, code) = index.list_updates().await; + assert_eq!(code, 200); + assert_eq!(response.as_array().unwrap().len(), 1); +} From ac89c35edc361159b653e97c1e0e13516c3cb826 Mon Sep 17 00:00:00 2001 From: mpostma Date: Tue, 23 Feb 2021 19:46:18 +0100 Subject: [PATCH 22/26] add settings routes errors --- src/routes/settings/mod.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/routes/settings/mod.rs b/src/routes/settings/mod.rs index 56c1d34a0..00bc4220e 100644 --- a/src/routes/settings/mod.rs +++ b/src/routes/settings/mod.rs @@ -1,5 +1,4 @@ use actix_web::{web, HttpResponse, delete, get, post}; -use log::error; use crate::Data; use crate::error::ResponseError; @@ -33,8 +32,7 @@ macro_rules! make_setting_route { Ok(HttpResponse::Ok().body(json)) } Err(e) => { - log::error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } @@ -56,8 +54,7 @@ macro_rules! make_setting_route { Ok(HttpResponse::Ok().body(json)) } Err(e) => { - log::error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } @@ -74,8 +71,7 @@ macro_rules! make_setting_route { Ok(HttpResponse::Ok().body(json)) } Err(e) => { - log::error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } @@ -147,8 +143,7 @@ async fn update_all( Ok(HttpResponse::Ok().body(json)) } Err(e) => { - error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } @@ -164,8 +159,7 @@ async fn get_all( Ok(HttpResponse::Ok().body(json)) } Err(e) => { - error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } @@ -182,8 +176,7 @@ async fn delete_all( Ok(HttpResponse::Ok().body(json)) } Err(e) => { - error!("{}", e); - unimplemented!(); + Ok(HttpResponse::BadRequest().body(serde_json::json!({ "error": e.to_string() }))) } } } From c7ab4dccc3a35ab72f01fff138ecf84b6f8e991c Mon Sep 17 00:00:00 2001 From: mpostma Date: Wed, 24 Feb 2021 09:30:51 +0100 Subject: [PATCH 23/26] test get settings --- tests/common/index.rs | 10 ++++ tests/common/server.rs | 2 +- tests/settings/get_settings.rs | 87 ++++++++++++++++++++++++++++++++++ tests/settings/mod.rs | 1 + 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/settings/get_settings.rs create mode 100644 tests/settings/mod.rs diff --git a/tests/common/index.rs b/tests/common/index.rs index a50f8e6a3..53f48706d 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -131,6 +131,16 @@ impl Index<'_> { let url = format!("/indexes/{}/documents/delete-batch", self.uid); self.service.post(url, serde_json::to_value(&ids).unwrap()).await } + + pub async fn settings(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings", self.uid); + self.service.get(url).await + } + + pub async fn update_settings(&self, settings: Value) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings", self.uid); + self.service.post(url, settings).await + } } pub struct GetDocumentOptions; diff --git a/tests/common/server.rs b/tests/common/server.rs index de32a2045..d7d76445c 100644 --- a/tests/common/server.rs +++ b/tests/common/server.rs @@ -10,7 +10,7 @@ use super::index::Index; use super::service::Service; pub struct Server { - service: Service, + pub service: Service, } impl Server { diff --git a/tests/settings/get_settings.rs b/tests/settings/get_settings.rs new file mode 100644 index 000000000..f66cf03dd --- /dev/null +++ b/tests/settings/get_settings.rs @@ -0,0 +1,87 @@ +use crate::common::Server; +use serde_json::json; + +#[actix_rt::test] +async fn get_settings_unexisting_index() { + let server = Server::new().await; + let (_response, code) = server.index("test").settings().await; + assert_eq!(code, 400) +} + +#[actix_rt::test] +async fn get_settings() { + let server = Server::new().await; + let index = server.index("test"); + index.create(None).await; + let (response, code) = index.settings().await; + assert_eq!(code, 200); + let settings = response.as_object().unwrap(); + assert_eq!(settings.keys().len(), 3); + assert_eq!(settings["displayedAttributes"], json!(["*"])); + assert_eq!(settings["searchableAttributes"], json!(["*"])); + assert_eq!(settings["facetedAttributes"], json!({})); +} + +#[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; + assert_eq!(code, 200); + let (_response, code) = index.get().await; + assert_eq!(code, 200); +} + +macro_rules! test_setting_routes { + ($($setting:ident), *) => { + $( + 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::()); + let (_response, code) = server.service.get(url).await; + assert_eq!(code, 400); + } + + #[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::()); + let (_response, code) = server.service.post(url, serde_json::Value::Null).await; + assert_eq!(code, 200); + let (_response, code) = server.index("test").get().await; + assert_eq!(code, 200); + } + + #[actix_rt::test] + #[ignore] + 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::()); + let (_response, code) = server.service.delete(url).await; + assert_eq!(code, 400); + } + } + )* + }; +} + +test_setting_routes!( + attributes_for_faceting, + displayed_attributes, + searchable_attributes); diff --git a/tests/settings/mod.rs b/tests/settings/mod.rs new file mode 100644 index 000000000..c9e93c85d --- /dev/null +++ b/tests/settings/mod.rs @@ -0,0 +1 @@ +mod get_settings; From 7d9c5f64aa7768efbe29b143f790b5f8358594ff Mon Sep 17 00:00:00 2001 From: mpostma Date: Wed, 24 Feb 2021 09:42:36 +0100 Subject: [PATCH 24/26] test partial update --- tests/settings/get_settings.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/settings/get_settings.rs b/tests/settings/get_settings.rs index f66cf03dd..d6d75e389 100644 --- a/tests/settings/get_settings.rs +++ b/tests/settings/get_settings.rs @@ -22,6 +22,34 @@ async fn get_settings() { assert_eq!(settings["facetedAttributes"], json!({})); } +#[actix_rt::test] +async fn update_settings_unknown_field() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.update_settings(json!({"foo": 12})).await; + assert_eq!(code, 400); +} + +#[actix_rt::test] +async fn test_partial_update() { + let server = Server::new().await; + let index = server.index("test"); + index.update_settings(json!({"displayedAttributes": ["foo"]})).await; + index.wait_update_id(0).await; + let (response, code) = index.settings().await; + assert_eq!(code, 200); + assert_eq!(response["displayedAttributes"],json!(["foo"])); + assert_eq!(response["searchableAttributes"],json!(["*"])); + + index.update_settings(json!({"searchableAttributes": ["bar"]})).await; + index.wait_update_id(1).await; + + let (response, code) = index.settings().await; + assert_eq!(code, 200); + assert_eq!(response["displayedAttributes"],json!(["foo"])); + assert_eq!(response["searchableAttributes"],json!(["bar"])); +} + #[actix_rt::test] async fn update_setting_unexisting_index() { let server = Server::new().await; From 3f939f3ccfd0f4b074d33187d00193f7ee6c27cb Mon Sep 17 00:00:00 2001 From: mpostma Date: Wed, 24 Feb 2021 10:14:36 +0100 Subject: [PATCH 25/26] test delete settings --- tests/common/index.rs | 5 +++++ tests/settings/get_settings.rs | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/tests/common/index.rs b/tests/common/index.rs index 53f48706d..710b96a9f 100644 --- a/tests/common/index.rs +++ b/tests/common/index.rs @@ -141,6 +141,11 @@ impl Index<'_> { let url = format!("/indexes/{}/settings", self.uid); self.service.post(url, settings).await } + + pub async fn delete_settings(&self) -> (Value, StatusCode) { + let url = format!("/indexes/{}/settings", self.uid); + self.service.delete(url).await + } } pub struct GetDocumentOptions; diff --git a/tests/settings/get_settings.rs b/tests/settings/get_settings.rs index d6d75e389..44866c0b0 100644 --- a/tests/settings/get_settings.rs +++ b/tests/settings/get_settings.rs @@ -50,6 +50,16 @@ async fn test_partial_update() { assert_eq!(response["searchableAttributes"],json!(["bar"])); } +#[actix_rt::test] +#[ignore] +// need fix #54 +async fn delete_settings_unexisting_index() { + let server = Server::new().await; + let index = server.index("test"); + let (_response, code) = index.delete_settings().await; + assert_eq!(code, 400); +} + #[actix_rt::test] async fn update_setting_unexisting_index() { let server = Server::new().await; From 60a42bc511d555fbae5ff6ffca766e5d0820072f Mon Sep 17 00:00:00 2001 From: mpostma Date: Wed, 24 Feb 2021 10:19:22 +0100 Subject: [PATCH 26/26] reset settings --- tests/settings/get_settings.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/settings/get_settings.rs b/tests/settings/get_settings.rs index 44866c0b0..bae044acb 100644 --- a/tests/settings/get_settings.rs +++ b/tests/settings/get_settings.rs @@ -60,6 +60,26 @@ async fn delete_settings_unexisting_index() { assert_eq!(code, 400); } +#[actix_rt::test] +async fn reset_all_settings() { + let server = Server::new().await; + let index = server.index("test"); + index.update_settings(json!({"displayedAttributes": ["foo"], "searchableAttributes": ["bar"]})).await; + index.wait_update_id(0).await; + let (response, code) = index.settings().await; + assert_eq!(code, 200); + assert_eq!(response["displayedAttributes"],json!(["foo"])); + assert_eq!(response["searchableAttributes"],json!(["bar"])); + + index.delete_settings().await; + index.wait_update_id(1).await; + + let (response, code) = index.settings().await; + assert_eq!(code, 200); + assert_eq!(response["displayedAttributes"],json!(["*"])); + assert_eq!(response["searchableAttributes"],json!(["*"])); +} + #[actix_rt::test] async fn update_setting_unexisting_index() { let server = Server::new().await;