Start writing more tests

This commit is contained in:
David Pedersen
2021-05-31 12:22:16 +02:00
parent 6822766165
commit 593c901aab
5 changed files with 259 additions and 196 deletions
+3 -182
View File
@@ -1,15 +1,3 @@
/*
Improvements to make:
Support extracting headers, perhaps via `headers::Header`?
Improve compile times with lots of routes, can we box and combine routers?
Tests
*/
use self::{
body::Body,
routing::{EmptyRouter, RouteAt},
@@ -33,6 +21,9 @@ pub mod routing;
mod error;
#[cfg(test)]
mod tests;
pub use self::error::Error;
pub fn app() -> App<EmptyRouter> {
@@ -139,173 +130,3 @@ where
}
}
}
#[cfg(test)]
mod tests {
#![allow(warnings)]
use super::*;
use crate::handler::Handler;
use http::{Method, Request, StatusCode};
use hyper::Server;
use serde::Deserialize;
use std::time::Duration;
use std::{fmt, net::SocketAddr, sync::Arc};
use tower::{
layer::util::Identity, make::Shared, service_fn, timeout::TimeoutLayer, ServiceBuilder,
ServiceExt,
};
use tower_http::{
add_extension::AddExtensionLayer,
compression::CompressionLayer,
trace::{Trace, TraceLayer},
};
#[tokio::test]
async fn basic() {
#[derive(Debug, Deserialize)]
struct Pagination {
page: usize,
per_page: usize,
}
#[derive(Debug, Deserialize)]
struct UsersCreate {
username: String,
}
async fn root(_: Request<Body>) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::from("Hello, World!")))
}
async fn large_static_file(
_: Request<Body>,
body: extract::BytesMaxLength<{ 1024 * 500 }>,
) -> Result<Response<Body>, Error> {
Ok(Response::new(Body::empty()))
}
let app = app()
// routes with functions
.at("/")
.get(root)
// routes with closures
.at("/users")
.get(
|_: Request<Body>, pagination: extract::Query<Pagination>| async {
let pagination = pagination.into_inner();
assert_eq!(pagination.page, 1);
assert_eq!(pagination.per_page, 30);
Ok::<_, Error>("users#index".to_string())
},
)
.post(
|_: Request<Body>,
payload: extract::Json<UsersCreate>,
_state: extract::Extension<Arc<State>>| async {
let payload = payload.into_inner();
assert_eq!(payload.username, "bob");
Ok::<_, Error>(response::Json(
serde_json::json!({ "username": payload.username }),
))
},
)
// routes with a service
.at("/service")
.get_service(service_fn(root))
// routes with layers applied
.at("/large-static-file")
.get(
large_static_file.layer(
ServiceBuilder::new()
.layer(TimeoutLayer::new(Duration::from_secs(30)))
.layer(CompressionLayer::new())
.into_inner(),
),
)
.into_service();
// state shared by all routes, could hold db connection etc
struct State {}
let state = Arc::new(State {});
// can add more middleware
let mut app = ServiceBuilder::new()
.layer(AddExtensionLayer::new(state))
.layer(TraceLayer::new_for_http())
.service(app);
let res = app
.ready()
.await
.unwrap()
.call(
Request::builder()
.method(Method::GET)
.uri("/")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(body_to_string(res).await, "Hello, World!");
let res = app
.ready()
.await
.unwrap()
.call(
Request::builder()
.method(Method::GET)
.uri("/users?page=1&per_page=30")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(body_to_string(res).await, "users#index");
let res = app
.ready()
.await
.unwrap()
.call(
Request::builder()
.method(Method::GET)
.uri("/users")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
assert_eq!(body_to_string(res).await, "");
let res = app
.ready()
.await
.unwrap()
.call(
Request::builder()
.method(Method::POST)
.uri("/users")
.body(Body::from(r#"{ "username": "bob" }"#))
.unwrap(),
)
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(body_to_string(res).await, r#"{"username":"bob"}"#);
}
async fn body_to_string<B>(res: Response<B>) -> String
where
B: http_body::Body,
B::Error: fmt::Debug,
{
let bytes = hyper::body::to_bytes(res.into_body()).await.unwrap();
String::from_utf8(bytes.to_vec()).unwrap()
}
}