#![feature(async_closure)]
#[cfg(test)]
use brio::{App, Ctx, Request, Response, Status};
use futures::Future;
use hyper::{Client, Uri};
use log::info;
use rand::{thread_rng, Rng};
use serde_json::{json, Value};
use std::panic;
use std::{pin::Pin, thread, time::Instant};
mod util;
use util::*;
type BoxFuture<'a, Response> = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
async fn handler(mut req: Request) -> Response {
let json = match req.json().await {
Ok(json) => json,
Err(_err) => {
return Response::with_status(Status::BadRequest);
}
};
let mut res = Response::with_status(Status::Ok);
res.set_json(json);
res
}
fn logger(mut ctx: Ctx) -> BoxFuture<Response> {
let now = Instant::now();
let path = ctx.req().route().path().clone();
ctx.req_mut()
.headers_mut()
.insert("foo".to_owned(), "bar".to_owned());
let method = ctx.req().route().method().unwrap().clone();
let fut = ctx.next();
Box::pin(async move {
let res = fut.await;
info!(
"request {} {} took {:?} ({})",
method,
path,
Instant::now().duration_since(now),
res.status() as u32
);
res
})
}
#[tokio::test]
async fn get() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let port: u32 = rng.gen_range(10000, 20000);
thread::spawn(move || {
let mut app = App::new();
app.get("/bar", async move |_req| Response::with_status(Status::Ok));
app.middleware("*", logger);
app.run(port)
});
let client = Client::new();
let uri: Uri = format!("http://127.0.0.1:{}/bar", port).parse()?;
let resp = client.get(uri).await?;
assert_eq!(resp.status(), 200);
Ok(())
}
#[tokio::test]
async fn post() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let port: u32 = rng.gen_range(10000, 20000);
thread::spawn(move || {
let mut app = App::new();
app.post("/foo", handler);
app.run(port)
});
let body = json!({"hello": "world"});
let client = Client::new();
let uri: Uri = format!("http://127.0.0.1:{}/foo", port).parse()?;
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(uri)
.header("content-type", "application/json")
.body(hyper::Body::from(serde_json::to_vec(&body)?))?;
let resp = client.request(req).await?;
assert_eq!(resp.status(), 200);
let buf = hyper::body::to_bytes(resp).await?;
let json = serde_json::from_slice::<Value>(&buf)?;
assert_eq!(body, json);
Ok(())
}
#[tokio::test]
async fn multiple_chunks() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let port: u32 = rng.gen_range(10000, 20000);
thread::spawn(move || {
let mut app = App::new();
app.post("/foo", handler);
app.middleware("*", logger);
app.run(port)
});
let client = Client::new();
let uri: Uri = format!("http://127.0.0.1:{}/foo", port).parse()?;
for _ in 0..2 {
let body = large_body();
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(uri.clone())
.header("content-type", "application/json")
.body(hyper::Body::from(serde_json::to_vec(&body)?))?;
let resp = client.request(req).await?;
assert_eq!(resp.status(), 200);
let buf = hyper::body::to_bytes(resp).await?;
let json = serde_json::from_slice::<Value>(&buf)?;
assert_eq!(body, json);
}
Ok(())
}
#[tokio::test]
async fn skip_body() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();
let port: u32 = rng.gen_range(10000, 20000);
thread::spawn(move || {
let mut app = App::new();
app.post("/foo", handler);
app.post("/bar", async move |_req| Response::with_status(Status::Ok));
app.middleware("*", logger);
app.run(port)
});
let client = Client::new();
let arr = Value::Array(vec![large_body(), large_body()]);
let uri: Uri = format!("http://127.0.0.1:{}/bar", port).parse()?;
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(uri.clone())
.header("content-type", "application/json")
.body(hyper::Body::from(serde_json::to_vec(&arr)?))?;
let resp = client.request(req).await?;
assert_eq!(resp.status(), 200);
let body = large_body();
let uri: Uri = format!("http://127.0.0.1:{}/foo", port).parse()?;
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.uri(uri.clone())
.header("content-type", "application/json")
.body(hyper::Body::from(serde_json::to_vec(&body)?))?;
let resp = client.request(req).await?;
assert_eq!(resp.status(), 200);
let buf = hyper::body::to_bytes(resp).await?;
let json = serde_json::from_slice::<Value>(&buf)?;
assert_eq!(body, json);
Ok(())
}