Revamp testing system for async.

* body_string_wait and body_bytes_wait are removed; use `.await` instead
* `dispatch()` is now an async fn and must be .await-ed
* Add `#[rocket::async_test]` macro, similar in purpose to `tokio::test`
* Tests now use either `rocket::async_test(async { })` or
  `#[rocket::async_test]` in order to `.await` the futures returned
  from `dispatch()` and `body_{string,bytes}()`
* Update 'test.sh' to reflect the tests that should be passing.

Broken:

* Cloned dispatch and mut_dispatch() with a live previous response now both fail, due to a (partial) check for mutable aliasing in LocalRequest.
* Some tests are still failing and need example-specific changes.
This commit is contained in:
Jeb Rosen 2019-08-24 10:27:10 -07:00 committed by Sergio Benitez
parent a87e1577aa
commit 560f0977d3
75 changed files with 821 additions and 847 deletions

View File

@ -42,5 +42,4 @@ members = [
"examples/tls",
"examples/fairings",
"examples/hello_2018",
"examples/hello_2015",
]

View File

@ -35,14 +35,14 @@ mod helmet_tests {
($helmet:expr, $closure:expr) => {{
let rocket = rocket::ignite().mount("/", routes![hello]).attach($helmet);
let client = Client::new(rocket).unwrap();
let response = client.get("/").dispatch();
let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
$closure(response)
}}
}
#[test]
fn default_headers_test() {
#[rocket::async_test]
async fn default_headers_test() {
dispatch!(SpaceHelmet::default(), |response: LocalResponse<'_>| {
assert_header!(response, "X-XSS-Protection", "1");
assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
@ -50,8 +50,8 @@ mod helmet_tests {
})
}
#[test]
fn disable_headers_test() {
#[rocket::async_test]
async fn disable_headers_test() {
let helmet = SpaceHelmet::default().disable::<XssFilter>();
dispatch!(helmet, |response: LocalResponse<'_>| {
assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
@ -84,8 +84,8 @@ mod helmet_tests {
});
}
#[test]
fn additional_headers_test() {
#[rocket::async_test]
async fn additional_headers_test() {
let helmet = SpaceHelmet::default()
.enable(Hsts::default())
.enable(ExpectCt::default())
@ -108,8 +108,8 @@ mod helmet_tests {
})
}
#[test]
fn uri_test() {
#[rocket::async_test]
async fn uri_test() {
let allow_uri = Uri::parse("https://www.google.com").unwrap();
let report_uri = Uri::parse("https://www.google.com").unwrap();
let enforce_uri = Uri::parse("https://www.google.com").unwrap();

View File

@ -47,7 +47,7 @@ mod static_tests {
async fn assert_file(client: &Client, prefix: &str, path: &str, exists: bool) {
let full_path = format!("/{}/{}", prefix, path);
let mut response = client.get(full_path).dispatch();
let mut response = client.get(full_path).dispatch().await;
if exists {
assert_eq!(response.status(), Status::Ok);
@ -71,48 +71,40 @@ mod static_tests {
}
}
#[test]
#[rocket::async_test]
fn test_static_no_index() {
rocket::async_test(async {
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "no_index", REGULAR_FILES, true).await;
assert_all(&client, "no_index", HIDDEN_FILES, false).await;
assert_all(&client, "no_index", INDEXED_DIRECTORIES, false).await;
})
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "no_index", REGULAR_FILES, true).await;
assert_all(&client, "no_index", HIDDEN_FILES, false).await;
assert_all(&client, "no_index", INDEXED_DIRECTORIES, false).await;
}
#[test]
#[rocket::async_test]
fn test_static_hidden() {
rocket::async_test(async {
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "dots", REGULAR_FILES, true).await;
assert_all(&client, "dots", HIDDEN_FILES, true).await;
assert_all(&client, "dots", INDEXED_DIRECTORIES, false).await;
})
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "dots", REGULAR_FILES, true).await;
assert_all(&client, "dots", HIDDEN_FILES, true).await;
assert_all(&client, "dots", INDEXED_DIRECTORIES, false).await;
}
#[test]
#[rocket::async_test]
fn test_static_index() {
rocket::async_test(async {
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "index", REGULAR_FILES, true).await;
assert_all(&client, "index", HIDDEN_FILES, false).await;
assert_all(&client, "index", INDEXED_DIRECTORIES, true).await;
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "index", REGULAR_FILES, true).await;
assert_all(&client, "index", HIDDEN_FILES, false).await;
assert_all(&client, "index", INDEXED_DIRECTORIES, true).await;
assert_all(&client, "default", REGULAR_FILES, true).await;
assert_all(&client, "default", HIDDEN_FILES, false).await;
assert_all(&client, "default", INDEXED_DIRECTORIES, true).await;
})
assert_all(&client, "default", REGULAR_FILES, true).await;
assert_all(&client, "default", HIDDEN_FILES, false).await;
assert_all(&client, "default", INDEXED_DIRECTORIES, true).await;
}
#[test]
#[rocket::async_test]
fn test_static_all() {
rocket::async_test(async {
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
})
let client = Client::new(rocket()).expect("valid rocket");
assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
}
#[test]
@ -129,33 +121,31 @@ mod static_tests {
}
}
#[test]
#[rocket::async_test]
fn test_forwarding() {
rocket::async_test(async {
use rocket::http::RawStr;
use rocket::{get, routes};
use rocket::http::RawStr;
use rocket::{get, routes};
#[get("/<value>", rank = 20)]
fn catch_one(value: String) -> String { value }
#[get("/<value>", rank = 20)]
fn catch_one(value: String) -> String { value }
#[get("/<a>/<b>", rank = 20)]
fn catch_two(a: &RawStr, b: &RawStr) -> String { format!("{}/{}", a, b) }
#[get("/<a>/<b>", rank = 20)]
fn catch_two(a: &RawStr, b: &RawStr) -> String { format!("{}/{}", a, b) }
let rocket = rocket().mount("/default", routes![catch_one, catch_two]);
let client = Client::new(rocket).expect("valid rocket");
let rocket = rocket().mount("/default", routes![catch_one, catch_two]);
let client = Client::new(rocket).expect("valid rocket");
let mut response = client.get("/default/ireallydontexist").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "ireallydontexist");
let mut response = client.get("/default/ireallydontexist").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "ireallydontexist");
let mut response = client.get("/default/idont/exist").dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "idont/exist");
let mut response = client.get("/default/idont/exist").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "idont/exist");
assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
})
assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
}
#[test]

View File

@ -65,20 +65,20 @@ mod templates_tests {
assert_eq!(template, Some(ESCAPED_EXPECTED.into()));
}
#[test]
fn test_template_metadata_with_tera() {
#[rocket::async_test]
async fn test_template_metadata_with_tera() {
let client = Client::new(rocket()).unwrap();
let response = client.get("/tera/txt_test").dispatch();
let response = client.get("/tera/txt_test").dispatch().await;
assert_eq!(response.status(), Status::Ok);
let response = client.get("/tera/html_test").dispatch();
let response = client.get("/tera/html_test").dispatch().await;
assert_eq!(response.status(), Status::Ok);
let response = client.get("/tera/not_existing").dispatch();
let response = client.get("/tera/not_existing").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let response = client.get("/hbs/txt_test").dispatch();
let response = client.get("/hbs/txt_test").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}
}
@ -105,23 +105,23 @@ mod templates_tests {
assert_eq!(template, Some(EXPECTED.into()));
}
#[test]
fn test_template_metadata_with_handlebars() {
#[rocket::async_test]
async fn test_template_metadata_with_handlebars() {
let client = Client::new(rocket()).unwrap();
let response = client.get("/hbs/test").dispatch();
let response = client.get("/hbs/test").dispatch().await;
assert_eq!(response.status(), Status::Ok);
let response = client.get("/hbs/not_existing").dispatch();
let response = client.get("/hbs/not_existing").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let response = client.get("/tera/test").dispatch();
let response = client.get("/tera/test").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}
#[test]
#[rocket::async_test]
#[cfg(debug_assertions)]
fn test_template_reload() {
async fn test_template_reload() {
use std::fs::File;
use std::io::Write;
use std::thread;
@ -146,7 +146,7 @@ mod templates_tests {
// set up the client. if we can't reload templates, then just quit
let client = Client::new(rocket()).unwrap();
let res = client.get("/is_reloading").dispatch();
let res = client.get("/is_reloading").dispatch().await;
if res.status() != Status::Ok {
return;
}
@ -160,7 +160,7 @@ mod templates_tests {
for _ in 0..6 {
// dispatch any request to trigger a template reload
client.get("/").dispatch();
client.get("/").dispatch().await;
// if the new content is correct, we are done
let new_rendered = Template::show(client.rocket(), RELOAD_TEMPLATE, ());
@ -169,6 +169,7 @@ mod templates_tests {
return;
}
// TODO.async: blocking call in async context
// otherwise, retry a few times, waiting 250ms in between
thread::sleep(Duration::from_millis(250));
}

View File

@ -28,4 +28,5 @@ version_check = "0.9.1"
[dev-dependencies]
rocket = { version = "0.5.0-dev", path = "../lib" }
compiletest_rs = "0.4"
futures-preview = "0.3.0-alpha.18"
compiletest_rs = { version = "0.3", features = ["stable"] }

View File

@ -0,0 +1,41 @@
use proc_macro::{TokenStream, Span};
use devise::{syn, Result};
use crate::syn_ext::syn_to_diag;
fn parse_input(input: TokenStream) -> Result<syn::ItemFn> {
let function: syn::ItemFn = syn::parse(input).map_err(syn_to_diag)
.map_err(|diag| diag.help("`#[async_test]` can only be applied to async functions"))?;
if function.sig.asyncness.is_none() {
return Err(Span::call_site().error("`#[async_test]` can only be applied to async functions"))
}
// TODO.async: verify of the form `async fn name(/* no args */) -> R`
Ok(function)
}
pub fn _async_test(_args: TokenStream, input: TokenStream) -> Result<TokenStream> {
let function = parse_input(input)?;
let attrs = &function.attrs;
let vis = &function.vis;
let name = &function.sig.ident;
let output = &function.sig.output;
let body = &function.block;
Ok(quote! {
#[test]
#(#attrs)*
#vis fn #name() #output {
rocket::async_test(async move {
#body
})
}
}.into())
}
pub fn async_test_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
_async_test(args, input).unwrap_or_else(|d| { d.emit(); TokenStream::new() })
}

View File

@ -1,3 +1,4 @@
pub mod async_test;
pub mod catch;
pub mod route;
pub mod segments;

View File

@ -399,6 +399,11 @@ pub fn catch(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::catch::catch_attribute(args, input))
}
#[proc_macro_attribute]
pub fn async_test(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::async_test::async_test_attribute(args, input))
}
/// Derive for the [`FromFormValue`] trait.
///
/// The [`FromFormValue`] derive can be applied to enums with nullary

View File

@ -85,6 +85,7 @@ fn run_mode(mode: &'static str, path: &'static str) {
config.clean_rmeta();
config.target_rustcflags = Some([
String::from("--edition=2018"),
link_flag("-L", "crate", &[]),
link_flag("-L", "dependency", &["deps"]),
extern_dep("rocket_http", Kind::Static).expect("find http dep"),

View File

@ -33,19 +33,19 @@ macro_rules! foo {
// regression test for `#[get] panicking if used inside a macro
foo!("/hello/<name>", name);
#[test]
fn test_reexpansion() {
#[rocket::async_test]
async fn test_reexpansion() {
let rocket = rocket::ignite().mount("/", routes![easy, hard, hi]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/easy/327").dispatch();
assert_eq!(response.body_string().unwrap(), "easy id: 327");
let mut response = client.get("/easy/327").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "easy id: 327");
let mut response = client.get("/hard/72").dispatch();
assert_eq!(response.body_string().unwrap(), "hard id: 72");
let mut response = client.get("/hard/72").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "hard id: 72");
let mut response = client.get("/hello/fish").dispatch();
assert_eq!(response.body_string().unwrap(), "fish");
let mut response = client.get("/hello/fish").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "fish");
}
macro_rules! index {
@ -59,11 +59,11 @@ macro_rules! index {
index!(i32);
#[test]
fn test_index() {
#[rocket::async_test]
async fn test_index() {
let rocket = rocket::ignite().mount("/", routes![index]).manage(100i32);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string().unwrap(), "Thing: 100");
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "Thing: 100");
}

View File

@ -21,43 +21,47 @@ pub enum Foo<'r> {
},
}
#[test]
fn responder_foo() {
#[rocket::async_test]
async fn responder_foo() {
let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/");
let req = local_req.inner();
let mut response = Foo::First("hello".into())
.respond_to(req)
.await
.expect("response okay");
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain));
assert_eq!(response.body_string(), Some("hello".into()));
assert_eq!(response.body_string().await, Some("hello".into()));
let mut response = Foo::Second("just a test".into())
.respond_to(req)
.await
.expect("response okay");
assert_eq!(response.status(), Status::InternalServerError);
assert_eq!(response.content_type(), Some(ContentType::Binary));
assert_eq!(response.body_string(), Some("just a test".into()));
assert_eq!(response.body_string().await, Some("just a test".into()));
let mut response = Foo::Third { responder: "well, hi", ct: ContentType::JSON }
.respond_to(req)
.await
.expect("response okay");
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.content_type(), Some(ContentType::HTML));
assert_eq!(response.body_string(), Some("well, hi".into()));
assert_eq!(response.body_string().await, Some("well, hi".into()));
let mut response = Foo::Fourth { string: "goodbye", ct: ContentType::JSON }
.respond_to(req)
.await
.expect("response okay");
assert_eq!(response.status(), Status::raw(105));
assert_eq!(response.content_type(), Some(ContentType::JSON));
assert_eq!(response.body_string(), Some("goodbye".into()));
assert_eq!(response.body_string().await, Some("goodbye".into()));
}
#[derive(Responder)]
@ -70,8 +74,8 @@ pub struct Bar<'r> {
_yet_another: String,
}
#[test]
fn responder_bar() {
#[rocket::async_test]
async fn responder_bar() {
let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/");
let req = local_req.inner();
@ -81,11 +85,11 @@ fn responder_bar() {
other: ContentType::HTML,
third: Cookie::new("cookie", "here!"),
_yet_another: "uh..hi?".into()
}.respond_to(req).expect("response okay");
}.respond_to(req).await.expect("response okay");
assert_eq!(response.status(), Status::InternalServerError);
assert_eq!(response.content_type(), Some(ContentType::Plain));
assert_eq!(response.body_string(), Some("foo foo".into()));
assert_eq!(response.body_string().await, Some("foo foo".into()));
assert_eq!(response.headers().get_one("Set-Cookie"), Some("cookie=here!"));
}
@ -95,17 +99,18 @@ pub struct Baz {
responder: &'static str,
}
#[test]
fn responder_baz() {
#[rocket::async_test]
async fn responder_baz() {
let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/");
let req = local_req.inner();
let mut response = Baz { responder: "just a custom" }
.respond_to(req)
.await
.expect("response okay");
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::new("application", "x-custom")));
assert_eq!(response.body_string(), Some("just a custom".into()));
assert_eq!(response.body_string().await, Some("just a custom".into()));
}

View File

@ -2,8 +2,6 @@
#[macro_use] extern crate rocket;
use std::io::Read;
use rocket::{Request, Data, Outcome::*};
use rocket::local::Client;
use rocket::request::Form;
@ -22,13 +20,19 @@ struct Simple(String);
impl FromDataSimple for Simple {
type Error = ();
fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> {
let mut string = String::new();
if let Err(_) = data.open().take(64).read_to_string(&mut string) {
return Failure((Status::InternalServerError, ()));
}
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
Box::pin(async {
use futures::io::AsyncReadExt as _;
use rocket::AsyncReadExt as _;
Success(Simple(string))
let mut string = String::new();
let mut stream = data.open().take(64);
if let Err(_) = stream.read_to_string(&mut string).await {
return Failure((Status::InternalServerError, ()));
}
Success(Simple(string))
})
}
}
@ -38,21 +42,21 @@ fn form(form: Form<Inner<'_>>) -> String { form.field.url_decode_lossy() }
#[post("/s", data = "<simple>")]
fn simple(simple: Simple) -> String { simple.0 }
#[test]
fn test_data() {
#[rocket::async_test]
async fn test_data() {
let rocket = rocket::ignite().mount("/", routes![form, simple]);
let client = Client::new(rocket).unwrap();
let mut response = client.post("/f")
.header(ContentType::Form)
.body("field=this%20is%20here")
.dispatch();
.dispatch().await;
assert_eq!(response.body_string().unwrap(), "this is here");
assert_eq!(response.body_string().await.unwrap(), "this is here");
let mut response = client.post("/s").body("this is here").dispatch();
assert_eq!(response.body_string().unwrap(), "this is here");
let mut response = client.post("/s").body("this is here").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "this is here");
let mut response = client.post("/s").body("this%20is%20here").dispatch();
assert_eq!(response.body_string().unwrap(), "this%20is%20here");
let mut response = client.post("/s").body("this%20is%20here").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "this%20is%20here");
}

View File

@ -33,36 +33,36 @@ fn binary() -> &'static str { "binary" }
#[get("/", rank = 3)]
fn other() -> &'static str { "other" }
#[test]
fn test_formats() {
#[rocket::async_test]
async fn test_formats() {
let rocket = rocket::ignite()
.mount("/", routes![json, xml, json_long, msgpack_long, msgpack,
plain, binary, other]);
let client = Client::new(rocket).unwrap();
let mut response = client.post("/").header(ContentType::JSON).dispatch();
assert_eq!(response.body_string().unwrap(), "json");
let mut response = client.post("/").header(ContentType::JSON).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "json");
let mut response = client.post("/").header(ContentType::MsgPack).dispatch();
assert_eq!(response.body_string().unwrap(), "msgpack_long");
let mut response = client.post("/").header(ContentType::MsgPack).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "msgpack_long");
let mut response = client.post("/").header(ContentType::XML).dispatch();
assert_eq!(response.body_string().unwrap(), "xml");
let mut response = client.post("/").header(ContentType::XML).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "xml");
let mut response = client.get("/").header(Accept::Plain).dispatch();
assert_eq!(response.body_string().unwrap(), "plain");
let mut response = client.get("/").header(Accept::Plain).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "plain");
let mut response = client.get("/").header(Accept::Binary).dispatch();
assert_eq!(response.body_string().unwrap(), "binary");
let mut response = client.get("/").header(Accept::Binary).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "binary");
let mut response = client.get("/").header(ContentType::JSON).dispatch();
assert_eq!(response.body_string().unwrap(), "plain");
let mut response = client.get("/").header(ContentType::JSON).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "plain");
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string().unwrap(), "plain");
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "plain");
let response = client.put("/").header(ContentType::HTML).dispatch();
let response = client.put("/").header(ContentType::HTML).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}
@ -80,8 +80,8 @@ fn get_bar_baz() -> &'static str { "get_bar_baz" }
#[put("/", format = "bar/baz")]
fn put_bar_baz() -> &'static str { "put_bar_baz" }
#[test]
fn test_custom_formats() {
#[rocket::async_test]
async fn test_custom_formats() {
let rocket = rocket::ignite()
.mount("/", routes![get_foo, post_foo, get_bar_baz, put_bar_baz]);
@ -92,24 +92,24 @@ fn test_custom_formats() {
let bar_baz_ct = ContentType::new("bar", "baz");
let bar_baz_a = Accept::new(&[MediaType::new("bar", "baz").into()]);
let mut response = client.get("/").header(foo_a).dispatch();
assert_eq!(response.body_string().unwrap(), "get_foo");
let mut response = client.get("/").header(foo_a).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "get_foo");
let mut response = client.post("/").header(foo_ct).dispatch();
assert_eq!(response.body_string().unwrap(), "post_foo");
let mut response = client.post("/").header(foo_ct).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "post_foo");
let mut response = client.get("/").header(bar_baz_a).dispatch();
assert_eq!(response.body_string().unwrap(), "get_bar_baz");
let mut response = client.get("/").header(bar_baz_a).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "get_bar_baz");
let mut response = client.put("/").header(bar_baz_ct).dispatch();
assert_eq!(response.body_string().unwrap(), "put_bar_baz");
let mut response = client.put("/").header(bar_baz_ct).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "put_bar_baz");
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string().unwrap(), "get_foo");
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "get_foo");
let response = client.put("/").header(ContentType::HTML).dispatch();
let response = client.put("/").header(ContentType::HTML).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let response = client.post("/").header(ContentType::HTML).dispatch();
let response = client.post("/").header(ContentType::HTML).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}

View File

@ -18,22 +18,22 @@ fn get2(_number: u32) -> &'static str { "2" }
#[get("/<_number>", rank = 3)]
fn get3(_number: u64) -> &'static str { "3" }
#[test]
fn test_ranking() {
#[rocket::async_test]
async fn test_ranking() {
let rocket = rocket::ignite().mount("/", routes![get0, get1, get2, get3]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/0").dispatch();
assert_eq!(response.body_string().unwrap(), "0");
let mut response = client.get("/0").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "0");
let mut response = client.get(format!("/{}", 1 << 8)).dispatch();
assert_eq!(response.body_string().unwrap(), "1");
let mut response = client.get(format!("/{}", 1 << 8)).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "1");
let mut response = client.get(format!("/{}", 1 << 16)).dispatch();
assert_eq!(response.body_string().unwrap(), "2");
let mut response = client.get(format!("/{}", 1 << 16)).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "2");
let mut response = client.get(format!("/{}", 1u64 << 32)).dispatch();
assert_eq!(response.body_string().unwrap(), "3");
let mut response = client.get(format!("/{}", 1u64 << 32)).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "3");
}
// Test a collision due to same auto rank.

View File

@ -28,11 +28,16 @@ struct Simple(String);
impl FromDataSimple for Simple {
type Error = ();
fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> {
use std::io::Read;
let mut string = String::new();
data.open().take(64).read_to_string(&mut string).unwrap();
Success(Simple(string))
fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
Box::pin(async move {
use futures::io::AsyncReadExt as _;
use rocket::AsyncReadExt as _;
let mut string = String::new();
let mut stream = data.open().take(64);
stream.read_to_string(&mut string).await.unwrap();
Success(Simple(string))
})
}
}
@ -75,8 +80,8 @@ fn post2(
fn test_unused_params(_unused_param: String, _unused_query: String, _unused_data: Data) {
}
#[test]
fn test_full_route() {
#[rocket::async_test]
async fn test_full_route() {
let rocket = rocket::ignite()
.mount("/1", routes![post1])
.mount("/2", routes![post2]);
@ -95,30 +100,30 @@ fn test_full_route() {
let uri = format!("{}{}", path_part, query_part);
let expected_uri = format!("{}?sky=blue&sky={}&{}", path_part, sky, query);
let response = client.post(&uri).body(simple).dispatch();
let response = client.post(&uri).body(simple).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let response = client.post(format!("/1{}", uri)).body(simple).dispatch();
let response = client.post(format!("/1{}", uri)).body(simple).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let mut response = client
.post(format!("/1{}", uri))
.header(ContentType::JSON)
.body(simple)
.dispatch();
.dispatch().await;
assert_eq!(response.body_string().unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
assert_eq!(response.body_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
sky, name, "A A", "inside", path, simple, expected_uri));
let response = client.post(format!("/2{}", uri)).body(simple).dispatch();
let response = client.post(format!("/2{}", uri)).body(simple).dispatch().await;
assert_eq!(response.status(), Status::NotFound);
let mut response = client
.post(format!("/2{}", uri))
.header(ContentType::JSON)
.body(simple)
.dispatch();
.dispatch().await;
assert_eq!(response.body_string().unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
assert_eq!(response.body_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
sky, name, "A A", "inside", path, simple, expected_uri));
}

View File

@ -152,6 +152,6 @@ pub fn custom(config: config::Config) -> Rocket {
// TODO.async: More thoughtful plan for async tests
/// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)]
pub fn async_test(fut: impl std::future::Future<Output = ()> + Send + 'static) {
pub fn async_test<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
tokio::runtime::Runtime::new().expect("create tokio runtime").block_on(fut)
}

View File

@ -55,11 +55,13 @@ use crate::error::LaunchError;
/// ```rust
/// use rocket::local::Client;
///
/// # let _ = async {
/// let rocket = rocket::ignite();
/// let client = Client::new(rocket).expect("valid rocket");
/// let response = client.post("/")
/// .body("Hello, world!")
/// .dispatch();
/// .dispatch().await;
/// # };
/// ```
///
/// [`new()`]: #method.new

View File

@ -44,8 +44,10 @@
//! # let rocket = rocket::ignite();
//! # let client = Client::new(rocket).unwrap();
//! # let req = client.get("/");
//! let response = req.dispatch();
//! # let _ = async {
//! let response = req.dispatch().await;
//! # let _ = response;
//! # };
//! ```
//!
//! All together and in idiomatic fashion, this might look like:
@ -53,11 +55,13 @@
//! ```rust
//! use rocket::local::Client;
//!
//! # let _ = async {
//! let client = Client::new(rocket::ignite()).expect("valid rocket");
//! let response = client.post("/")
//! .body("Hello, world!")
//! .dispatch();
//! .dispatch().await;
//! # let _ = response;
//! # };
//! ```
//!
//! # Unit/Integration Testing
@ -82,15 +86,15 @@
//! use super::{rocket, hello};
//! use rocket::local::Client;
//!
//! #[test]
//! #[rocket::async_test]
//! fn test_hello_world() {
//! // Construct a client to use for dispatching requests.
//! let rocket = rocket::ignite().mount("/", routes![hello]);
//! let client = Client::new(rocket).expect("valid rocket instance");
//!
//! // Dispatch a request to 'GET /' and validate the response.
//! let mut response = client.get("/").dispatch();
//! assert_eq!(response.body_string(), Some("Hello, world!".into()));
//! let mut response = client.get("/").dispatch().await;
//! assert_eq!(response.body_string().await, Some("Hello, world!".into()));
//! }
//! }
//! ```

View File

@ -67,10 +67,6 @@ use crate::local::Client;
/// [`mut_dispatch`]: #method.mut_dispatch
pub struct LocalRequest<'c> {
client: &'c Client,
// This pointer exists to access the `Arc<Request>` mutably inside of
// `LocalRequest`. This is the only place that a `Request` can be accessed
// mutably. This is accomplished via the private `request_mut()` method.
ptr: *mut Request<'c>,
// This `Arc` exists so that we can transfer ownership to the `LocalResponse`
// selectively on dispatch. This is necessary because responses may point
// into the request, and thus the request and all of its data needs to be
@ -118,9 +114,8 @@ impl<'c> LocalRequest<'c> {
}
// See the comments on the structure for what's going on here.
let mut request = Arc::new(request);
let ptr = Arc::get_mut(&mut request).unwrap() as *mut Request<'_>;
LocalRequest { client, ptr, request, uri, data: vec![] }
let request = Arc::new(request);
LocalRequest { client, request, uri, data: vec![] }
}
/// Retrieves the inner `Request` as seen by Rocket.
@ -142,7 +137,7 @@ impl<'c> LocalRequest<'c> {
#[inline(always)]
fn request_mut(&mut self) -> &mut Request<'c> {
// See the comments in the structure for the argument of correctness.
unsafe { &mut *self.ptr }
Arc::get_mut(&mut self.request).expect("mutable aliasing!")
}
// This method should _never_ be publicly exposed!
@ -152,7 +147,7 @@ impl<'c> LocalRequest<'c> {
// Additionally, the caller must ensure that the owned instance of
// `Arc<Request>` remains valid as long as the returned reference can be
// accessed.
unsafe { &mut *self.ptr }
unsafe { &mut *(self.request_mut() as *mut _) }
}
/// Add a header to this request.
@ -351,9 +346,9 @@ impl<'c> LocalRequest<'c> {
/// let response = client.get("/").dispatch();
/// ```
#[inline(always)]
pub fn dispatch(mut self) -> LocalResponse<'c> {
pub async fn dispatch(mut self) -> LocalResponse<'c> {
let r = self.long_lived_request();
LocalRequest::_dispatch(self.client, r, self.request, &self.uri, self.data)
LocalRequest::_dispatch(self.client, r, self.request, &self.uri, self.data).await
}
/// Dispatches the request, returning the response.
@ -375,22 +370,28 @@ impl<'c> LocalRequest<'c> {
/// ```rust
/// use rocket::local::Client;
///
/// let client = Client::new(rocket::ignite()).unwrap();
/// rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).unwrap();
///
/// let mut req = client.get("/");
/// let response_a = req.mut_dispatch();
/// let response_b = req.mut_dispatch();
/// let mut req = client.get("/");
/// let response_a = req.mut_dispatch().await;
/// // TODO.async: Annoying. Is this really a good example to show?
/// drop(response_a);
/// let response_b = req.mut_dispatch().await;
/// })
/// ```
#[inline(always)]
pub fn mut_dispatch(&mut self) -> LocalResponse<'c> {
pub async fn mut_dispatch(&mut self) -> LocalResponse<'c> {
let req = self.long_lived_request();
let data = std::mem::replace(&mut self.data, vec![]);
let rc_req = self.request.clone();
LocalRequest::_dispatch(self.client, req, rc_req, &self.uri, data)
LocalRequest::_dispatch(self.client, req, rc_req, &self.uri, data).await
}
// Performs the actual dispatch.
fn _dispatch(
// TODO.async: @jebrosen suspects there might be actual UB in here after all,
// and now we just went and mixed threads into it
async fn _dispatch(
client: &'c Client,
request: &'c mut Request<'c>,
owned_request: Arc<Request<'c>>,
@ -405,38 +406,34 @@ impl<'c> LocalRequest<'c> {
request.set_uri(uri.into_owned());
} else {
error!("Malformed request URI: {}", uri);
return tokio::runtime::Runtime::new().expect("create runtime").block_on(async move {
let res = client.rocket().handle_error(Status::BadRequest, request).await;
LocalResponse { _request: owned_request, response: res }
})
let res = client.rocket().handle_error(Status::BadRequest, request).await;
return LocalResponse { _request: owned_request, response: res };
}
tokio::runtime::Runtime::new().expect("create runtime").block_on(async move {
// Actually dispatch the request.
let response = client.rocket().dispatch(request, Data::local(data)).await;
// Actually dispatch the request.
let response = client.rocket().dispatch(request, Data::local(data)).await;
// If the client is tracking cookies, updates the internal cookie jar
// with the changes reflected by `response`.
if let Some(ref jar) = client.cookies {
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
// If the client is tracking cookies, updates the internal cookie jar
// with the changes reflected by `response`.
if let Some(ref jar) = client.cookies {
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
let current_time = time::OffsetDateTime::now_utc();
for cookie in response.cookies() {
if let Some(expires) = cookie.expires() {
if expires <= current_time {
jar.force_remove(cookie);
continue;
}
for cookie in response.cookies() {
if let Some(expires) = cookie.expires() {
if expires <= current_time {
jar.force_remove(cookie);
continue;
}
jar.add(cookie.into_owned());
}
}
LocalResponse {
_request: owned_request,
response: response
jar.add(cookie.into_owned());
}
})
}
LocalResponse {
_request: owned_request,
response: response
}
}
}
@ -458,16 +455,6 @@ pub struct LocalResponse<'c> {
response: Response<'c>,
}
impl LocalResponse<'_> {
pub fn body_string_wait(&mut self) -> Option<String> {
tokio::runtime::Runtime::new().expect("create runtime").block_on(self.body_string())
}
pub fn body_bytes_wait(&mut self) -> Option<Vec<u8>> {
tokio::runtime::Runtime::new().expect("create runtime").block_on(self.body_bytes())
}
}
impl<'c> Deref for LocalResponse<'c> {
type Target = Response<'c>;
@ -490,20 +477,17 @@ impl fmt::Debug for LocalResponse<'_> {
}
}
impl<'c> Clone for LocalRequest<'c> {
fn clone(&self) -> LocalRequest<'c> {
// Don't alias the existing `Request`. See #1312.
let mut request = Rc::new(self.inner().clone());
let ptr = Rc::get_mut(&mut request).unwrap() as *mut Request<'_>;
LocalRequest {
ptr, request,
client: self.client,
data: self.data.clone(),
uri: self.uri.clone()
}
}
}
// TODO.async: Figure out a way to accomplish this
//impl<'c> Clone for LocalRequest<'c> {
// fn clone(&self) -> LocalRequest<'c> {
// LocalRequest {
// client: self.client,
// request: self.request.clone(),
// data: self.data.clone(),
// uri: self.uri.clone()
// }
// }
//}
#[cfg(test)]
mod tests {

View File

@ -346,7 +346,7 @@ impl<'r> ResponseBuilder<'r> {
///
/// ```rust,ignore
/// use rocket::Response;
/// use futures::compat::{AsyncRead01CompatExt, Future01CompatExt};
/// use futures_tokio_compat::Compat as TokioCompat;
/// use tokio::fs::File;
/// # use std::io;
///
@ -354,7 +354,7 @@ impl<'r> ResponseBuilder<'r> {
/// # async fn test() -> io::Result<()> {
/// # #[allow(unused_variables)]
/// let response = Response::build()
/// .sized_body(File::open("body.txt").compat().await?.compat())
/// .sized_body(TokioCompat::new(File::open("body.txt").await?))
/// .finalize();
/// # Ok(())
/// # }
@ -373,7 +373,7 @@ impl<'r> ResponseBuilder<'r> {
///
/// ```rust
/// use rocket::Response;
/// use futures::compat::{AsyncRead01CompatExt, Future01CompatExt};
/// use futures_tokio_compat::Compat as TokioCompat;
/// use tokio::fs::File;
/// # use std::io;
///
@ -381,7 +381,7 @@ impl<'r> ResponseBuilder<'r> {
/// # async fn test() -> io::Result<()> {
/// # #[allow(unused_variables)]
/// let response = Response::build()
/// .streamed_body(File::open("body.txt").compat().await?.compat())
/// .streamed_body(TokioCompat::new(File::open("body.txt").await?))
/// .finalize();
/// # Ok(())
/// # }
@ -401,7 +401,7 @@ impl<'r> ResponseBuilder<'r> {
///
/// ```rust
/// use rocket::Response;
/// use futures::compat::{AsyncRead01CompatExt, Future01CompatExt};
/// use futures_tokio_compat::Compat as TokioCompat;
/// use tokio::fs::File;
/// # use std::io;
///
@ -409,7 +409,7 @@ impl<'r> ResponseBuilder<'r> {
/// # async fn test() -> io::Result<()> {
/// # #[allow(unused_variables)]
/// let response = Response::build()
/// .chunked_body(File::open("body.txt").compat().await?.compat(), 8096)
/// .chunked_body(TokioCompat::new(File::open("body.txt").await?), 8096)
/// .finalize();
/// # Ok(())
/// # }

View File

@ -18,16 +18,16 @@ mod test_absolute_uris_okay {
use super::*;
use rocket::local::Client;
#[test]
fn redirect_works() {
#[rocket::async_test]
async fn redirect_works() {
let rocket = rocket::ignite().mount("/", routes![google, rocket]);
let client = Client::new(rocket).unwrap();
let response = client.get("/google").dispatch();
let response = client.get("/google").dispatch().await;
let location = response.headers().get_one("Location");
assert_eq!(location, Some("https://www.google.com"));
let response = client.get("/rocket").dispatch();
let response = client.get("/rocket").dispatch().await;
let location = response.headers().get_one("Location");
assert_eq!(location, Some("https://rocket.rs:80"));
}

View File

@ -19,16 +19,16 @@ mod conditionally_set_server_header {
use super::*;
use rocket::local::Client;
#[test]
fn do_not_overwrite_server_header() {
#[rocket::async_test]
async fn do_not_overwrite_server_header() {
let rocket = rocket::ignite().mount("/", routes![do_not_overwrite, use_default]);
let client = Client::new(rocket).unwrap();
let response = client.get("/do_not_overwrite").dispatch();
let response = client.get("/do_not_overwrite").dispatch().await;
let server = response.headers().get_one("Server");
assert_eq!(server, Some("Test"));
let response = client.get("/use_default").dispatch();
let response = client.get("/use_default").dispatch().await;
let server = response.headers().get_one("Server");
assert_eq!(server, Some("Rocket"));
}

View File

@ -43,16 +43,16 @@ fn number(params: Form<ThingForm>) -> DerivedResponder {
DerivedResponder { data: params.thing.to_string() }
}
#[test]
fn test_derive_reexports() {
#[rocket::async_test]
async fn test_derive_reexports() {
use rocket::local::Client;
let rocket = rocket::ignite().mount("/", routes![index, number]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait().unwrap(), "hello");
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "hello");
let mut response = client.get("/?thing=b").dispatch();
assert_eq!(response.body_string_wait().unwrap(), "b");
let mut response = client.get("/?thing=b").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "b");
}

View File

@ -26,8 +26,8 @@ mod fairing_before_head_strip {
use rocket::http::Status;
use rocket::State;
#[test]
fn not_auto_handled() {
#[rocket::async_test]
async fn not_auto_handled() {
let rocket = rocket::ignite()
.mount("/", routes![head])
.attach(AdHoc::on_request("Check HEAD", |req, _| {
@ -41,13 +41,13 @@ mod fairing_before_head_strip {
}));
let client = Client::new(rocket).unwrap();
let mut response = client.head("/").dispatch();
let mut response = client.head("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert!(response.body().is_none());
}
#[test]
fn auto_handled() {
#[rocket::async_test]
async fn auto_handled() {
#[derive(Default)]
struct Counter(AtomicUsize);
@ -70,7 +70,7 @@ mod fairing_before_head_strip {
}));
let client = Client::new(rocket).unwrap();
let mut response = client.head("/").dispatch();
let mut response = client.head("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert!(response.body().is_none());
}

View File

@ -26,37 +26,37 @@ mod flash_lazy_remove_tests {
use rocket::local::Client;
use rocket::http::Status;
#[test]
fn test() {
#[rocket::async_test]
async fn test() {
use super::*;
let r = rocket::ignite().mount("/", routes![set, unused, used]);
let client = Client::new(r).unwrap();
// Ensure the cookie's not there at first.
let response = client.get("/unused").dispatch();
let response = client.get("/unused").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
// Set the flash cookie.
client.post("/").dispatch();
client.post("/").dispatch().await;
// Try once.
let response = client.get("/unused").dispatch();
let response = client.get("/unused").dispatch().await;
assert_eq!(response.status(), Status::Ok);
// Try again; should still be there.
let response = client.get("/unused").dispatch();
let response = client.get("/unused").dispatch().await;
assert_eq!(response.status(), Status::Ok);
// Now use it.
let mut response = client.get("/use").dispatch();
assert_eq!(response.body_string_wait(), Some(FLASH_MESSAGE.into()));
let mut response = client.get("/use").dispatch().await;
assert_eq!(response.body_string().await, Some(FLASH_MESSAGE.into()));
// Now it should be gone.
let response = client.get("/unused").dispatch();
let response = client.get("/unused").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
// Still gone.
let response = client.get("/use").dispatch();
let response = client.get("/use").dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}
}

View File

@ -20,24 +20,24 @@ mod tests {
use rocket::local::Client;
use rocket::http::{Status, ContentType};
#[test]
fn method_eval() {
#[rocket::async_test]
async fn method_eval() {
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
let mut response = client.post("/")
.header(ContentType::Form)
.body("_method=patch&form_data=Form+data")
.dispatch();
.dispatch().await;
assert_eq!(response.body_string_wait(), Some("OK".into()));
assert_eq!(response.body_string().await, Some("OK".into()));
}
#[test]
fn get_passes_through() {
#[rocket::async_test]
async fn get_passes_through() {
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
let response = client.get("/")
.header(ContentType::Form)
.body("_method=patch&form_data=Form+data")
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}

View File

@ -20,25 +20,25 @@ mod tests {
use rocket::http::ContentType;
use rocket::http::Status;
fn check_decoding(raw: &str, decoded: &str) {
async fn check_decoding(raw: &str, decoded: &str) {
let client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
let mut response = client.post("/")
.header(ContentType::Form)
.body(format!("form_data={}", raw))
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(Some(decoded.to_string()), response.body_string_wait());
assert_eq!(Some(decoded.to_string()), response.body_string().await);
}
#[test]
fn test_proper_decoding() {
check_decoding("password", "password");
check_decoding("", "");
check_decoding("+", " ");
check_decoding("%2B", "+");
check_decoding("1+1", "1 1");
check_decoding("1%2B1", "1+1");
check_decoding("%3Fa%3D1%26b%3D2", "?a=1&b=2");
#[rocket::async_test]
async fn test_proper_decoding() {
check_decoding("password", "password").await;
check_decoding("", "").await;
check_decoding("+", " ").await;
check_decoding("%2B", "+").await;
check_decoding("1+1", "1 1").await;
check_decoding("1%2B1", "1+1").await;
check_decoding("%3Fa%3D1%26b%3D2", "?a=1&b=2").await;
}
}

View File

@ -33,13 +33,11 @@ mod head_handling_tests {
routes![index, empty, other]
}
fn assert_empty_sized_body<T: futures::AsyncRead + Unpin>(body: Body<T>, expected_size: u64) {
async fn assert_empty_sized_body<T: futures::AsyncRead + Unpin>(body: Body<T>, expected_size: u64) {
match body {
Body::Sized(mut body, size) => {
let mut buffer = vec![];
tokio::runtime::Runtime::new().expect("create runtime").block_on(async {
body.read_to_end(&mut buffer).await.unwrap();
});
body.read_to_end(&mut buffer).await.unwrap();
assert_eq!(size, expected_size);
assert_eq!(buffer.len(), 0);
}
@ -47,27 +45,27 @@ mod head_handling_tests {
}
}
#[test]
fn auto_head() {
#[rocket::async_test]
async fn auto_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap();
let mut response = client.head("/").dispatch();
let mut response = client.head("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_empty_sized_body(response.body().unwrap(), 13);
assert_empty_sized_body(response.body().unwrap(), 13).await;
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
assert_eq!(content_type, vec![ContentType::Plain.to_string()]);
let mut response = client.head("/empty").dispatch();
let mut response = client.head("/empty").dispatch().await;
assert_eq!(response.status(), Status::NoContent);
assert!(response.body_bytes_wait().is_none());
assert!(response.body_bytes().await.is_none());
}
#[test]
fn user_head() {
#[rocket::async_test]
async fn user_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap();
let mut response = client.head("/other").dispatch();
let mut response = client.head("/other").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_empty_sized_body(response.body().unwrap(), 17);
assert_empty_sized_body(response.body().unwrap(), 17).await;
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
assert_eq!(content_type, vec![ContentType::JSON.to_string()]);

View File

@ -28,47 +28,47 @@ mod limits_tests {
rocket::custom(config).mount("/", routes![super::index])
}
#[test]
fn large_enough() {
#[rocket::async_test]
async fn large_enough() {
let client = Client::new(rocket_with_forms_limit(128)).unwrap();
let mut response = client.post("/")
.body("value=Hello+world")
.header(ContentType::Form)
.dispatch();
.dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello world".into()));
assert_eq!(response.body_string().await, Some("Hello world".into()));
}
#[test]
fn just_large_enough() {
#[rocket::async_test]
async fn just_large_enough() {
let client = Client::new(rocket_with_forms_limit(17)).unwrap();
let mut response = client.post("/")
.body("value=Hello+world")
.header(ContentType::Form)
.dispatch();
.dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello world".into()));
assert_eq!(response.body_string().await, Some("Hello world".into()));
}
#[test]
fn much_too_small() {
#[rocket::async_test]
async fn much_too_small() {
let client = Client::new(rocket_with_forms_limit(4)).unwrap();
let response = client.post("/")
.body("value=Hello+world")
.header(ContentType::Form)
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::UnprocessableEntity);
}
#[test]
fn contracted() {
#[rocket::async_test]
async fn contracted() {
let client = Client::new(rocket_with_forms_limit(10)).unwrap();
let mut response = client.post("/")
.body("value=Hello+world")
.header(ContentType::Form)
.dispatch();
.dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hell".into()));
assert_eq!(response.body_string().await, Some("Hell".into()));
}
}

View File

@ -60,33 +60,33 @@ mod local_request_content_type_tests {
rocket::ignite().mount("/", routes![rg_ct, data_has_ct, data_no_ct])
}
#[test]
fn has_no_ct() {
#[rocket::async_test]
async fn has_no_ct() {
let client = Client::new(rocket()).unwrap();
let mut req = client.post("/");
assert_eq!(req.clone().dispatch().body_string_wait(), Some("Absent".to_string()));
assert_eq!(req.mut_dispatch().body_string_wait(), Some("Absent".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Absent".to_string()));
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Absent".to_string()));
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Absent".to_string()));
assert_eq!(req.dispatch().await.body_string().await, Some("Absent".to_string()));
let mut req = client.post("/data");
assert_eq!(req.clone().dispatch().body_string_wait(), Some("Data Absent".to_string()));
assert_eq!(req.mut_dispatch().body_string_wait(), Some("Data Absent".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Data Absent".to_string()));
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Data Absent".to_string()));
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Absent".to_string()));
assert_eq!(req.dispatch().await.body_string().await, Some("Data Absent".to_string()));
}
#[test]
fn has_ct() {
#[rocket::async_test]
async fn has_ct() {
let client = Client::new(rocket()).unwrap();
let mut req = client.post("/").header(ContentType::JSON);
assert_eq!(req.clone().dispatch().body_string_wait(), Some("Present".to_string()));
assert_eq!(req.mut_dispatch().body_string_wait(), Some("Present".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Present".to_string()));
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Present".to_string()));
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Present".to_string()));
assert_eq!(req.dispatch().await.body_string().await, Some("Present".to_string()));
let mut req = client.post("/data").header(ContentType::JSON);
assert_eq!(req.clone().dispatch().body_string_wait(), Some("Data Present".to_string()));
assert_eq!(req.mut_dispatch().body_string_wait(), Some("Data Present".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Data Present".to_string()));
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Data Present".to_string()));
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Present".to_string()));
assert_eq!(req.dispatch().await.body_string().await, Some("Data Present".to_string()));
}
}

View File

@ -22,25 +22,25 @@ mod private_cookie_test {
use rocket::http::Cookie;
use rocket::http::Status;
#[test]
fn private_cookie_is_returned() {
#[rocket::async_test]
async fn private_cookie_is_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap();
let req = client.get("/").private_cookie(Cookie::new("cookie_name", "cookie_value"));
let mut response = req.dispatch();
let mut response = req.dispatch().await;
assert_eq!(response.body_string_wait(), Some("cookie_value".into()));
assert_eq!(response.body_string().await, Some("cookie_value".into()));
assert_eq!(response.headers().get_one("Set-Cookie"), None);
}
#[test]
fn regular_cookie_is_not_returned() {
#[rocket::async_test]
async fn regular_cookie_is_not_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap();
let req = client.get("/").cookie(Cookie::new("cookie_name", "cookie_value"));
let response = req.dispatch();
let response = req.dispatch().await;
assert_eq!(response.status(), Status::NotFound);
}

View File

@ -43,18 +43,18 @@ mod nested_fairing_attaches_tests {
use super::*;
use rocket::local::Client;
#[test]
fn test_counts() {
#[rocket::async_test]
async fn test_counts() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("1, 1".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("1, 1".into()));
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("1, 2".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("1, 2".into()));
client.get("/").dispatch();
client.get("/").dispatch();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("1, 5".into()));
client.get("/").dispatch().await;
client.get("/").dispatch().await;
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("1, 5".into()));
}
}

View File

@ -44,8 +44,8 @@ mod tests {
req.add_header(ct);
}
let mut response = req.dispatch();
let body_str = response.body_string_wait();
let mut response = req.dispatch().await;
let body_str = response.body_string().await;
let body: Option<&'static str> = $body;
match body {
Some(string) => assert_eq!(body_str, Some(string.to_string())),
@ -54,15 +54,15 @@ mod tests {
)
}
#[test]
fn exact_match_or_forward() {
#[rocket::async_test]
async fn exact_match_or_forward() {
check_dispatch!("/first", Some(ContentType::JSON), Some("specified"));
check_dispatch!("/first", None, Some("unspecified"));
check_dispatch!("/first", Some(ContentType::HTML), Some("unspecified"));
}
#[test]
fn exact_match_or_none() {
#[rocket::async_test]
async fn exact_match_or_none() {
check_dispatch!("/second", Some(ContentType::JSON), Some("specified_json"));
check_dispatch!("/second", Some(ContentType::HTML), Some("specified_html"));
check_dispatch!("/second", Some(ContentType::CSV), None);

View File

@ -14,10 +14,10 @@ mod tests {
use rocket::local::Client;
use rocket::http::Status;
#[test]
fn error_catcher_redirect() {
#[rocket::async_test]
async fn error_catcher_redirect() {
let client = Client::new(rocket::ignite().register(catchers![not_found])).unwrap();
let response = client.get("/unknown").dispatch();
let response = client.get("/unknown").dispatch().await;
println!("Response:\n{:?}", response);
let location: Vec<_> = response.headers().get("location").collect();

View File

@ -15,21 +15,21 @@ mod route_guard_tests {
use super::*;
use rocket::local::Client;
fn assert_path(client: &Client, path: &str) {
let mut res = client.get(path).dispatch();
assert_eq!(res.body_string_wait(), Some(path.into()));
async fn assert_path(client: &Client, path: &str) {
let mut res = client.get(path).dispatch().await;
assert_eq!(res.body_string().await, Some(path.into()));
}
#[test]
fn check_mount_path() {
#[rocket::async_test]
async fn check_mount_path() {
let rocket = rocket::ignite()
.mount("/first", routes![files])
.mount("/second", routes![files]);
let client = Client::new(rocket).unwrap();
assert_path(&client, "/first/some/path");
assert_path(&client, "/second/some/path");
assert_path(&client, "/first/second/b/c");
assert_path(&client, "/second/a/b/c");
assert_path(&client, "/first/some/path").await;
assert_path(&client, "/second/some/path").await;
assert_path(&client, "/first/second/b/c").await;
assert_path(&client, "/second/a/b/c").await;
}
}

View File

@ -33,8 +33,8 @@ mod tests {
use super::*;
use rocket::local::Client;
#[test]
fn segments_works() {
#[rocket::async_test]
async fn segments_works() {
let rocket = rocket::ignite()
.mount("/", routes![test, two, one_two, none, dual])
.mount("/point", routes![test, two, one_two, dual]);
@ -47,8 +47,8 @@ mod tests {
"/static", "/point/static"]
{
let path = "this/is/the/path/we/want";
let mut response = client.get(format!("{}/{}", prefix, path)).dispatch();
assert_eq!(response.body_string_wait(), Some(path.into()));
let mut response = client.get(format!("{}/{}", prefix, path)).dispatch().await;
assert_eq!(response.body_string().await, Some(path.into()));
}
}
}

View File

@ -31,42 +31,42 @@ mod strict_and_lenient_forms_tests {
Client::new(rocket::ignite().mount("/", routes![strict, lenient])).unwrap()
}
#[test]
fn test_strict_form() {
#[rocket::async_test]
async fn test_strict_form() {
let client = client();
let mut response = client.post("/strict")
.header(ContentType::Form)
.body(format!("field={}", FIELD_VALUE))
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(FIELD_VALUE.into()));
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
let response = client.post("/strict")
.header(ContentType::Form)
.body(format!("field={}&extra=whoops", FIELD_VALUE))
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::UnprocessableEntity);
}
#[test]
fn test_lenient_form() {
#[rocket::async_test]
async fn test_lenient_form() {
let client = client();
let mut response = client.post("/lenient")
.header(ContentType::Form)
.body(format!("field={}", FIELD_VALUE))
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(FIELD_VALUE.into()));
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
let mut response = client.post("/lenient")
.header(ContentType::Form)
.body(format!("field={}&extra=whoops", FIELD_VALUE))
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(FIELD_VALUE.into()));
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
}
}

View File

@ -32,28 +32,28 @@ mod tests {
use rocket::local::Client;
use rocket::http::{Status, uri::Uri};
#[test]
fn uri_percent_encoding_redirect() {
#[rocket::async_test]
async fn uri_percent_encoding_redirect() {
let expected_location = vec!["/hello/John%5B%5D%7C%5C%25@%5E"];
let client = Client::new(rocket()).unwrap();
let response = client.get("/raw").dispatch();
let response = client.get("/raw").dispatch().await;
let location: Vec<_> = response.headers().get("location").collect();
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(&location, &expected_location);
let response = client.get("/uri").dispatch();
let response = client.get("/uri").dispatch().await;
let location: Vec<_> = response.headers().get("location").collect();
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(&location, &expected_location);
}
#[test]
fn uri_percent_encoding_get() {
#[rocket::async_test]
async fn uri_percent_encoding_get() {
let client = Client::new(rocket()).unwrap();
let name = Uri::percent_encode(NAME);
let mut response = client.get(format!("/hello/{}", name)).dispatch();
let mut response = client.get(format!("/hello/{}", name)).dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait().unwrap(), format!("Hello, {}!", NAME));
assert_eq!(response.body_string().await.unwrap(), format!("Hello, {}!", NAME));
}
}

View File

@ -62,7 +62,9 @@ pub fn test_config(environment: Environment) {
}))
.mount("/", routes![check_config]);
let client = Client::new(rocket).unwrap();
let response = client.get("/check_config").dispatch();
assert_eq!(response.status(), Status::Ok);
rocket::async_test(async move {
let client = Client::new(rocket).unwrap();
let response = client.get("/check_config").dispatch().await;
assert_eq!(response.status(), Status::Ok);
})
}

View File

@ -2,7 +2,7 @@ use super::Person;
use rocket::http::{Accept, ContentType, Header, MediaType, Method, Status};
use rocket::local::Client;
fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
async fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
where H: Into<Header<'static>>
{
let rocket = rocket::ignite()
@ -10,36 +10,36 @@ fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
.register(catchers![super::not_found]);
let client = Client::new(rocket).unwrap();
let mut response = client.req(method, uri).header(header).dispatch();
let mut response = client.req(method, uri).header(header).dispatch().await;
assert_eq!(response.status(), status);
assert_eq!(response.body_string_wait(), Some(body));
assert_eq!(response.body_string().await, Some(body));
}
#[test]
fn test_hello() {
#[rocket::async_test]
async fn test_hello() {
let person = Person { name: "Michael".to_string(), age: 80, };
let body = serde_json::to_string(&person).unwrap();
test(Method::Get, "/hello/Michael/80", Accept::JSON, Status::Ok, body.clone());
test(Method::Get, "/hello/Michael/80", Accept::Any, Status::Ok, body.clone());
test(Method::Get, "/hello/Michael/80", Accept::JSON, Status::Ok, body.clone()).await;
test(Method::Get, "/hello/Michael/80", Accept::Any, Status::Ok, body.clone()).await;
// No `Accept` header is an implicit */*.
test(Method::Get, "/hello/Michael/80", ContentType::XML, Status::Ok, body);
test(Method::Get, "/hello/Michael/80", ContentType::XML, Status::Ok, body).await;
let person = Person { name: "".to_string(), age: 99, };
let body = serde_json::to_string(&person).unwrap();
test(Method::Post, "/hello/99", ContentType::Plain, Status::Ok, body);
test(Method::Post, "/hello/99", ContentType::Plain, Status::Ok, body).await;
}
#[test]
fn test_hello_invalid_content_type() {
#[rocket::async_test]
async fn test_hello_invalid_content_type() {
let b = format!("<p>'{}' requests are not supported.</p>", MediaType::HTML);
test(Method::Get, "/hello/Michael/80", Accept::HTML, Status::NotFound, b.clone());
test(Method::Post, "/hello/80", ContentType::HTML, Status::NotFound, b);
test(Method::Get, "/hello/Michael/80", Accept::HTML, Status::NotFound, b.clone()).await;
test(Method::Post, "/hello/80", ContentType::HTML, Status::NotFound, b).await;
}
#[test]
fn test_404() {
#[rocket::async_test]
async fn test_404() {
let body = "<p>Sorry, '/unknown' is an invalid path! Try \
/hello/&lt;name&gt;/&lt;age&gt; instead.</p>";
test(Method::Get, "/unknown", Accept::JSON, Status::NotFound, body.to_string());
test(Method::Get, "/unknown", Accept::JSON, Status::NotFound, body.to_string()).await;
}

View File

@ -5,13 +5,13 @@ use rocket::local::Client;
use rocket::http::*;
use rocket_contrib::templates::Template;
#[test]
fn test_submit() {
#[rocket::async_test]
async fn test_submit() {
let client = Client::new(rocket()).unwrap();
let response = client.post("/submit")
.header(ContentType::Form)
.body("message=Hello from Rocket!")
.dispatch();
.dispatch().await;
let cookie_headers: Vec<_> = response.headers().get("Set-Cookie").collect();
let location_headers: Vec<_> = response.headers().get("Location").collect();
@ -21,29 +21,29 @@ fn test_submit() {
assert_eq!(location_headers, vec!["/".to_string()]);
}
fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: String) {
async fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: String) {
// Attach a cookie if one is given.
let client = Client::new(rocket()).unwrap();
let mut response = match optional_cookie {
Some(cookie) => client.get("/").cookie(cookie).dispatch(),
None => client.get("/").dispatch(),
Some(cookie) => client.get("/").cookie(cookie).dispatch().await,
None => client.get("/").dispatch().await,
};
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected_body));
assert_eq!(response.body_string().await, Some(expected_body));
}
#[test]
fn test_index() {
#[rocket::async_test]
async fn test_index() {
let client = Client::new(rocket()).unwrap();
// Render the template with an empty context.
let mut context: HashMap<&str, &str> = HashMap::new();
let template = Template::show(client.rocket(), "index", &context).unwrap();
test_body(None, template);
test_body(None, template).await;
// Render the template with a context that contains the message.
context.insert("message", "Hello from Rocket!");
let template = Template::show(client.rocket(), "index", &context).unwrap();
test_body(Some(Cookie::new("message", "Hello from Rocket!")), template);
test_body(Some(Cookie::new("message", "Hello from Rocket!")), template).await;
}

View File

@ -1,31 +1,31 @@
use rocket::local::Client;
use rocket::http::Status;
fn test(uri: &str, status: Status, body: String) {
async fn test(uri: &str, status: Status, body: String) {
let rocket = rocket::ignite()
.mount("/", routes![super::hello])
.register(catchers![super::not_found]);
let client = Client::new(rocket).unwrap();
let mut response = client.get(uri).dispatch();
let mut response = client.get(uri).dispatch().await;
assert_eq!(response.status(), status);
assert_eq!(response.body_string_wait(), Some(body));
assert_eq!(response.body_string().await, Some(body));
}
#[test]
fn test_hello() {
#[rocket::async_test]
async fn test_hello() {
let (name, age) = ("Arthur", 42);
let uri = format!("/hello/{}/{}", name, age);
test(&uri, Status::Ok, format!("Hello, {} year old named {}!", age, name));
test(&uri, Status::Ok, format!("Hello, {} year old named {}!", age, name)).await;
}
#[test]
fn test_hello_invalid_age() {
#[rocket::async_test]
async fn test_hello_invalid_age() {
for &(name, age) in &[("Ford", -129), ("Trillian", 128)] {
let uri = format!("/hello/{}/{}", name, age);
let body = format!("<p>Sorry, but '{}' is not a valid path!</p>
<p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>",
uri);
test(&uri, Status::NotFound, body);
test(&uri, Status::NotFound, body).await;
}
}

View File

@ -1,38 +1,38 @@
use super::rocket;
use rocket::local::Client;
#[test]
fn rewrite_get_put() {
#[rocket::async_test]
async fn rewrite_get_put() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello, fairings!".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, fairings!".into()));
}
#[test]
fn counts() {
#[rocket::async_test]
async fn counts() {
let client = Client::new(rocket()).unwrap();
// Issue 1 GET request.
client.get("/").dispatch();
client.get("/").dispatch().await;
// Check the GET count, taking into account _this_ GET request.
let mut response = client.get("/counts").dispatch();
assert_eq!(response.body_string_wait(), Some("Get: 2\nPost: 0".into()));
let mut response = client.get("/counts").dispatch().await;
assert_eq!(response.body_string().await, Some("Get: 2\nPost: 0".into()));
// Issue 1 more GET request and a POST.
client.get("/").dispatch();
client.post("/").dispatch();
client.get("/").dispatch().await;
client.post("/").dispatch().await;
// Check the counts.
let mut response = client.get("/counts").dispatch();
assert_eq!(response.body_string_wait(), Some("Get: 4\nPost: 1".into()));
let mut response = client.get("/counts").dispatch().await;
assert_eq!(response.body_string().await, Some("Get: 4\nPost: 1".into()));
}
#[test]
fn token() {
#[rocket::async_test]
async fn token() {
let client = Client::new(rocket()).unwrap();
// Ensure the token is '123', which is what we have in `Rocket.toml`.
let mut res = client.get("/token").dispatch();
assert_eq!(res.body_string_wait(), Some("123".into()));
let mut res = client.get("/token").dispatch().await;
assert_eq!(res.body_string().await, Some("123".into()));
}

View File

@ -15,12 +15,14 @@ impl fmt::Display for FormOption {
}
fn assert_form_eq(client: &Client, form_str: &str, expected: String) {
let mut res = client.post("/")
.header(ContentType::Form)
.body(form_str)
.dispatch();
rocket::async_test(async move {
let mut res = client.post("/")
.header(ContentType::Form)
.body(form_str)
.dispatch().await;
assert_eq!(res.body_string_wait(), Some(expected));
assert_eq!(res.body_string().await, Some(expected));
})
}
fn assert_valid_form(client: &Client, input: &FormInput<'_>) {

View File

@ -3,20 +3,22 @@ use rocket::local::Client;
use rocket::http::{ContentType, Status};
fn test_login<T>(user: &str, pass: &str, age: &str, status: Status, body: T)
where T: Into<Option<&'static str>>
where T: Into<Option<&'static str>> + Send
{
let client = Client::new(rocket()).unwrap();
let query = format!("username={}&password={}&age={}", user, pass, age);
let mut response = client.post("/login")
.header(ContentType::Form)
.body(&query)
.dispatch();
rocket::async_test(async move {
let client = Client::new(rocket()).unwrap();
let query = format!("username={}&password={}&age={}", user, pass, age);
let mut response = client.post("/login")
.header(ContentType::Form)
.body(&query)
.dispatch().await;
assert_eq!(response.status(), status);
if let Some(expected_str) = body.into() {
let body_str = response.body_string_wait();
assert!(body_str.map_or(false, |s| s.contains(expected_str)));
}
assert_eq!(response.status(), status);
if let Some(expected_str) = body.into() {
let body_str = response.body_string().await;
assert!(body_str.map_or(false, |s| s.contains(expected_str)));
}
})
}
#[test]
@ -44,13 +46,15 @@ fn test_invalid_age() {
}
fn check_bad_form(form_str: &str, status: Status) {
let client = Client::new(rocket()).unwrap();
let response = client.post("/login")
.header(ContentType::Form)
.body(form_str)
.dispatch();
rocket::async_test(async {
let client = Client::new(rocket()).unwrap();
let response = client.post("/login")
.header(ContentType::Form)
.body(form_str)
.dispatch().await;
assert_eq!(response.status(), status);
assert_eq!(response.status(), status);
})
}
#[test]

View File

@ -8,12 +8,12 @@ use rocket_contrib::templates::Template;
macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({
let client = Client::new(rocket()).unwrap();
$test_fn(&client, client.req($method, $path).dispatch());
$test_fn(&client, client.req($method, $path).dispatch().await);
})
}
#[test]
fn test_root() {
#[rocket::async_test]
async fn test_root() {
// Check that the redirect works.
for method in &[Get, Head] {
dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| {
@ -33,13 +33,13 @@ fn test_root() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}
}
#[test]
fn test_name() {
#[rocket::async_test]
async fn test_name() {
// Check that the /hello/<name> route works.
dispatch!(Get, "/hello/Jack%20Daniels", |client: &Client, mut response: LocalResponse<'_>| {
let context = TemplateContext {
@ -51,12 +51,12 @@ fn test_name() {
let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}
#[test]
fn test_404() {
#[rocket::async_test]
async fn test_404() {
// Check that the error catcher works.
dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| {
let mut map = std::collections::HashMap::new();
@ -64,6 +64,6 @@ fn test_404() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}

View File

@ -1,9 +0,0 @@
[package]
name = "hello_2015"
version = "0.0.0"
workspace = "../../"
edition = "2015"
publish = false
[dependencies]
rocket = { path = "../../core/lib" }

View File

@ -1,14 +0,0 @@
#![feature(proc_macro_hygiene)]
#[macro_use] extern crate rocket;
#[cfg(test)] mod tests;
#[get("/")]
fn hello() -> &'static str {
"Hello, Rust 2015!"
}
fn main() {
rocket::ignite().mount("/", routes![hello]).launch();
}

View File

@ -1,50 +0,0 @@
use rocket::{self, routes, local::Client};
#[test]
fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello, Rust 2015!".into()));
}
// Tests unrelated to the example.
mod scoped_uri_tests {
use rocket::{get, routes};
mod inner {
use rocket::uri;
#[rocket::get("/")]
pub fn hello() -> String {
format!("Hello! Try {}.", uri!(super::hello_name: "Rust 2015"))
}
}
#[get("/<name>")]
fn hello_name(name: String) -> String {
format!("Hello, {}! This is {}.", name, rocket::uri!(hello_name: &name))
}
fn rocket() -> rocket::Rocket {
rocket::ignite()
.mount("/", routes![hello_name])
.mount("/", rocket::routes![inner::hello])
}
use rocket::local::Client;
#[test]
fn test_inner_hello() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello! Try /Rust%202015.".into()));
}
#[test]
fn test_hello_name() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/Rust%202015").dispatch();
assert_eq!(response.body_string_wait().unwrap(), "Hello, Rust 2015! This is /Rust%202015.");
}
}

View File

@ -1,11 +1,11 @@
use rocket::{self, routes, local::Client};
#[test]
fn hello_world() {
#[rocket::async_test]
async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello, Rust 2018!".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into()));
}
// Tests unrelated to the example.
@ -34,17 +34,17 @@ mod scoped_uri_tests {
use rocket::local::Client;
#[test]
fn test_inner_hello() {
#[rocket::async_test]
async fn test_inner_hello() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello! Try /Rust%202018.".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello! Try /Rust%202018.".into()));
}
#[test]
fn test_hello_name() {
#[rocket::async_test]
async fn test_hello_name() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/Rust%202018").dispatch();
assert_eq!(response.body_string_wait().unwrap(), "Hello, Rust 2018! This is /Rust%202018.");
let mut response = client.get("/Rust%202018").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "Hello, Rust 2018! This is /Rust%202018.");
}
}

View File

@ -5,34 +5,34 @@ fn client() -> Client {
Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).unwrap()
}
fn test(uri: &str, expected: String) {
async fn test(uri: String, expected: String) {
let client = client();
assert_eq!(client.get(uri).dispatch().body_string_wait(), Some(expected));
assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected));
}
fn test_404(uri: &str) {
async fn test_404(uri: &'static str) {
let client = client();
assert_eq!(client.get(uri).dispatch().status(), Status::NotFound);
assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound);
}
#[test]
fn test_hello() {
#[rocket::async_test]
async fn test_hello() {
for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] {
test(&format!("/hello/{}/{}", name, age),
format!("Hello, {} year old named {}!", age, name));
test(format!("/hello/{}/{}", name, age),
format!("Hello, {} year old named {}!", age, name)).await;
}
}
#[test]
fn test_failing_hello() {
test_404("/hello/Mike/1000");
test_404("/hello/Mike/-129");
test_404("/hello/Mike/-1");
#[rocket::async_test]
async fn test_failing_hello() {
test_404("/hello/Mike/1000").await;
test_404("/hello/Mike/-129").await;
test_404("/hello/Mike/-1").await;
}
#[test]
fn test_hi() {
#[rocket::async_test]
async fn test_hi() {
for name in &["Mike", "A", "123", "hi", "c"] {
test(&format!("/hello/{}", name), name.to_string());
test(format!("/hello/{}", name), name.to_string()).await;
}
}

View File

@ -1,9 +1,9 @@
use rocket::local::Client;
#[test]
fn hello_world() {
#[rocket::async_test]
async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello, world!".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
}

View File

@ -2,71 +2,71 @@ use crate::rocket;
use rocket::local::Client;
use rocket::http::{Status, ContentType};
#[test]
fn bad_get_put() {
#[rocket::async_test]
async fn bad_get_put() {
let client = Client::new(rocket()).unwrap();
// Try to get a message with an ID that doesn't exist.
let mut res = client.get("/message/99").header(ContentType::JSON).dispatch();
let mut res = client.get("/message/99").header(ContentType::JSON).dispatch().await;
assert_eq!(res.status(), Status::NotFound);
let body = res.body_string_wait().unwrap();
let body = res.body_string().await.unwrap();
assert!(body.contains("error"));
assert!(body.contains("Resource was not found."));
// Try to get a message with an invalid ID.
let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch();
let body = res.body_string_wait().unwrap();
let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch().await;
let body = res.body_string().await.unwrap();
assert_eq!(res.status(), Status::NotFound);
assert!(body.contains("error"));
// Try to put a message without a proper body.
let res = client.put("/message/80").header(ContentType::JSON).dispatch();
let res = client.put("/message/80").header(ContentType::JSON).dispatch().await;
assert_eq!(res.status(), Status::BadRequest);
// Try to put a message for an ID that doesn't exist.
let res = client.put("/message/80")
.header(ContentType::JSON)
.body(r#"{ "contents": "Bye bye, world!" }"#)
.dispatch();
.dispatch().await;
assert_eq!(res.status(), Status::NotFound);
}
#[test]
fn post_get_put_get() {
#[rocket::async_test]
async fn post_get_put_get() {
let client = Client::new(rocket()).unwrap();
// Check that a message with ID 1 doesn't exist.
let res = client.get("/message/1").header(ContentType::JSON).dispatch();
let res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
assert_eq!(res.status(), Status::NotFound);
// Add a new message with ID 1.
let res = client.post("/message/1")
.header(ContentType::JSON)
.body(r#"{ "contents": "Hello, world!" }"#)
.dispatch();
.dispatch().await;
assert_eq!(res.status(), Status::Ok);
// Check that the message exists with the correct contents.
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch();
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
assert_eq!(res.status(), Status::Ok);
let body = res.body_string_wait().unwrap();
let body = res.body_string().await.unwrap();
assert!(body.contains("Hello, world!"));
// Change the message contents.
let res = client.put("/message/1")
.header(ContentType::JSON)
.body(r#"{ "contents": "Bye bye, world!" }"#)
.dispatch();
.dispatch().await;
assert_eq!(res.status(), Status::Ok);
// Check that the message exists with the updated contents.
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch();
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
assert_eq!(res.status(), Status::Ok);
let body = res.body_string_wait().unwrap();
let body = res.body_string().await.unwrap();
assert!(!body.contains("Hello, world!"));
assert!(body.contains("Bye bye, world!"));
}

View File

@ -1,13 +1,13 @@
use rocket::local::Client;
use rocket::http::Status;
#[test]
fn test_push_pop() {
#[rocket::async_test]
async fn test_push_pop() {
let client = Client::new(super::rocket()).unwrap();
let response = client.put("/push?event=test1").dispatch();
let response = client.put("/push?event=test1").dispatch().await;
assert_eq!(response.status(), Status::Ok);
let mut response = client.get("/pop").dispatch();
assert_eq!(response.body_string_wait(), Some("test1".to_string()));
let mut response = client.get("/pop").dispatch().await;
assert_eq!(response.body_string().await, Some("test1".to_string()));
}

View File

@ -3,10 +3,12 @@ use rocket::local::Client;
use rocket::http::{ContentType, Status};
fn test(uri: &str, content_type: ContentType, status: Status, body: String) {
let client = Client::new(rocket()).unwrap();
let mut response = client.get(uri).header(content_type).dispatch();
assert_eq!(response.status(), status);
assert_eq!(response.body_string_wait(), Some(body));
rocket::async_test(async move {
let client = Client::new(rocket()).unwrap();
let mut response = client.get(uri).header(content_type).dispatch().await;
assert_eq!(response.status(), status);
assert_eq!(response.body_string().await, Some(body));
})
}
#[test]
@ -39,14 +41,14 @@ fn test_upload() {
let response = client.post("/upload")
.header(ContentType::Plain)
.body(&expected_body)
.dispatch();
.dispatch().await;
assert_eq!(response.status(), Status::Ok);
// Ensure we get back the same body.
let mut response = client.get("/upload").dispatch();
let mut response = client.get("/upload").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected_body));
assert_eq!(response.body_string().await, Some(expected_body));
}
#[test]

View File

@ -8,27 +8,27 @@ struct Message {
contents: String
}
#[test]
fn msgpack_get() {
#[rocket::async_test]
async fn msgpack_get() {
let client = Client::new(rocket()).unwrap();
let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch();
let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch().await;
assert_eq!(res.status(), Status::Ok);
assert_eq!(res.content_type(), Some(ContentType::MsgPack));
// Check that the message is `[1, "Hello, world!"]`
assert_eq!(&res.body_bytes_wait().unwrap(),
assert_eq!(&res.body_bytes().await.unwrap(),
&[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
}
#[test]
fn msgpack_post() {
#[rocket::async_test]
async fn msgpack_post() {
// Dispatch request with a message of `[2, "Goodbye, world!"]`.
let client = Client::new(rocket()).unwrap();
let mut res = client.post("/message")
.header(ContentType::MsgPack)
.body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33])
.dispatch();
.dispatch().await;
assert_eq!(res.status(), Status::Ok);
assert_eq!(res.body_string_wait(), Some("Goodbye, world!".into()));
assert_eq!(res.body_string().await, Some("Goodbye, world!".into()));
}

View File

@ -8,30 +8,30 @@ fn client() -> Client {
}
fn test_200(uri: &str, expected_body: &str) {
async fn test_200(uri: &str, expected_body: &str) {
let client = client();
let mut response = client.get(uri).dispatch();
let mut response = client.get(uri).dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected_body.to_string()));
assert_eq!(response.body_string().await, Some(expected_body.to_string()));
}
fn test_303(uri: &str, expected_location: &str) {
async fn test_303(uri: &str, expected_location: &str) {
let client = client();
let response = client.get(uri).dispatch();
let response = client.get(uri).dispatch().await;
let location_headers: Vec<_> = response.headers().get("Location").collect();
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(location_headers, vec![expected_location]);
}
#[test]
fn test() {
test_200("/users/Sergio", "Hello, Sergio!");
#[rocket::async_test]
async fn test() {
test_200("/users/Sergio", "Hello, Sergio!").await;
test_200("/users/login",
"Hi! That user doesn't exist. Maybe you need to log in?");
"Hi! That user doesn't exist. Maybe you need to log in?").await;
}
#[test]
fn test_redirects() {
test_303("/", "/users/login");
test_303("/users/unknown", "/users/login");
#[rocket::async_test]
async fn test_redirects() {
test_303("/", "/users/login").await;
test_303("/users/unknown", "/users/login").await;
}

View File

@ -6,54 +6,54 @@ fn extract_id(from: &str) -> Option<String> {
from.rfind('/').map(|i| &from[(i + 1)..]).map(|s| s.trim_end().to_string())
}
#[test]
fn check_index() {
#[rocket::async_test]
async fn check_index() {
let client = Client::new(rocket()).unwrap();
// Ensure the index returns what we expect.
let mut response = client.get("/").dispatch();
let mut response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain));
assert_eq!(response.body_string_wait(), Some(index().into()))
assert_eq!(response.body_string().await, Some(index().into()))
}
fn upload_paste(client: &Client, body: &str) -> String {
let mut response = client.post("/").body(body).dispatch();
async fn upload_paste(client: &Client, body: &str) -> String {
let mut response = client.post("/").body(body).dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain));
extract_id(&response.body_string_wait().unwrap()).unwrap()
extract_id(&response.body_string().await.unwrap()).unwrap()
}
fn download_paste(client: &Client, id: &str) -> String {
let mut response = client.get(format!("/{}", id)).dispatch();
async fn download_paste(client: &Client, id: &str) -> String {
let mut response = client.get(format!("/{}", id)).dispatch().await;
assert_eq!(response.status(), Status::Ok);
response.body_string_wait().unwrap()
response.body_string().await.unwrap()
}
#[test]
fn pasting() {
#[rocket::async_test]
async fn pasting() {
let client = Client::new(rocket()).unwrap();
// Do a trivial upload, just to make sure it works.
let body_1 = "Hello, world!";
let id_1 = upload_paste(&client, body_1);
assert_eq!(download_paste(&client, &id_1), body_1);
let id_1 = upload_paste(&client, body_1).await;
assert_eq!(download_paste(&client, &id_1).await, body_1);
// Make sure we can keep getting that paste.
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_1).await, body_1);
// Upload some unicode.
let body_2 = "こんにちは";
let id_2 = upload_paste(&client, body_2);
assert_eq!(download_paste(&client, &id_2), body_2);
let id_2 = upload_paste(&client, body_2).await;
assert_eq!(download_paste(&client, &id_2).await, body_2);
// Make sure we can get both pastes.
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_2), body_2);
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_2), body_2);
assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_2).await, body_2);
assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_2).await, body_2);
// Now a longer upload.
let body_3 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
@ -63,8 +63,8 @@ fn pasting() {
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.";
let id_3 = upload_paste(&client, body_3);
assert_eq!(download_paste(&client, &id_3), body_3);
assert_eq!(download_paste(&client, &id_1), body_1);
assert_eq!(download_paste(&client, &id_2), body_2);
let id_3 = upload_paste(&client, body_3).await;
assert_eq!(download_paste(&client, &id_3).await, body_3);
assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_2).await, body_2);
}

View File

@ -5,19 +5,19 @@ use rocket::http::Status;
macro_rules! run_test {
($query:expr, $test_fn:expr) => ({
let client = Client::new(rocket()).unwrap();
$test_fn(client.get(format!("/hello{}", $query)).dispatch());
$test_fn(client.get(format!("/hello{}", $query)).dispatch().await);
})
}
#[test]
fn age_and_name_params() {
run_test!("?age=10&first-name=john", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("Hello, 10 year old named john!".into()));
});
run_test!("?age=20&first-name=john", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("20 years old? Hi, john!".into()));
});
}
@ -25,12 +25,12 @@ fn age_and_name_params() {
#[test]
fn age_param_only() {
run_test!("?age=10", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("We're gonna need a name, and only a name.".into()));
});
run_test!("?age=20", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("We're gonna need a name, and only a name.".into()));
});
}
@ -38,19 +38,19 @@ fn age_param_only() {
#[test]
fn name_param_only() {
run_test!("?first-name=John", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(), Some("Hello John!".into()));
assert_eq!(response.body_string().await, Some("Hello John!".into()));
});
}
#[test]
fn no_params() {
run_test!("", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("We're gonna need a name, and only a name.".into()));
});
run_test!("?", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("We're gonna need a name, and only a name.".into()));
});
}
@ -58,12 +58,12 @@ fn no_params() {
#[test]
fn extra_params() {
run_test!("?age=20&first-name=Bob&extra", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("20 years old? Hi, Bob!".into()));
});
run_test!("?age=30&first-name=Bob&extra", |mut response: Response<'_>| {
assert_eq!(response.body_string_wait(),
assert_eq!(response.body_string().await,
Some("We're gonna need a name, and only a name.".into()));
});
}

View File

@ -1,31 +1,31 @@
use rocket::local::Client;
fn test(uri: &str, expected: String) {
async fn test(uri: String, expected: String) {
let rocket = rocket::ignite().mount("/", routes![super::hello, super::hi]);
let client = Client::new(rocket).unwrap();
let mut response = client.get(uri).dispatch();
assert_eq!(response.body_string_wait(), Some(expected));
let mut response = client.get(&uri).dispatch().await;
assert_eq!(response.body_string().await, Some(expected));
}
#[test]
fn test_hello() {
#[rocket::async_test]
async fn test_hello() {
for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] {
test(&format!("/hello/{}/{}", name, age),
format!("Hello, {} year old named {}!", age, name));
test(format!("/hello/{}/{}", name, age),
format!("Hello, {} year old named {}!", age, name)).await;
}
}
#[test]
fn test_failing_hello_hi() {
#[rocket::async_test]
async fn test_failing_hello_hi() {
// Invalid integers.
for &(name, age) in &[("Mike", 1000), ("Michael", 128), ("A", -800), ("a", -200)] {
test(&format!("/hello/{}/{}", name, age),
format!("Hi {}! Your age ({}) is kind of funky.", name, age));
test(format!("/hello/{}/{}", name, age),
format!("Hi {}! Your age ({}) is kind of funky.", name, age)).await;
}
// Non-integers.
for &(name, age) in &[("Mike", "!"), ("Michael", "hi"), ("A", "blah"), ("a", "0-1")] {
test(&format!("/hello/{}/{}", name, age),
format!("Hi {}! Your age ({}) is kind of funky.", name, age));
test(format!("/hello/{}/{}", name, age),
format!("Hi {}! Your age ({}) is kind of funky.", name, age)).await;
}
}

View File

@ -1,9 +1,9 @@
use super::rocket;
use rocket::local::Client;
#[test]
fn hello() {
#[rocket::async_test]
async fn hello() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Rocketeer".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Rocketeer".into()));
}

View File

@ -7,15 +7,15 @@ use std::fs::{self, File};
const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!";
#[test]
fn test_index() {
#[rocket::async_test]
async fn test_index() {
let client = Client::new(super::rocket()).unwrap();
let mut res = client.get("/").dispatch();
assert_eq!(res.body_string_wait(), Some(super::index().to_string()));
let mut res = client.get("/").dispatch().await;
assert_eq!(res.body_string().await, Some(super::index().to_string()));
}
#[test]
fn test_raw_upload() {
#[rocket::async_test]
async fn test_raw_upload() {
// Delete the upload file before we begin.
let upload_file = env::temp_dir().join("upload.txt");
let _ = fs::remove_file(&upload_file);
@ -25,10 +25,10 @@ fn test_raw_upload() {
let mut res = client.post("/upload")
.header(ContentType::Plain)
.body(UPLOAD_CONTENTS)
.dispatch();
.dispatch().await;
assert_eq!(res.status(), Status::Ok);
assert_eq!(res.body_string_wait(), Some(UPLOAD_CONTENTS.len().to_string()));
assert_eq!(res.body_string().await, Some(UPLOAD_CONTENTS.len().to_string()));
// Ensure we find the body in the /tmp/upload.txt file.
let mut file_contents = String::new();

View File

@ -6,10 +6,10 @@ fn client() -> Client {
Client::new(rocket).unwrap()
}
#[test]
fn test_root() {
#[rocket::async_test]
async fn test_root() {
let client = client();
let mut response = client.get("/").dispatch();
let mut response = client.get("/").dispatch().await;
assert!(response.body().is_none());
assert_eq!(response.status(), Status::SeeOther);
@ -22,9 +22,9 @@ fn test_root() {
}
}
#[test]
fn test_login() {
#[rocket::async_test]
async fn test_login() {
let client = client();
let mut r = client.get("/login").dispatch();
assert_eq!(r.body_string_wait(), Some("Hi! Please log in before continuing.".into()));
let mut r = client.get("/login").dispatch().await;
assert_eq!(r.body_string().await, Some("Hi! Please log in before continuing.".into()));
}

View File

@ -34,26 +34,26 @@ mod test {
use rocket::local::Client;
use rocket::http::Header;
fn test_header_count<'h>(headers: Vec<Header<'static>>) {
async fn test_header_count<'h>(headers: Vec<Header<'static>>) {
let client = Client::new(super::rocket()).unwrap();
let mut req = client.get("/");
for header in headers.iter().cloned() {
req.add_header(header);
}
let mut response = req.dispatch();
let mut response = req.dispatch().await;
let expect = format!("Your request contained {} headers!", headers.len());
assert_eq!(response.body_string_wait(), Some(expect));
assert_eq!(response.body_string().await, Some(expect));
}
#[test]
fn test_n_headers() {
#[rocket::async_test]
async fn test_n_headers() {
for i in 0..50 {
let headers = (0..i)
.map(|n| Header::new(n.to_string(), n.to_string()))
.collect();
test_header_count(headers);
test_header_count(headers).await;
}
}
}

View File

@ -3,10 +3,10 @@ use std::sync::atomic::{Ordering};
use super::{rocket, Atomics};
use rocket::local::Client;
#[test]
fn test() {
#[rocket::async_test]
async fn test() {
let client = Client::new(rocket()).unwrap();
client.get("/").dispatch();
client.get("/").dispatch().await;
let atomics = client.rocket().state::<Atomics>().unwrap();
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 2);

View File

@ -13,58 +13,58 @@ fn user_id_cookie(response: &Response<'_>) -> Option<Cookie<'static>> {
cookie.map(|c| c.into_owned())
}
fn login(client: &Client, user: &str, pass: &str) -> Option<Cookie<'static>> {
async fn login(client: &Client, user: &str, pass: &str) -> Option<Cookie<'static>> {
let response = client.post("/login")
.header(ContentType::Form)
.body(format!("username={}&password={}", user, pass))
.dispatch();
.dispatch().await;
user_id_cookie(&response)
}
#[test]
fn redirect_on_index() {
#[rocket::async_test]
async fn redirect_on_index() {
let client = Client::new(rocket()).unwrap();
let response = client.get("/").dispatch();
let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(response.headers().get_one("Location"), Some("/login"));
}
#[test]
fn can_login() {
#[rocket::async_test]
async fn can_login() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/login").dispatch();
let body = response.body_string_wait().unwrap();
let mut response = client.get("/login").dispatch().await;
let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Please login to continue."));
}
#[test]
fn login_fails() {
#[rocket::async_test]
async fn login_fails() {
let client = Client::new(rocket()).unwrap();
assert!(login(&client, "Seergio", "password").is_none());
assert!(login(&client, "Sergio", "idontknow").is_none());
assert!(login(&client, "Seergio", "password").await.is_none());
assert!(login(&client, "Sergio", "idontknow").await.is_none());
}
#[test]
fn login_logout_succeeds() {
#[rocket::async_test]
async fn login_logout_succeeds() {
let client = Client::new(rocket()).unwrap();
let login_cookie = login(&client, "Sergio", "password").expect("logged in");
let login_cookie = login(&client, "Sergio", "password").await.expect("logged in");
// Ensure we're logged in.
let mut response = client.get("/").cookie(login_cookie.clone()).dispatch();
let body = response.body_string_wait().unwrap();
let mut response = client.get("/").cookie(login_cookie.clone()).dispatch().await;
let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Logged in with user ID 1"));
// One more.
let response = client.get("/login").cookie(login_cookie.clone()).dispatch();
let response = client.get("/login").cookie(login_cookie.clone()).dispatch().await;
assert_eq!(response.status(), Status::SeeOther);
assert_eq!(response.headers().get_one("Location"), Some("/"));
// Logout.
let response = client.post("/logout").cookie(login_cookie).dispatch();
let response = client.post("/logout").cookie(login_cookie).dispatch().await;
let cookie = user_id_cookie(&response).expect("logout cookie");
assert!(cookie.value().is_empty());
@ -73,8 +73,8 @@ fn login_logout_succeeds() {
assert_eq!(response.headers().get_one("Location"), Some("/login"));
// The page should show the success message, and no errors.
let mut response = client.get("/login").dispatch();
let body = response.body_string().unwrap();
let mut response = client.get("/login").dispatch().await;
let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Successfully logged out."));
assert!(!body.contains("Error"));

View File

@ -1,28 +1,28 @@
use rocket::local::Client;
use rocket::http::Status;
fn register_hit(client: &Client) {
let response = client.get("/").dispatch();
async fn register_hit(client: &Client) {
let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
}
fn get_count(client: &Client) -> usize {
let mut response = client.get("/count").dispatch();
response.body_string_wait().and_then(|s| s.parse().ok()).unwrap()
async fn get_count(client: &Client) -> usize {
let mut response = client.get("/count").dispatch().await;
response.body_string().await.and_then(|s| s.parse().ok()).unwrap()
}
#[test]
fn test_count() {
#[rocket::async_test]
async fn test_count() {
let client = Client::new(super::rocket()).unwrap();
// Count should start at 0.
assert_eq!(get_count(&client), 0);
assert_eq!(get_count(&client).await, 0);
for _ in 0..99 { register_hit(&client); }
assert_eq!(get_count(&client), 99);
for _ in 0..99 { register_hit(&client).await; }
assert_eq!(get_count(&client).await, 99);
register_hit(&client);
assert_eq!(get_count(&client), 100);
register_hit(&client).await;
assert_eq!(get_count(&client).await, 100);
}
#[test]

View File

@ -10,7 +10,7 @@ async fn test_query_file<T> (path: &str, file: T, status: Status)
where T: Into<Option<&'static str>>
{
let client = Client::new(rocket()).unwrap();
let mut response = client.get(path).dispatch();
let mut response = client.get(path).dispatch().await;
assert_eq!(response.status(), status);
let body_data = response.body_bytes().await;
@ -28,37 +28,29 @@ fn read_file_content(path: &str) -> Vec<u8> {
file_content
}
#[test]
fn test_index_html() {
rocket::async_test(async {
test_query_file("/", "static/index.html", Status::Ok).await;
test_query_file("/?v=1", "static/index.html", Status::Ok).await;
test_query_file("/?this=should&be=ignored", "static/index.html", Status::Ok).await;
})
#[rocket::async_test]
async fn test_index_html() {
test_query_file("/", "static/index.html", Status::Ok).await;
test_query_file("/?v=1", "static/index.html", Status::Ok).await;
test_query_file("/?this=should&be=ignored", "static/index.html", Status::Ok).await;
}
#[test]
fn test_hidden_file() {
rocket::async_test(async {
test_query_file("/hidden/hi.txt", "static/hidden/hi.txt", Status::Ok).await;
test_query_file("/hidden/hi.txt?v=1", "static/hidden/hi.txt", Status::Ok).await;
test_query_file("/hidden/hi.txt?v=1&a=b", "static/hidden/hi.txt", Status::Ok).await;
})
#[rocket::async_test]
async fn test_hidden_file() {
test_query_file("/hidden/hi.txt", "static/hidden/hi.txt", Status::Ok).await;
test_query_file("/hidden/hi.txt?v=1", "static/hidden/hi.txt", Status::Ok).await;
test_query_file("/hidden/hi.txt?v=1&a=b", "static/hidden/hi.txt", Status::Ok).await;
}
#[test]
fn test_icon_file() {
rocket::async_test(async {
test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok).await;
test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok).await;
})
#[rocket::async_test]
async fn test_icon_file() {
test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok).await;
test_query_file("/rocket-icon.jpg", "static/rocket-icon.jpg", Status::Ok).await;
}
#[test]
fn test_invalid_path() {
rocket::async_test(async {
test_query_file("/thou_shalt_not_exist", None, Status::NotFound).await;
test_query_file("/thou/shalt/not/exist", None, Status::NotFound).await;
test_query_file("/thou/shalt/not/exist?a=b&c=d", None, Status::NotFound).await;
})
#[rocket::async_test]
async fn test_invalid_path() {
test_query_file("/thou_shalt_not_exist", None, Status::NotFound).await;
test_query_file("/thou/shalt/not/exist", None, Status::NotFound).await;
test_query_file("/thou/shalt/not/exist?a=b&c=d", None, Status::NotFound).await;
}

View File

@ -3,21 +3,21 @@ use std::io::prelude::*;
use rocket::local::Client;
#[test]
fn test_root() {
#[rocket::async_test]
async fn test_root() {
let client = Client::new(super::rocket()).unwrap();
let mut res = client.get("/").dispatch();
let mut res = client.get("/").dispatch().await;
// Check that we have exactly 25,000 'a'.
let res_str = res.body_string_wait().unwrap();
let res_str = res.body_string().await.unwrap();
assert_eq!(res_str.len(), 25000);
for byte in res_str.as_bytes() {
assert_eq!(*byte, b'a');
}
}
#[test]
fn test_file() {
#[rocket::async_test]
async fn test_file() {
// Create the 'big_file'
const CONTENTS: &str = "big_file contents...not so big here";
let mut file = File::create(super::FILENAME).expect("create big_file");
@ -25,8 +25,8 @@ fn test_file() {
// Get the big file contents, hopefully.
let client = Client::new(super::rocket()).unwrap();
let mut res = client.get("/big_file").dispatch();
assert_eq!(res.body_string_wait(), Some(CONTENTS.into()));
let mut res = client.get("/big_file").dispatch().await;
assert_eq!(res.body_string().await, Some(CONTENTS.into()));
// Delete the 'big_file'.
fs::remove_file(super::FILENAME).expect("remove big_file");

View File

@ -7,12 +7,12 @@ use rocket_contrib::templates::Template;
macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({
let client = Client::new(rocket()).unwrap();
$test_fn(&client, client.req($method, $path).dispatch());
$test_fn(&client, client.req($method, $path).dispatch().await);
})
}
#[test]
fn test_root() {
#[rocket::async_test]
async fn test_root() {
// Check that the redirect works.
for method in &[Get, Head] {
dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| {
@ -32,13 +32,13 @@ fn test_root() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}
}
#[test]
fn test_name() {
#[rocket::async_test]
async fn test_name() {
// Check that the /hello/<name> route works.
dispatch!(Get, "/hello/Jack", |client: &Client, mut response: LocalResponse<'_>| {
let context = super::TemplateContext {
@ -48,12 +48,12 @@ fn test_name() {
let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}
#[test]
fn test_404() {
#[rocket::async_test]
async fn test_404() {
// Check that the error catcher works.
dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| {
let mut map = std::collections::HashMap::new();
@ -61,6 +61,6 @@ fn test_404() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected));
assert_eq!(response.body_string().await, Some(expected));
});
}

View File

@ -21,11 +21,11 @@ mod test {
use rocket::local::Client;
use rocket::http::Status;
#[test]
fn test_hello() {
#[rocket::async_test]
async fn test_hello() {
let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch();
let mut response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some("Hello, world!".into()));
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
}
}

View File

@ -1,9 +1,9 @@
use rocket::local::Client;
#[test]
fn hello_world() {
#[rocket::async_test]
async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch();
assert_eq!(response.body_string_wait(), Some("Hello, world!".into()));
let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
}

View File

@ -14,13 +14,16 @@ static DB_LOCK: Mutex<()> = Mutex::new(());
macro_rules! run_test {
(|$client:ident, $conn:ident| $block:expr) => ({
let _lock = DB_LOCK.lock();
let rocket = super::rocket();
let db = super::DbConn::get_one(&rocket);
let $client = Client::new(rocket).expect("Rocket client");
let $conn = db.expect("failed to get database connection for testing");
Task::delete_all(&$conn).expect("failed to delete all tasks for testing");
$block
rocket::async_test(async move {
let rocket = super::rocket();
let db = super::DbConn::get_one(&rocket);
let $client = Client::new(rocket).expect("Rocket client");
let $conn = db.expect("failed to get database connection for testing");
Task::delete_all(&$conn).expect("failed to delete all tasks for testing");
$block
})
})
}
@ -34,7 +37,7 @@ fn test_insertion_deletion() {
client.post("/todo")
.header(ContentType::Form)
.body("description=My+first+task")
.dispatch();
.dispatch().await;
// Ensure we have one more task in the database.
let new_tasks = Task::all(&conn).unwrap();
@ -46,7 +49,7 @@ fn test_insertion_deletion() {
// Issue a request to delete the task.
let id = new_tasks[0].id.unwrap();
client.delete(format!("/todo/{}", id)).dispatch();
client.delete(format!("/todo/{}", id)).dispatch().await;
// Ensure it's gone.
let final_tasks = Task::all(&conn).unwrap();
@ -64,17 +67,17 @@ fn test_toggle() {
client.post("/todo")
.header(ContentType::Form)
.body("description=test_for_completion")
.dispatch();
.dispatch().await;
let task = Task::all(&conn).unwrap()[0].clone();
assert_eq!(task.completed, false);
// Issue a request to toggle the task; ensure it is completed.
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
client.put(format!("/todo/{}", task.id.unwrap())).dispatch().await;
assert_eq!(Task::all(&conn).unwrap()[0].completed, true);
// Issue a request to toggle the task; ensure it's not completed again.
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
client.put(format!("/todo/{}", task.id.unwrap())).dispatch().await;
assert_eq!(Task::all(&conn).unwrap()[0].completed, false);
})
}
@ -83,7 +86,6 @@ fn test_toggle() {
fn test_many_insertions() {
const ITER: usize = 100;
let rng = thread_rng();
run_test!(|client, conn| {
// Get the number of tasks initially.
let init_num = Task::all(&conn).unwrap().len();
@ -91,11 +93,11 @@ fn test_many_insertions() {
for i in 0..ITER {
// Issue a request to insert a new task with a random description.
let desc: String = rng.sample_iter(&Alphanumeric).take(12).collect();
let desc: String = thread_rng().sample_iter(&Alphanumeric).take(12).collect();
client.post("/todo")
.header(ContentType::Form)
.body(format!("description={}", desc))
.dispatch();
.dispatch().await;
// Record the description we choose for this iteration.
descs.insert(0, desc);
@ -117,7 +119,7 @@ fn test_bad_form_submissions() {
// Submit an empty form. We should get a 422 but no flash error.
let res = client.post("/todo")
.header(ContentType::Form)
.dispatch();
.dispatch().await;
let mut cookies = res.headers().get("Set-Cookie");
assert_eq!(res.status(), Status::UnprocessableEntity);
@ -128,7 +130,7 @@ fn test_bad_form_submissions() {
let res = client.post("/todo")
.header(ContentType::Form)
.body("description=")
.dispatch();
.dispatch().await;
let mut cookies = res.headers().get("Set-Cookie");
assert!(cookies.any(|value| value.contains("error")));
@ -137,7 +139,7 @@ fn test_bad_form_submissions() {
let res = client.post("/todo")
.header(ContentType::Form)
.body("evil=smile")
.dispatch();
.dispatch().await;
let mut cookies = res.headers().get("Set-Cookie");
assert_eq!(res.status(), Status::UnprocessableEntity);

View File

@ -2,24 +2,24 @@ use super::rocket;
use rocket::local::Client;
use rocket::http::Status;
fn test(uri: &str, expected: &str) {
async fn test(uri: &str, expected: &str) {
let client = Client::new(rocket()).unwrap();
let mut res = client.get(uri).dispatch();
assert_eq!(res.body_string_wait(), Some(expected.into()));
let mut res = client.get(uri).dispatch().await;
assert_eq!(res.body_string().await, Some(expected.into()));
}
fn test_404(uri: &str) {
async fn test_404(uri: &str) {
let client = Client::new(rocket()).unwrap();
let res = client.get(uri).dispatch();
let res = client.get(uri).dispatch().await;
assert_eq!(res.status(), Status::NotFound);
}
#[test]
fn test_people() {
test("/people/7f205202-7ba1-4c39-b2fc-3e630722bf9f", "We found: Lacy");
test("/people/4da34121-bc7d-4fc1-aee6-bf8de0795333", "We found: Bob");
test("/people/ad962969-4e3d-4de7-ac4a-2d86d6d10839", "We found: George");
#[rocket::async_test]
async fn test_people() {
test("/people/7f205202-7ba1-4c39-b2fc-3e630722bf9f", "We found: Lacy").await;
test("/people/4da34121-bc7d-4fc1-aee6-bf8de0795333", "We found: Bob").await;
test("/people/ad962969-4e3d-4de7-ac4a-2d86d6d10839", "We found: George").await;
test("/people/e18b3a5c-488f-4159-a240-2101e0da19fd",
"Person not found for UUID: e18b3a5c-488f-4159-a240-2101e0da19fd");
test_404("/people/invalid_uuid");
"Person not found for UUID: e18b3a5c-488f-4159-a240-2101e0da19fd").await;
test_404("/people/invalid_uuid").await;
}

View File

@ -67,7 +67,8 @@ if [ "$1" = "--contrib" ]; then
msgpack
tera_templates
handlebars_templates
serve
# TODO.async: tokio-rs/tokio#1356
# serve
helmet
diesel_postgres_pool
diesel_sqlite_pool
@ -86,8 +87,9 @@ if [ "$1" = "--contrib" ]; then
pushd "${CONTRIB_LIB_ROOT}" > /dev/null 2>&1
echo ":: Building and testing contrib [default]..."
CARGO_INCREMENTAL=0 cargo test
# TODO.async: 'serve' (broken) is a default feature
# echo ":: Building and testing contrib [default]..."
# CARGO_INCREMENTAL=0 cargo test
for feature in "${FEATURES[@]}"; do
echo ":: Building and testing contrib [${feature}]..."