add test with warp
cargo devel CI / cargo CI (push) Failing after 1m46s
Details
cargo devel CI / cargo CI (push) Failing after 1m46s
Details
This commit is contained in:
parent
77ced4b277
commit
b17fcb8c41
|
@ -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<Self, Self::Err> {
|
||||
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<Self, Self::Err> {
|
||||
Ok(Self {
|
||||
inner: s.to_string(),
|
||||
})
|
||||
let s = s.replace('"', "");
|
||||
Ok(Self { inner: s })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Extract = (Json,), Error = warp::Rejection> + Clone {
|
||||
warp::path!("api" / "v1" / "items")
|
||||
.and(warp::get())
|
||||
.and(warp::query::<HashMap<String, String>>())
|
||||
|
@ -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<Extract = (Json,), Error = warp::Rejection> + 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue