mirror of
https://github.com/tokio-rs/axum.git
synced 2024-12-28 23:38:20 +01:00
Add some more tests
This commit is contained in:
parent
11843addf6
commit
867dd8012c
2 changed files with 107 additions and 8 deletions
|
@ -10,6 +10,17 @@ pub trait FromRequest: Sized {
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error>;
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_body(req: &mut Request<Body>) -> Body {
|
||||||
|
struct BodyAlreadyTaken;
|
||||||
|
|
||||||
|
if req.extensions_mut().insert(BodyAlreadyTaken).is_some() {
|
||||||
|
panic!("Cannot have two request body on extractors")
|
||||||
|
} else {
|
||||||
|
let body = std::mem::take(req.body_mut());
|
||||||
|
body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T> FromRequest for Option<T>
|
impl<T> FromRequest for Option<T>
|
||||||
where
|
where
|
||||||
|
@ -57,7 +68,7 @@ where
|
||||||
{
|
{
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
||||||
if has_content_type(&req, "application/json") {
|
if has_content_type(&req, "application/json") {
|
||||||
let body = std::mem::take(req.body_mut());
|
let body = take_body(req);
|
||||||
|
|
||||||
let bytes = hyper::body::to_bytes(body)
|
let bytes = hyper::body::to_bytes(body)
|
||||||
.await
|
.await
|
||||||
|
@ -116,7 +127,7 @@ where
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Bytes {
|
impl FromRequest for Bytes {
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
||||||
let body = std::mem::take(req.body_mut());
|
let body = take_body(req);
|
||||||
|
|
||||||
let bytes = hyper::body::to_bytes(body)
|
let bytes = hyper::body::to_bytes(body)
|
||||||
.await
|
.await
|
||||||
|
@ -129,7 +140,7 @@ impl FromRequest for Bytes {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for String {
|
impl FromRequest for String {
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
||||||
let body = std::mem::take(req.body_mut());
|
let body = take_body(req);
|
||||||
|
|
||||||
let bytes = hyper::body::to_bytes(body)
|
let bytes = hyper::body::to_bytes(body)
|
||||||
.await
|
.await
|
||||||
|
@ -145,7 +156,7 @@ impl FromRequest for String {
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl FromRequest for Body {
|
impl FromRequest for Body {
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
||||||
let body = std::mem::take(req.body_mut());
|
let body = take_body(req);
|
||||||
Ok(body)
|
Ok(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +174,7 @@ impl<const N: u64> BytesMaxLength<N> {
|
||||||
impl<const N: u64> FromRequest for BytesMaxLength<N> {
|
impl<const N: u64> FromRequest for BytesMaxLength<N> {
|
||||||
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
async fn from_request(req: &mut Request<Body>) -> Result<Self, Error> {
|
||||||
let content_length = req.headers().get(http::header::CONTENT_LENGTH).cloned();
|
let content_length = req.headers().get(http::header::CONTENT_LENGTH).cloned();
|
||||||
let body = std::mem::take(req.body_mut());
|
let body = take_body(req);
|
||||||
|
|
||||||
let content_length =
|
let content_length =
|
||||||
content_length.and_then(|value| value.to_str().ok()?.parse::<u64>().ok());
|
content_length.and_then(|value| value.to_str().ok()?.parse::<u64>().ok());
|
||||||
|
|
94
src/tests.rs
94
src/tests.rs
|
@ -157,10 +157,98 @@ async fn body_with_length_limit() {
|
||||||
assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
|
assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(david): can extractors change the request type?
|
#[tokio::test]
|
||||||
// TODO(david): should FromRequest be an async-trait?
|
async fn routing() {
|
||||||
|
let app = app()
|
||||||
|
.at("/users")
|
||||||
|
.get(|_: Request<Body>| async { Ok("users#index") })
|
||||||
|
.post(|_: Request<Body>| async { Ok("users#create") })
|
||||||
|
.at("/users/:id")
|
||||||
|
.get(|_: Request<Body>| async { Ok("users#show") })
|
||||||
|
.at("/users/:id/action")
|
||||||
|
.get(|_: Request<Body>| async { Ok("users#action") })
|
||||||
|
.into_service();
|
||||||
|
|
||||||
// TODO(david): routing
|
let addr = run_in_background(app).await;
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/users", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "users#index");
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.post(format!("http://{}/users", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "users#create");
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/users/1", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "users#show");
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/users/1/action", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
assert_eq!(res.text().await.unwrap(), "users#action");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn extracting_url_params() {
|
||||||
|
let app = app()
|
||||||
|
.at("/users/:id")
|
||||||
|
.get(
|
||||||
|
|_: Request<Body>, params: extract::UrlParams<(i32,)>| async move {
|
||||||
|
let (id,) = params.into_inner();
|
||||||
|
assert_eq!(id, 42);
|
||||||
|
|
||||||
|
Ok(response::Empty)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.post(
|
||||||
|
|_: Request<Body>, params_map: extract::UrlParamsMap| async move {
|
||||||
|
assert_eq!(params_map.get("id").unwrap(), "1337");
|
||||||
|
assert_eq!(params_map.get_typed::<i32>("id").unwrap(), 1337);
|
||||||
|
|
||||||
|
Ok(response::Empty)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.into_service();
|
||||||
|
|
||||||
|
let addr = run_in_background(app).await;
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.get(format!("http://{}/users/42", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let res = client
|
||||||
|
.post(format!("http://{}/users/1337", addr))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(david): lots of routes and boxing, shouldn't take forever to compile
|
// TODO(david): lots of routes and boxing, shouldn't take forever to compile
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue