From b17fcb8c41823851f82eae047139360fc9c968b9 Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Fri, 8 Mar 2024 19:49:40 +0100 Subject: [PATCH] add test with warp --- members/rest-queued/src/client.rs | 36 +++++++++++---- members/rest-queued/src/routes.rs | 77 +++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 13 deletions(-) diff --git a/members/rest-queued/src/client.rs b/members/rest-queued/src/client.rs index fcdf086..5e5a959 100644 --- a/members/rest-queued/src/client.rs +++ b/members/rest-queued/src/client.rs @@ -4,7 +4,9 @@ use crate::{store::Sequence, Item, Store}; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; -const ALPHABET: &str = "qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"; +pub const ALPHABET: &str = "qwertzuiopasdfghjklyxcvbnmQWERTZUIOPASDFGHJKLYXCVBNM"; +pub const TOK_LEN: usize = 40; +pub const ID_LEN: usize = 20; #[derive(Debug, Clone, PartialEq, Eq, Serialize)] pub struct Client { @@ -61,20 +63,24 @@ impl Id { pub fn new() -> Self { let mut rng = rand::thread_rng(); let mut data = ALPHABET.to_string().into_bytes(); + data.repeat(ID_LEN); data.shuffle(&mut rng); Self { - inner: String::from_utf8(data[..20].into()).unwrap(), + inner: String::from_utf8(data[..ID_LEN].into()).unwrap(), } } + + pub fn len(&self) -> usize { + self.inner.len() + } } impl FromStr for Id { type Err = Infallible; fn from_str(s: &str) -> Result { - Ok(Self { - inner: s.to_string(), - }) + let s = s.replace('"', ""); + Ok(Self { inner: s }) } } @@ -84,7 +90,7 @@ impl Display for Id { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Token { #[serde(rename = "token")] inner: String, @@ -94,19 +100,29 @@ impl Token { pub fn new() -> Self { let mut rng = rand::thread_rng(); let mut data = ALPHABET.to_string().into_bytes(); + data.repeat(TOK_LEN); data.shuffle(&mut rng); Self { - inner: String::from_utf8(data).unwrap(), + inner: String::from_utf8(data[..TOK_LEN].to_vec()).unwrap(), } } + + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl Display for Token { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.inner) + } } impl FromStr for Token { type Err = Infallible; fn from_str(s: &str) -> Result { - Ok(Self { - inner: s.to_string(), - }) + let s = s.replace('"', ""); + Ok(Self { inner: s }) } } diff --git a/members/rest-queued/src/routes.rs b/members/rest-queued/src/routes.rs index 31f982c..36935c5 100644 --- a/members/rest-queued/src/routes.rs +++ b/members/rest-queued/src/routes.rs @@ -5,7 +5,8 @@ use warp::{ filters::BoxedFilter, http::StatusCode, reject::{MissingHeader, Rejection}, - reply, Filter, Reply, + reply::{self, Json}, + Filter, Reply, }; use crate::{Client, Id, Store, StoreErr, Token}; @@ -62,7 +63,7 @@ pub async fn item_getter( } // GET /api/v1/items -pub fn get_items(store: Store) -> BoxedFilter<(impl Reply,)> { +pub fn get_items(store: Store) -> impl Filter + Clone { warp::path!("api" / "v1" / "items") .and(warp::get()) .and(warp::query::>()) @@ -74,7 +75,9 @@ pub fn get_items(store: Store) -> BoxedFilter<(impl Reply,)> { } // GET /api/v1/register -pub fn get_register(store: Store) -> BoxedFilter<(impl Reply,)> { +pub fn get_register( + store: Store, +) -> impl Filter + Clone { warp::path!("api" / "v1" / "register") .and(warp::get()) .and(with_store(store)) @@ -88,3 +91,71 @@ pub fn get_register(store: Store) -> BoxedFilter<(impl Reply,)> { }) .boxed() } + +mod test { + use warp::{ + http::StatusCode, + hyper::{self, body::*}, + reply::{Json, Reply}, + }; + + use std::str::FromStr; + + #[tokio::test] + async fn test_register_and_get() { + let store = crate::Store::new(); + let filter = super::get_register(store.clone()); + + let response: warp::reply::Response = warp::test::request() + .path("/api/v1/register") + .filter(&filter) + .await + .unwrap() + .into_response(); + + assert_eq!(response.status(), StatusCode::OK); + let body_raw: Bytes = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body_json: serde_json::Value = serde_json::from_slice(&body_raw).unwrap(); + + assert!(body_json.is_object()); + let id: crate::Id = crate::Id::from_str( + &body_json + .get("id") + .expect("response has no field 'id'") + .to_owned() + .to_string(), + ) + .unwrap(); + let token: crate::Token = crate::Token::from_str( + &body_json + .get("token") + .expect("response has no field 'token'") + .to_owned() + .to_string(), + ) + .unwrap(); + + assert_eq!(id.len(), crate::ID_LEN); + assert_eq!(token.len(), crate::TOK_LEN); + + let filter = super::get_items(store); + let response: warp::reply::Response = warp::test::request() + .path(format!("/api/v1/items/?id={id}").as_str()) + .header("Token", token.to_string()) + .filter(&filter) + .await + .unwrap() + .into_response(); + assert_eq!(response.status(), StatusCode::OK); + let body_raw: Bytes = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body_json: serde_json::Value = serde_json::from_slice(&body_raw).unwrap(); + assert!(body_json.is_array()); + + for i in 0..2 { + assert!(body_json[i].is_object()); + let item: crate::Item = + serde_json::from_value(body_json[i].clone().take()).unwrap(); + assert_eq!(item.seq, i); + } + } +}