restructure project

This commit is contained in:
mpostma 2021-03-10 13:46:49 +01:00
parent 8061a04661
commit 5ecf514d28
No known key found for this signature in database
GPG key ID: CBC8A7C1D7A28C3A
75 changed files with 4377 additions and 323 deletions

View file

@ -0,0 +1,158 @@
use std::time::Duration;
use actix_web::http::StatusCode;
use serde_json::{json, Value};
use tokio::time::sleep;
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 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,
"primaryKey": primary_key,
});
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
}
pub async fn delete(&self) -> (Value, StatusCode) {
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 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) -> 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 {
let (response, status_code) = self.service.get(&url).await;
assert_eq!(status_code, 200);
if response["status"] == "processed" || response["status"] == "failed" {
return response;
}
sleep(Duration::from_secs(1)).await;
}
panic!("Timeout waiting for update id");
}
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
}
#[allow(dead_code)]
pub async fn list_updates(&self) -> (Value, StatusCode) {
let url = format!("/indexes/{}/updates", self.uid);
self.service.get(url).await
}
pub async fn get_document(&self, id: u64, _options: Option<GetDocumentOptions>) -> (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 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
}
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 async fn delete_batch(&self, ids: Vec<u64>) -> (Value, StatusCode) {
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 async fn delete_settings(&self) -> (Value, StatusCode) {
let url = format!("/indexes/{}/settings", self.uid);
self.service.delete(url).await
}
}
pub struct GetDocumentOptions;
#[derive(Debug, Default)]
pub struct GetAllDocumentsOptions {
pub limit: Option<usize>,
pub offset: Option<usize>,
pub attributes_to_retrieve: Option<Vec<&'static str>>,
}

View file

@ -0,0 +1,31 @@
mod index;
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]
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()
)
});
};
}

View file

@ -0,0 +1,71 @@
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};
use super::index::Index;
use super::service::Service;
pub struct Server {
pub 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(),
#[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();
let service = Service(data);
Server {
service,
}
}
/// Returns a view to an index. There is no guarantee that the index exists.
pub fn index<'a>(&'a self, uid: impl AsRef<str>) -> Index<'a> {
Index {
uid: uid.as_ref().to_string(),
service: &self.service,
}
}
pub async fn list_indexes(&self) -> (Value, StatusCode) {
self.service.get("/indexes").await
}
}

View file

@ -0,0 +1,85 @@
use actix_web::{http::StatusCode, test};
use serde_json::Value;
use meilisearch_http::data::Data;
use meilisearch_http::create_app;
pub struct Service(pub Data);
impl Service {
pub async fn post(&self, url: impl AsRef<str>, body: Value) -> (Value, StatusCode) {
let mut app =
test::init_service(create_app!(&self.0, true)).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)
}
/// 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<str>, body: impl AsRef<str>) -> (Value, StatusCode) {
let mut app =
test::init_service(create_app!(&self.0, true)).await;
let req = test::TestRequest::post()
.uri(url.as_ref())
.set_payload(body.as_ref().to_string())
.insert_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<str>) -> (Value, StatusCode) {
let mut app =
test::init_service(create_app!(&self.0, true)).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)
}
pub async fn put(&self, url: impl AsRef<str>, body: Value) -> (Value, StatusCode) {
let mut app =
test::init_service(create_app!(&self.0, true)).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)
}
pub async fn delete(&self, url: impl AsRef<str>) -> (Value, StatusCode) {
let mut app =
test::init_service(create_app!(&self.0, true)).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)
}
}