From b69f8d67c33e02044572ed94f49e3a7ba76debf1 Mon Sep 17 00:00:00 2001 From: "Andrey \"MOU\" Larionov" Date: Thu, 13 Oct 2022 00:56:57 +0200 Subject: [PATCH] Added test to verify response encoding Alongside request encoding (compression) support, it is helpful to verify that the server respect `Accept-Encoding` headers and apply the corresponding compression to responses. --- meilisearch-http/tests/common/encoder.rs | 31 ++++++++++++- .../tests/documents/get_documents.rs | 44 ++++++++++++++++++- meilisearch-http/tests/index/create_index.rs | 42 ++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/meilisearch-http/tests/common/encoder.rs b/meilisearch-http/tests/common/encoder.rs index 78d6051d1..44a59d39b 100644 --- a/meilisearch-http/tests/common/encoder.rs +++ b/meilisearch-http/tests/common/encoder.rs @@ -2,7 +2,8 @@ use actix_http::header::TryIntoHeaderPair; use bytes::Bytes; use flate2::write::{GzEncoder, ZlibEncoder}; use flate2::Compression; -use std::io::Write; +use std::io::{Read, Write}; +use flate2::read::{GzDecoder, ZlibDecoder}; #[derive(Clone, Copy)] pub enum Encoder { @@ -41,6 +42,34 @@ impl Encoder { } } + pub fn decode(self: &Encoder, bytes: impl Into) -> impl Into { + let mut buffer = Vec::new(); + let input = bytes.into(); + match self { + Self::Gzip => { + GzDecoder::new(input.as_ref()) + .read_to_end(&mut buffer) + .expect("Invalid gzip stream"); + }, + Self::Deflate => { + ZlibDecoder::new(input.as_ref()) + .read_to_end(&mut buffer) + .expect("Invalid zlib stream"); + }, + Self::Plain => { + buffer + .write(input.as_ref()) + .expect("Unexpected memory copying issue"); + }, + Self::Brotli => { + brotli::Decompressor::new(input.as_ref(), 4096 ) + .read_to_end(&mut buffer) + .expect("Invalid brotli stream"); + }, + }; + buffer + } + pub fn header(self: &Encoder) -> Option { match self { Self::Plain => None, diff --git a/meilisearch-http/tests/documents/get_documents.rs b/meilisearch-http/tests/documents/get_documents.rs index c15d3f7fa..cd25dd57c 100644 --- a/meilisearch-http/tests/documents/get_documents.rs +++ b/meilisearch-http/tests/documents/get_documents.rs @@ -1,6 +1,11 @@ use crate::common::{GetAllDocumentsOptions, GetDocumentOptions, Server}; +use actix_web::test; +use http::header::ACCEPT_ENCODING; -use serde_json::json; +use crate::common::encoder::Encoder; +use meilisearch_http::{analytics, create_app}; +use serde_json::{json, Value}; +use urlencoding::encode as urlencode; // TODO: partial test since we are testing error, amd error is not yet fully implemented in // transplant @@ -155,6 +160,43 @@ async fn get_all_documents_no_options() { assert_eq!(first, arr[0]); } +#[actix_rt::test] +async fn get_all_documents_no_options_with_response_compression() { + let server = Server::new().await; + let index_uid = "test"; + let index = server.index(index_uid); + index.load_test_set().await; + + let app = test::init_service(create_app!( + &server.service.meilisearch, + &server.service.auth, + true, + server.service.options, + analytics::MockAnalytics::new(&server.service.options).0 + )) + .await; + + let req = test::TestRequest::get() + .uri(&format!( + "/indexes/{}/documents?", + urlencode(index_uid.as_ref()) + )) + .insert_header((ACCEPT_ENCODING, "gzip")) + .to_request(); + + let res = test::call_service(&app, req).await; + + assert_eq!(res.status(), 200); + + let bytes = test::read_body(res).await; + let decoded = Encoder::Gzip.decode(bytes); + let parsed_response = + serde_json::from_slice::(&decoded.into().as_ref()).expect("Expecting valid json"); + + let arr = parsed_response["results"].as_array().unwrap(); + assert_eq!(arr.len(), 20); +} + #[actix_rt::test] async fn test_get_all_documents_limit() { let server = Server::new().await; diff --git a/meilisearch-http/tests/index/create_index.rs b/meilisearch-http/tests/index/create_index.rs index f6ca76ee7..f3f0949f6 100644 --- a/meilisearch-http/tests/index/create_index.rs +++ b/meilisearch-http/tests/index/create_index.rs @@ -1,5 +1,9 @@ use crate::common::encoder::Encoder; use crate::common::Server; +use actix_web::http::header::ContentType; +use actix_web::test; +use http::header::ACCEPT_ENCODING; +use meilisearch_http::{analytics, create_app}; use serde_json::{json, Value}; #[actix_rt::test] @@ -36,6 +40,44 @@ async fn create_index_with_gzip_encoded_request() { assert_eq!(response["details"]["primaryKey"], Value::Null); } +#[actix_rt::test] +async fn create_index_with_gzip_encoded_request_and_receiving_brotli_encoded_response() { + let server = Server::new().await; + let app = test::init_service(create_app!( + &server.service.meilisearch, + &server.service.auth, + true, + server.service.options, + analytics::MockAnalytics::new(&server.service.options).0 + )) + .await; + + let body = serde_json::to_string(&json!({ + "uid": "test", + "primaryKey": None::<&str>, + })) + .unwrap(); + let req = test::TestRequest::post() + .uri("/indexes") + .insert_header(Encoder::Gzip.header().unwrap()) + .insert_header((ACCEPT_ENCODING, "br")) + .insert_header(ContentType::json()) + .set_payload(Encoder::Gzip.encode(body)) + .to_request(); + + let res = test::call_service(&app, req).await; + + assert_eq!(res.status(), 202); + + let bytes = test::read_body(res).await; + let decoded = Encoder::Brotli.decode(bytes); + let parsed_response = + serde_json::from_slice::(&decoded.into().as_ref()).expect("Expecting valid json"); + + assert_eq!(parsed_response["taskUid"], 0); + assert_eq!(parsed_response["indexUid"], "test"); +} + #[actix_rt::test] async fn create_index_with_zlib_encoded_request() { let server = Server::new().await;