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/tls",
"examples/fairings", "examples/fairings",
"examples/hello_2018", "examples/hello_2018",
"examples/hello_2015",
] ]

View File

@ -35,14 +35,14 @@ mod helmet_tests {
($helmet:expr, $closure:expr) => {{ ($helmet:expr, $closure:expr) => {{
let rocket = rocket::ignite().mount("/", routes![hello]).attach($helmet); let rocket = rocket::ignite().mount("/", routes![hello]).attach($helmet);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let response = client.get("/").dispatch(); let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
$closure(response) $closure(response)
}} }}
} }
#[test] #[rocket::async_test]
fn default_headers_test() { async fn default_headers_test() {
dispatch!(SpaceHelmet::default(), |response: LocalResponse<'_>| { dispatch!(SpaceHelmet::default(), |response: LocalResponse<'_>| {
assert_header!(response, "X-XSS-Protection", "1"); assert_header!(response, "X-XSS-Protection", "1");
assert_header!(response, "X-Frame-Options", "SAMEORIGIN"); assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
@ -50,8 +50,8 @@ mod helmet_tests {
}) })
} }
#[test] #[rocket::async_test]
fn disable_headers_test() { async fn disable_headers_test() {
let helmet = SpaceHelmet::default().disable::<XssFilter>(); let helmet = SpaceHelmet::default().disable::<XssFilter>();
dispatch!(helmet, |response: LocalResponse<'_>| { dispatch!(helmet, |response: LocalResponse<'_>| {
assert_header!(response, "X-Frame-Options", "SAMEORIGIN"); assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
@ -84,8 +84,8 @@ mod helmet_tests {
}); });
} }
#[test] #[rocket::async_test]
fn additional_headers_test() { async fn additional_headers_test() {
let helmet = SpaceHelmet::default() let helmet = SpaceHelmet::default()
.enable(Hsts::default()) .enable(Hsts::default())
.enable(ExpectCt::default()) .enable(ExpectCt::default())
@ -108,8 +108,8 @@ mod helmet_tests {
}) })
} }
#[test] #[rocket::async_test]
fn uri_test() { async fn uri_test() {
let allow_uri = Uri::parse("https://www.google.com").unwrap(); let allow_uri = Uri::parse("https://www.google.com").unwrap();
let report_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(); 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) { async fn assert_file(client: &Client, prefix: &str, path: &str, exists: bool) {
let full_path = format!("/{}/{}", prefix, path); 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 { if exists {
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
@ -71,48 +71,40 @@ mod static_tests {
} }
} }
#[test] #[rocket::async_test]
fn test_static_no_index() { fn test_static_no_index() {
rocket::async_test(async { let client = Client::new(rocket()).expect("valid rocket");
let client = Client::new(rocket()).expect("valid rocket"); assert_all(&client, "no_index", REGULAR_FILES, true).await;
assert_all(&client, "no_index", REGULAR_FILES, true).await; assert_all(&client, "no_index", HIDDEN_FILES, false).await;
assert_all(&client, "no_index", HIDDEN_FILES, false).await; assert_all(&client, "no_index", INDEXED_DIRECTORIES, false).await;
assert_all(&client, "no_index", INDEXED_DIRECTORIES, false).await;
})
} }
#[test] #[rocket::async_test]
fn test_static_hidden() { fn test_static_hidden() {
rocket::async_test(async { let client = Client::new(rocket()).expect("valid rocket");
let client = Client::new(rocket()).expect("valid rocket"); assert_all(&client, "dots", REGULAR_FILES, true).await;
assert_all(&client, "dots", REGULAR_FILES, true).await; assert_all(&client, "dots", HIDDEN_FILES, true).await;
assert_all(&client, "dots", HIDDEN_FILES, true).await; assert_all(&client, "dots", INDEXED_DIRECTORIES, false).await;
assert_all(&client, "dots", INDEXED_DIRECTORIES, false).await;
})
} }
#[test] #[rocket::async_test]
fn test_static_index() { fn test_static_index() {
rocket::async_test(async { let client = Client::new(rocket()).expect("valid rocket");
let client = Client::new(rocket()).expect("valid rocket"); assert_all(&client, "index", REGULAR_FILES, true).await;
assert_all(&client, "index", REGULAR_FILES, true).await; assert_all(&client, "index", HIDDEN_FILES, false).await;
assert_all(&client, "index", HIDDEN_FILES, false).await; assert_all(&client, "index", INDEXED_DIRECTORIES, true).await;
assert_all(&client, "index", INDEXED_DIRECTORIES, true).await;
assert_all(&client, "default", REGULAR_FILES, true).await; assert_all(&client, "default", REGULAR_FILES, true).await;
assert_all(&client, "default", HIDDEN_FILES, false).await; assert_all(&client, "default", HIDDEN_FILES, false).await;
assert_all(&client, "default", INDEXED_DIRECTORIES, true).await; assert_all(&client, "default", INDEXED_DIRECTORIES, true).await;
})
} }
#[test] #[rocket::async_test]
fn test_static_all() { fn test_static_all() {
rocket::async_test(async { let client = Client::new(rocket()).expect("valid rocket");
let client = Client::new(rocket()).expect("valid rocket"); assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", REGULAR_FILES, true).await; assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await; assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
})
} }
#[test] #[test]
@ -129,33 +121,31 @@ mod static_tests {
} }
} }
#[test] #[rocket::async_test]
fn test_forwarding() { fn test_forwarding() {
rocket::async_test(async { use rocket::http::RawStr;
use rocket::http::RawStr; use rocket::{get, routes};
use rocket::{get, routes};
#[get("/<value>", rank = 20)] #[get("/<value>", rank = 20)]
fn catch_one(value: String) -> String { value } fn catch_one(value: String) -> String { value }
#[get("/<a>/<b>", rank = 20)] #[get("/<a>/<b>", rank = 20)]
fn catch_two(a: &RawStr, b: &RawStr) -> String { format!("{}/{}", a, b) } fn catch_two(a: &RawStr, b: &RawStr) -> String { format!("{}/{}", a, b) }
let rocket = rocket().mount("/default", routes![catch_one, catch_two]); let rocket = rocket().mount("/default", routes![catch_one, catch_two]);
let client = Client::new(rocket).expect("valid rocket"); let client = Client::new(rocket).expect("valid rocket");
let mut response = client.get("/default/ireallydontexist").dispatch(); let mut response = client.get("/default/ireallydontexist").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "ireallydontexist"); assert_eq!(response.body_string().await.unwrap(), "ireallydontexist");
let mut response = client.get("/default/idont/exist").dispatch(); let mut response = client.get("/default/idont/exist").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string().await.unwrap(), "idont/exist"); assert_eq!(response.body_string().await.unwrap(), "idont/exist");
assert_all(&client, "both", REGULAR_FILES, true).await; assert_all(&client, "both", REGULAR_FILES, true).await;
assert_all(&client, "both", HIDDEN_FILES, true).await; assert_all(&client, "both", HIDDEN_FILES, true).await;
assert_all(&client, "both", INDEXED_DIRECTORIES, true).await; assert_all(&client, "both", INDEXED_DIRECTORIES, true).await;
})
} }
#[test] #[test]

View File

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

View File

@ -28,4 +28,5 @@ version_check = "0.9.1"
[dev-dependencies] [dev-dependencies]
rocket = { version = "0.5.0-dev", path = "../lib" } 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 catch;
pub mod route; pub mod route;
pub mod segments; pub mod segments;

View File

@ -399,6 +399,11 @@ pub fn catch(args: TokenStream, input: TokenStream) -> TokenStream {
emit!(attribute::catch::catch_attribute(args, input)) 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. /// Derive for the [`FromFormValue`] trait.
/// ///
/// The [`FromFormValue`] derive can be applied to enums with nullary /// 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.clean_rmeta();
config.target_rustcflags = Some([ config.target_rustcflags = Some([
String::from("--edition=2018"),
link_flag("-L", "crate", &[]), link_flag("-L", "crate", &[]),
link_flag("-L", "dependency", &["deps"]), link_flag("-L", "dependency", &["deps"]),
extern_dep("rocket_http", Kind::Static).expect("find http dep"), 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 // regression test for `#[get] panicking if used inside a macro
foo!("/hello/<name>", name); foo!("/hello/<name>", name);
#[test] #[rocket::async_test]
fn test_reexpansion() { async fn test_reexpansion() {
let rocket = rocket::ignite().mount("/", routes![easy, hard, hi]); let rocket = rocket::ignite().mount("/", routes![easy, hard, hi]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/easy/327").dispatch(); let mut response = client.get("/easy/327").dispatch().await;
assert_eq!(response.body_string().unwrap(), "easy id: 327"); assert_eq!(response.body_string().await.unwrap(), "easy id: 327");
let mut response = client.get("/hard/72").dispatch(); let mut response = client.get("/hard/72").dispatch().await;
assert_eq!(response.body_string().unwrap(), "hard id: 72"); assert_eq!(response.body_string().await.unwrap(), "hard id: 72");
let mut response = client.get("/hello/fish").dispatch(); let mut response = client.get("/hello/fish").dispatch().await;
assert_eq!(response.body_string().unwrap(), "fish"); assert_eq!(response.body_string().await.unwrap(), "fish");
} }
macro_rules! index { macro_rules! index {
@ -59,11 +59,11 @@ macro_rules! index {
index!(i32); index!(i32);
#[test] #[rocket::async_test]
fn test_index() { async fn test_index() {
let rocket = rocket::ignite().mount("/", routes![index]).manage(100i32); let rocket = rocket::ignite().mount("/", routes![index]).manage(100i32);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().unwrap(), "Thing: 100"); assert_eq!(response.body_string().await.unwrap(), "Thing: 100");
} }

View File

@ -21,43 +21,47 @@ pub enum Foo<'r> {
}, },
} }
#[test] #[rocket::async_test]
fn responder_foo() { async fn responder_foo() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();
let mut response = Foo::First("hello".into()) let mut response = Foo::First("hello".into())
.respond_to(req) .respond_to(req)
.await
.expect("response okay"); .expect("response okay");
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain)); 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()) let mut response = Foo::Second("just a test".into())
.respond_to(req) .respond_to(req)
.await
.expect("response okay"); .expect("response okay");
assert_eq!(response.status(), Status::InternalServerError); assert_eq!(response.status(), Status::InternalServerError);
assert_eq!(response.content_type(), Some(ContentType::Binary)); 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 } let mut response = Foo::Third { responder: "well, hi", ct: ContentType::JSON }
.respond_to(req) .respond_to(req)
.await
.expect("response okay"); .expect("response okay");
assert_eq!(response.status(), Status::NotFound); assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.content_type(), Some(ContentType::HTML)); 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 } let mut response = Foo::Fourth { string: "goodbye", ct: ContentType::JSON }
.respond_to(req) .respond_to(req)
.await
.expect("response okay"); .expect("response okay");
assert_eq!(response.status(), Status::raw(105)); assert_eq!(response.status(), Status::raw(105));
assert_eq!(response.content_type(), Some(ContentType::JSON)); 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)] #[derive(Responder)]
@ -70,8 +74,8 @@ pub struct Bar<'r> {
_yet_another: String, _yet_another: String,
} }
#[test] #[rocket::async_test]
fn responder_bar() { async fn responder_bar() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();
@ -81,11 +85,11 @@ fn responder_bar() {
other: ContentType::HTML, other: ContentType::HTML,
third: Cookie::new("cookie", "here!"), third: Cookie::new("cookie", "here!"),
_yet_another: "uh..hi?".into() _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.status(), Status::InternalServerError);
assert_eq!(response.content_type(), Some(ContentType::Plain)); 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!")); assert_eq!(response.headers().get_one("Set-Cookie"), Some("cookie=here!"));
} }
@ -95,17 +99,18 @@ pub struct Baz {
responder: &'static str, responder: &'static str,
} }
#[test] #[rocket::async_test]
fn responder_baz() { async fn responder_baz() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();
let mut response = Baz { responder: "just a custom" } let mut response = Baz { responder: "just a custom" }
.respond_to(req) .respond_to(req)
.await
.expect("response okay"); .expect("response okay");
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::new("application", "x-custom"))); 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; #[macro_use] extern crate rocket;
use std::io::Read;
use rocket::{Request, Data, Outcome::*}; use rocket::{Request, Data, Outcome::*};
use rocket::local::Client; use rocket::local::Client;
use rocket::request::Form; use rocket::request::Form;
@ -22,13 +20,19 @@ struct Simple(String);
impl FromDataSimple for Simple { impl FromDataSimple for Simple {
type Error = (); type Error = ();
fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> { fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
let mut string = String::new(); Box::pin(async {
if let Err(_) = data.open().take(64).read_to_string(&mut string) { use futures::io::AsyncReadExt as _;
return Failure((Status::InternalServerError, ())); 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>")] #[post("/s", data = "<simple>")]
fn simple(simple: Simple) -> String { simple.0 } fn simple(simple: Simple) -> String { simple.0 }
#[test] #[rocket::async_test]
fn test_data() { async fn test_data() {
let rocket = rocket::ignite().mount("/", routes![form, simple]); let rocket = rocket::ignite().mount("/", routes![form, simple]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.post("/f") let mut response = client.post("/f")
.header(ContentType::Form) .header(ContentType::Form)
.body("field=this%20is%20here") .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(); let mut response = client.post("/s").body("this is here").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%20is%20here").dispatch(); let mut response = client.post("/s").body("this%20is%20here").dispatch().await;
assert_eq!(response.body_string().unwrap(), "this%20is%20here"); assert_eq!(response.body_string().await.unwrap(), "this%20is%20here");
} }

View File

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

View File

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

View File

@ -28,11 +28,16 @@ struct Simple(String);
impl FromDataSimple for Simple { impl FromDataSimple for Simple {
type Error = (); type Error = ();
fn from_data(_: &Request<'_>, data: Data) -> data::Outcome<Self, ()> { fn from_data(_: &Request<'_>, data: Data) -> data::FromDataFuture<'static, Self, ()> {
use std::io::Read; Box::pin(async move {
let mut string = String::new(); use futures::io::AsyncReadExt as _;
data.open().take(64).read_to_string(&mut string).unwrap(); use rocket::AsyncReadExt as _;
Success(Simple(string))
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) { fn test_unused_params(_unused_param: String, _unused_query: String, _unused_data: Data) {
} }
#[test] #[rocket::async_test]
fn test_full_route() { async fn test_full_route() {
let rocket = rocket::ignite() let rocket = rocket::ignite()
.mount("/1", routes![post1]) .mount("/1", routes![post1])
.mount("/2", routes![post2]); .mount("/2", routes![post2]);
@ -95,30 +100,30 @@ fn test_full_route() {
let uri = format!("{}{}", path_part, query_part); let uri = format!("{}{}", path_part, query_part);
let expected_uri = format!("{}?sky=blue&sky={}&{}", path_part, sky, query); 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); 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); assert_eq!(response.status(), Status::NotFound);
let mut response = client let mut response = client
.post(format!("/1{}", uri)) .post(format!("/1{}", uri))
.header(ContentType::JSON) .header(ContentType::JSON)
.body(simple) .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)); 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); assert_eq!(response.status(), Status::NotFound);
let mut response = client let mut response = client
.post(format!("/2{}", uri)) .post(format!("/2{}", uri))
.header(ContentType::JSON) .header(ContentType::JSON)
.body(simple) .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)); 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 // TODO.async: More thoughtful plan for async tests
/// WARNING: This is unstable! Do not use this method outside of Rocket! /// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)] #[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) tokio::runtime::Runtime::new().expect("create tokio runtime").block_on(fut)
} }

View File

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

View File

@ -44,8 +44,10 @@
//! # let rocket = rocket::ignite(); //! # let rocket = rocket::ignite();
//! # let client = Client::new(rocket).unwrap(); //! # let client = Client::new(rocket).unwrap();
//! # let req = client.get("/"); //! # let req = client.get("/");
//! let response = req.dispatch(); //! # let _ = async {
//! let response = req.dispatch().await;
//! # let _ = response; //! # let _ = response;
//! # };
//! ``` //! ```
//! //!
//! All together and in idiomatic fashion, this might look like: //! All together and in idiomatic fashion, this might look like:
@ -53,11 +55,13 @@
//! ```rust //! ```rust
//! use rocket::local::Client; //! use rocket::local::Client;
//! //!
//! # let _ = async {
//! let client = Client::new(rocket::ignite()).expect("valid rocket"); //! let client = Client::new(rocket::ignite()).expect("valid rocket");
//! let response = client.post("/") //! let response = client.post("/")
//! .body("Hello, world!") //! .body("Hello, world!")
//! .dispatch(); //! .dispatch().await;
//! # let _ = response; //! # let _ = response;
//! # };
//! ``` //! ```
//! //!
//! # Unit/Integration Testing //! # Unit/Integration Testing
@ -82,15 +86,15 @@
//! use super::{rocket, hello}; //! use super::{rocket, hello};
//! use rocket::local::Client; //! use rocket::local::Client;
//! //!
//! #[test] //! #[rocket::async_test]
//! fn test_hello_world() { //! fn test_hello_world() {
//! // Construct a client to use for dispatching requests. //! // Construct a client to use for dispatching requests.
//! let rocket = rocket::ignite().mount("/", routes![hello]); //! let rocket = rocket::ignite().mount("/", routes![hello]);
//! let client = Client::new(rocket).expect("valid rocket instance"); //! let client = Client::new(rocket).expect("valid rocket instance");
//! //!
//! // Dispatch a request to 'GET /' and validate the response. //! // Dispatch a request to 'GET /' and validate the response.
//! let mut response = client.get("/").dispatch(); //! let mut response = client.get("/").dispatch().await;
//! assert_eq!(response.body_string(), Some("Hello, world!".into())); //! 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 /// [`mut_dispatch`]: #method.mut_dispatch
pub struct LocalRequest<'c> { pub struct LocalRequest<'c> {
client: &'c Client, 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` // This `Arc` exists so that we can transfer ownership to the `LocalResponse`
// selectively on dispatch. This is necessary because responses may point // 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 // 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. // See the comments on the structure for what's going on here.
let mut request = Arc::new(request); let request = Arc::new(request);
let ptr = Arc::get_mut(&mut request).unwrap() as *mut Request<'_>; LocalRequest { client, request, uri, data: vec![] }
LocalRequest { client, ptr, request, uri, data: vec![] }
} }
/// Retrieves the inner `Request` as seen by Rocket. /// Retrieves the inner `Request` as seen by Rocket.
@ -142,7 +137,7 @@ impl<'c> LocalRequest<'c> {
#[inline(always)] #[inline(always)]
fn request_mut(&mut self) -> &mut Request<'c> { fn request_mut(&mut self) -> &mut Request<'c> {
// See the comments in the structure for the argument of correctness. // 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! // 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 // Additionally, the caller must ensure that the owned instance of
// `Arc<Request>` remains valid as long as the returned reference can be // `Arc<Request>` remains valid as long as the returned reference can be
// accessed. // accessed.
unsafe { &mut *self.ptr } unsafe { &mut *(self.request_mut() as *mut _) }
} }
/// Add a header to this request. /// Add a header to this request.
@ -351,9 +346,9 @@ impl<'c> LocalRequest<'c> {
/// let response = client.get("/").dispatch(); /// let response = client.get("/").dispatch();
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn dispatch(mut self) -> LocalResponse<'c> { pub async fn dispatch(mut self) -> LocalResponse<'c> {
let r = self.long_lived_request(); 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. /// Dispatches the request, returning the response.
@ -375,22 +370,28 @@ impl<'c> LocalRequest<'c> {
/// ```rust /// ```rust
/// use rocket::local::Client; /// 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 mut req = client.get("/");
/// let response_a = req.mut_dispatch(); /// let response_a = req.mut_dispatch().await;
/// let response_b = req.mut_dispatch(); /// // TODO.async: Annoying. Is this really a good example to show?
/// drop(response_a);
/// let response_b = req.mut_dispatch().await;
/// })
/// ``` /// ```
#[inline(always)] #[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 req = self.long_lived_request();
let data = std::mem::replace(&mut self.data, vec![]); let data = std::mem::replace(&mut self.data, vec![]);
let rc_req = self.request.clone(); 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. // 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, client: &'c Client,
request: &'c mut Request<'c>, request: &'c mut Request<'c>,
owned_request: Arc<Request<'c>>, owned_request: Arc<Request<'c>>,
@ -405,38 +406,34 @@ impl<'c> LocalRequest<'c> {
request.set_uri(uri.into_owned()); request.set_uri(uri.into_owned());
} else { } else {
error!("Malformed request URI: {}", uri); 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;
let res = client.rocket().handle_error(Status::BadRequest, request).await; return LocalResponse { _request: owned_request, response: res };
LocalResponse { _request: owned_request, response: res }
})
} }
tokio::runtime::Runtime::new().expect("create runtime").block_on(async move { // Actually dispatch the request.
// Actually dispatch the request. let response = client.rocket().dispatch(request, Data::local(data)).await;
let response = client.rocket().dispatch(request, Data::local(data)).await;
// If the client is tracking cookies, updates the internal cookie jar // If the client is tracking cookies, updates the internal cookie jar
// with the changes reflected by `response`. // with the changes reflected by `response`.
if let Some(ref jar) = client.cookies { if let Some(ref jar) = client.cookies {
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock"); let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
let current_time = time::OffsetDateTime::now_utc(); let current_time = time::OffsetDateTime::now_utc();
for cookie in response.cookies() { for cookie in response.cookies() {
if let Some(expires) = cookie.expires() { if let Some(expires) = cookie.expires() {
if expires <= current_time { if expires <= current_time {
jar.force_remove(cookie); jar.force_remove(cookie);
continue; continue;
}
} }
jar.add(cookie.into_owned());
} }
}
LocalResponse { jar.add(cookie.into_owned());
_request: owned_request,
response: response
} }
}) }
LocalResponse {
_request: owned_request,
response: response
}
} }
} }
@ -458,16 +455,6 @@ pub struct LocalResponse<'c> {
response: Response<'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> { impl<'c> Deref for LocalResponse<'c> {
type Target = Response<'c>; type Target = Response<'c>;
@ -490,20 +477,17 @@ impl fmt::Debug for LocalResponse<'_> {
} }
} }
impl<'c> Clone for LocalRequest<'c> { // TODO.async: Figure out a way to accomplish this
fn clone(&self) -> LocalRequest<'c> { //impl<'c> Clone for LocalRequest<'c> {
// Don't alias the existing `Request`. See #1312. // fn clone(&self) -> LocalRequest<'c> {
let mut request = Rc::new(self.inner().clone()); // LocalRequest {
let ptr = Rc::get_mut(&mut request).unwrap() as *mut Request<'_>; // client: self.client,
// request: self.request.clone(),
LocalRequest { // data: self.data.clone(),
ptr, request, // uri: self.uri.clone()
client: self.client, // }
data: self.data.clone(), // }
uri: self.uri.clone() //}
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

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

View File

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

View File

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

View File

@ -43,16 +43,16 @@ fn number(params: Form<ThingForm>) -> DerivedResponder {
DerivedResponder { data: params.thing.to_string() } DerivedResponder { data: params.thing.to_string() }
} }
#[test] #[rocket::async_test]
fn test_derive_reexports() { async fn test_derive_reexports() {
use rocket::local::Client; use rocket::local::Client;
let rocket = rocket::ignite().mount("/", routes![index, number]); let rocket = rocket::ignite().mount("/", routes![index, number]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait().unwrap(), "hello"); assert_eq!(response.body_string().await.unwrap(), "hello");
let mut response = client.get("/?thing=b").dispatch(); let mut response = client.get("/?thing=b").dispatch().await;
assert_eq!(response.body_string_wait().unwrap(), "b"); 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::http::Status;
use rocket::State; use rocket::State;
#[test] #[rocket::async_test]
fn not_auto_handled() { async fn not_auto_handled() {
let rocket = rocket::ignite() let rocket = rocket::ignite()
.mount("/", routes![head]) .mount("/", routes![head])
.attach(AdHoc::on_request("Check HEAD", |req, _| { .attach(AdHoc::on_request("Check HEAD", |req, _| {
@ -41,13 +41,13 @@ mod fairing_before_head_strip {
})); }));
let client = Client::new(rocket).unwrap(); 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_eq!(response.status(), Status::Ok);
assert!(response.body().is_none()); assert!(response.body().is_none());
} }
#[test] #[rocket::async_test]
fn auto_handled() { async fn auto_handled() {
#[derive(Default)] #[derive(Default)]
struct Counter(AtomicUsize); struct Counter(AtomicUsize);
@ -70,7 +70,7 @@ mod fairing_before_head_strip {
})); }));
let client = Client::new(rocket).unwrap(); 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_eq!(response.status(), Status::Ok);
assert!(response.body().is_none()); assert!(response.body().is_none());
} }

View File

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

View File

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

View File

@ -20,25 +20,25 @@ mod tests {
use rocket::http::ContentType; use rocket::http::ContentType;
use rocket::http::Status; 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 client = Client::new(rocket::ignite().mount("/", routes![bug])).unwrap();
let mut response = client.post("/") let mut response = client.post("/")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("form_data={}", raw)) .body(format!("form_data={}", raw))
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::Ok); 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] #[rocket::async_test]
fn test_proper_decoding() { async fn test_proper_decoding() {
check_decoding("password", "password"); check_decoding("password", "password").await;
check_decoding("", ""); check_decoding("", "").await;
check_decoding("+", " "); check_decoding("+", " ").await;
check_decoding("%2B", "+"); check_decoding("%2B", "+").await;
check_decoding("1+1", "1 1"); check_decoding("1+1", "1 1").await;
check_decoding("1%2B1", "1+1"); check_decoding("1%2B1", "1+1").await;
check_decoding("%3Fa%3D1%26b%3D2", "?a=1&b=2"); 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] 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 { match body {
Body::Sized(mut body, size) => { Body::Sized(mut body, size) => {
let mut buffer = vec![]; 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!(size, expected_size);
assert_eq!(buffer.len(), 0); assert_eq!(buffer.len(), 0);
} }
@ -47,27 +45,27 @@ mod head_handling_tests {
} }
} }
#[test] #[rocket::async_test]
fn auto_head() { async fn auto_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); 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_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(); let content_type: Vec<_> = response.headers().get("Content-Type").collect();
assert_eq!(content_type, vec![ContentType::Plain.to_string()]); 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_eq!(response.status(), Status::NoContent);
assert!(response.body_bytes_wait().is_none()); assert!(response.body_bytes().await.is_none());
} }
#[test] #[rocket::async_test]
fn user_head() { async fn user_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); 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_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(); let content_type: Vec<_> = response.headers().get("Content-Type").collect();
assert_eq!(content_type, vec![ContentType::JSON.to_string()]); 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]) rocket::custom(config).mount("/", routes![super::index])
} }
#[test] #[rocket::async_test]
fn large_enough() { async fn large_enough() {
let client = Client::new(rocket_with_forms_limit(128)).unwrap(); let client = Client::new(rocket_with_forms_limit(128)).unwrap();
let mut response = client.post("/") let mut response = client.post("/")
.body("value=Hello+world") .body("value=Hello+world")
.header(ContentType::Form) .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] #[rocket::async_test]
fn just_large_enough() { async fn just_large_enough() {
let client = Client::new(rocket_with_forms_limit(17)).unwrap(); let client = Client::new(rocket_with_forms_limit(17)).unwrap();
let mut response = client.post("/") let mut response = client.post("/")
.body("value=Hello+world") .body("value=Hello+world")
.header(ContentType::Form) .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] #[rocket::async_test]
fn much_too_small() { async fn much_too_small() {
let client = Client::new(rocket_with_forms_limit(4)).unwrap(); let client = Client::new(rocket_with_forms_limit(4)).unwrap();
let response = client.post("/") let response = client.post("/")
.body("value=Hello+world") .body("value=Hello+world")
.header(ContentType::Form) .header(ContentType::Form)
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::UnprocessableEntity); assert_eq!(response.status(), Status::UnprocessableEntity);
} }
#[test] #[rocket::async_test]
fn contracted() { async fn contracted() {
let client = Client::new(rocket_with_forms_limit(10)).unwrap(); let client = Client::new(rocket_with_forms_limit(10)).unwrap();
let mut response = client.post("/") let mut response = client.post("/")
.body("value=Hello+world") .body("value=Hello+world")
.header(ContentType::Form) .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]) rocket::ignite().mount("/", routes![rg_ct, data_has_ct, data_no_ct])
} }
#[test] #[rocket::async_test]
fn has_no_ct() { async fn has_no_ct() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut req = client.post("/"); let mut req = client.post("/");
assert_eq!(req.clone().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().body_string_wait(), Some("Absent".to_string())); assert_eq!(req.mut_dispatch().await.body_string().await, Some("Absent".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Absent".to_string())); assert_eq!(req.dispatch().await.body_string().await, Some("Absent".to_string()));
let mut req = client.post("/data"); let mut req = client.post("/data");
assert_eq!(req.clone().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().body_string_wait(), Some("Data Absent".to_string())); assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Absent".to_string()));
assert_eq!(req.dispatch().body_string_wait(), Some("Data Absent".to_string())); assert_eq!(req.dispatch().await.body_string().await, Some("Data Absent".to_string()));
} }
#[test] #[rocket::async_test]
fn has_ct() { async fn has_ct() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut req = client.post("/").header(ContentType::JSON); let mut req = client.post("/").header(ContentType::JSON);
assert_eq!(req.clone().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().body_string_wait(), Some("Present".to_string())); assert_eq!(req.mut_dispatch().await.body_string().await, Some("Present".to_string()));
assert_eq!(req.dispatch().body_string_wait(), 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); 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.clone().dispatch().await.body_string().await, Some("Data Present".to_string()));
assert_eq!(req.mut_dispatch().body_string_wait(), Some("Data Present".to_string())); assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Present".to_string()));
assert_eq!(req.dispatch().body_string_wait(), 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::Cookie;
use rocket::http::Status; use rocket::http::Status;
#[test] #[rocket::async_test]
fn private_cookie_is_returned() { async fn private_cookie_is_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]); let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let req = client.get("/").private_cookie(Cookie::new("cookie_name", "cookie_value")); 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); assert_eq!(response.headers().get_one("Set-Cookie"), None);
} }
#[test] #[rocket::async_test]
fn regular_cookie_is_not_returned() { async fn regular_cookie_is_not_returned() {
let rocket = rocket::ignite().mount("/", routes![return_private_cookie]); let rocket = rocket::ignite().mount("/", routes![return_private_cookie]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let req = client.get("/").cookie(Cookie::new("cookie_name", "cookie_value")); 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); assert_eq!(response.status(), Status::NotFound);
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -33,8 +33,8 @@ mod tests {
use super::*; use super::*;
use rocket::local::Client; use rocket::local::Client;
#[test] #[rocket::async_test]
fn segments_works() { async fn segments_works() {
let rocket = rocket::ignite() let rocket = rocket::ignite()
.mount("/", routes![test, two, one_two, none, dual]) .mount("/", routes![test, two, one_two, none, dual])
.mount("/point", routes![test, two, one_two, dual]); .mount("/point", routes![test, two, one_two, dual]);
@ -47,8 +47,8 @@ mod tests {
"/static", "/point/static"] "/static", "/point/static"]
{ {
let path = "this/is/the/path/we/want"; let path = "this/is/the/path/we/want";
let mut response = client.get(format!("{}/{}", prefix, path)).dispatch(); let mut response = client.get(format!("{}/{}", prefix, path)).dispatch().await;
assert_eq!(response.body_string_wait(), Some(path.into())); 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() Client::new(rocket::ignite().mount("/", routes![strict, lenient])).unwrap()
} }
#[test] #[rocket::async_test]
fn test_strict_form() { async fn test_strict_form() {
let client = client(); let client = client();
let mut response = client.post("/strict") let mut response = client.post("/strict")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("field={}", FIELD_VALUE)) .body(format!("field={}", FIELD_VALUE))
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::Ok); 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") let response = client.post("/strict")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("field={}&extra=whoops", FIELD_VALUE)) .body(format!("field={}&extra=whoops", FIELD_VALUE))
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::UnprocessableEntity); assert_eq!(response.status(), Status::UnprocessableEntity);
} }
#[test] #[rocket::async_test]
fn test_lenient_form() { async fn test_lenient_form() {
let client = client(); let client = client();
let mut response = client.post("/lenient") let mut response = client.post("/lenient")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("field={}", FIELD_VALUE)) .body(format!("field={}", FIELD_VALUE))
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::Ok); 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") let mut response = client.post("/lenient")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("field={}&extra=whoops", FIELD_VALUE)) .body(format!("field={}&extra=whoops", FIELD_VALUE))
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::Ok); 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::local::Client;
use rocket::http::{Status, uri::Uri}; use rocket::http::{Status, uri::Uri};
#[test] #[rocket::async_test]
fn uri_percent_encoding_redirect() { async fn uri_percent_encoding_redirect() {
let expected_location = vec!["/hello/John%5B%5D%7C%5C%25@%5E"]; let expected_location = vec!["/hello/John%5B%5D%7C%5C%25@%5E"];
let client = Client::new(rocket()).unwrap(); 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(); let location: Vec<_> = response.headers().get("location").collect();
assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.status(), Status::SeeOther);
assert_eq!(&location, &expected_location); 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(); let location: Vec<_> = response.headers().get("location").collect();
assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.status(), Status::SeeOther);
assert_eq!(&location, &expected_location); assert_eq!(&location, &expected_location);
} }
#[test] #[rocket::async_test]
fn uri_percent_encoding_get() { async fn uri_percent_encoding_get() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let name = Uri::percent_encode(NAME); 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.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]); .mount("/", routes![check_config]);
let client = Client::new(rocket).unwrap(); rocket::async_test(async move {
let response = client.get("/check_config").dispatch(); let client = Client::new(rocket).unwrap();
assert_eq!(response.status(), Status::Ok); 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::http::{Accept, ContentType, Header, MediaType, Method, Status};
use rocket::local::Client; 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>> where H: Into<Header<'static>>
{ {
let rocket = rocket::ignite() 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]); .register(catchers![super::not_found]);
let client = Client::new(rocket).unwrap(); 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.status(), status);
assert_eq!(response.body_string_wait(), Some(body)); assert_eq!(response.body_string().await, Some(body));
} }
#[test] #[rocket::async_test]
fn test_hello() { async fn test_hello() {
let person = Person { name: "Michael".to_string(), age: 80, }; let person = Person { name: "Michael".to_string(), age: 80, };
let body = serde_json::to_string(&person).unwrap(); 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::JSON, Status::Ok, body.clone()).await;
test(Method::Get, "/hello/Michael/80", Accept::Any, Status::Ok, body.clone()); test(Method::Get, "/hello/Michael/80", Accept::Any, Status::Ok, body.clone()).await;
// No `Accept` header is an implicit */*. // 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 person = Person { name: "".to_string(), age: 99, };
let body = serde_json::to_string(&person).unwrap(); 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] #[rocket::async_test]
fn test_hello_invalid_content_type() { async fn test_hello_invalid_content_type() {
let b = format!("<p>'{}' requests are not supported.</p>", MediaType::HTML); 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::Get, "/hello/Michael/80", Accept::HTML, Status::NotFound, b.clone()).await;
test(Method::Post, "/hello/80", ContentType::HTML, Status::NotFound, b); test(Method::Post, "/hello/80", ContentType::HTML, Status::NotFound, b).await;
} }
#[test] #[rocket::async_test]
fn test_404() { async fn test_404() {
let body = "<p>Sorry, '/unknown' is an invalid path! Try \ let body = "<p>Sorry, '/unknown' is an invalid path! Try \
/hello/&lt;name&gt;/&lt;age&gt; instead.</p>"; /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::http::*;
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
#[test] #[rocket::async_test]
fn test_submit() { async fn test_submit() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let response = client.post("/submit") let response = client.post("/submit")
.header(ContentType::Form) .header(ContentType::Form)
.body("message=Hello from Rocket!") .body("message=Hello from Rocket!")
.dispatch(); .dispatch().await;
let cookie_headers: Vec<_> = response.headers().get("Set-Cookie").collect(); let cookie_headers: Vec<_> = response.headers().get("Set-Cookie").collect();
let location_headers: Vec<_> = response.headers().get("Location").collect(); let location_headers: Vec<_> = response.headers().get("Location").collect();
@ -21,29 +21,29 @@ fn test_submit() {
assert_eq!(location_headers, vec!["/".to_string()]); 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. // Attach a cookie if one is given.
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut response = match optional_cookie { let mut response = match optional_cookie {
Some(cookie) => client.get("/").cookie(cookie).dispatch(), Some(cookie) => client.get("/").cookie(cookie).dispatch().await,
None => client.get("/").dispatch(), None => client.get("/").dispatch().await,
}; };
assert_eq!(response.status(), Status::Ok); 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] #[rocket::async_test]
fn test_index() { async fn test_index() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Render the template with an empty context. // Render the template with an empty context.
let mut context: HashMap<&str, &str> = HashMap::new(); let mut context: HashMap<&str, &str> = HashMap::new();
let template = Template::show(client.rocket(), "index", &context).unwrap(); 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. // Render the template with a context that contains the message.
context.insert("message", "Hello from Rocket!"); context.insert("message", "Hello from Rocket!");
let template = Template::show(client.rocket(), "index", &context).unwrap(); 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::local::Client;
use rocket::http::Status; 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() let rocket = rocket::ignite()
.mount("/", routes![super::hello]) .mount("/", routes![super::hello])
.register(catchers![super::not_found]); .register(catchers![super::not_found]);
let client = Client::new(rocket).unwrap(); 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.status(), status);
assert_eq!(response.body_string_wait(), Some(body)); assert_eq!(response.body_string().await, Some(body));
} }
#[test] #[rocket::async_test]
fn test_hello() { async fn test_hello() {
let (name, age) = ("Arthur", 42); let (name, age) = ("Arthur", 42);
let uri = format!("/hello/{}/{}", name, age); 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] #[rocket::async_test]
fn test_hello_invalid_age() { async fn test_hello_invalid_age() {
for &(name, age) in &[("Ford", -129), ("Trillian", 128)] { for &(name, age) in &[("Ford", -129), ("Trillian", 128)] {
let uri = format!("/hello/{}/{}", name, age); let uri = format!("/hello/{}/{}", name, age);
let body = format!("<p>Sorry, but '{}' is not a valid path!</p> let body = format!("<p>Sorry, but '{}' is not a valid path!</p>
<p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>", <p>Try visiting /hello/&lt;name&gt;/&lt;age&gt; instead.</p>",
uri); uri);
test(&uri, Status::NotFound, body); test(&uri, Status::NotFound, body).await;
} }
} }

View File

@ -1,38 +1,38 @@
use super::rocket; use super::rocket;
use rocket::local::Client; use rocket::local::Client;
#[test] #[rocket::async_test]
fn rewrite_get_put() { async fn rewrite_get_put() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello, fairings!".into())); assert_eq!(response.body_string().await, Some("Hello, fairings!".into()));
} }
#[test] #[rocket::async_test]
fn counts() { async fn counts() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Issue 1 GET request. // Issue 1 GET request.
client.get("/").dispatch(); client.get("/").dispatch().await;
// Check the GET count, taking into account _this_ GET request. // Check the GET count, taking into account _this_ GET request.
let mut response = client.get("/counts").dispatch(); let mut response = client.get("/counts").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Get: 2\nPost: 0".into())); assert_eq!(response.body_string().await, Some("Get: 2\nPost: 0".into()));
// Issue 1 more GET request and a POST. // Issue 1 more GET request and a POST.
client.get("/").dispatch(); client.get("/").dispatch().await;
client.post("/").dispatch(); client.post("/").dispatch().await;
// Check the counts. // Check the counts.
let mut response = client.get("/counts").dispatch(); let mut response = client.get("/counts").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Get: 4\nPost: 1".into())); assert_eq!(response.body_string().await, Some("Get: 4\nPost: 1".into()));
} }
#[test] #[rocket::async_test]
fn token() { async fn token() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Ensure the token is '123', which is what we have in `Rocket.toml`. // Ensure the token is '123', which is what we have in `Rocket.toml`.
let mut res = client.get("/token").dispatch(); let mut res = client.get("/token").dispatch().await;
assert_eq!(res.body_string_wait(), Some("123".into())); 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) { fn assert_form_eq(client: &Client, form_str: &str, expected: String) {
let mut res = client.post("/") rocket::async_test(async move {
.header(ContentType::Form) let mut res = client.post("/")
.body(form_str) .header(ContentType::Form)
.dispatch(); .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<'_>) { fn assert_valid_form(client: &Client, input: &FormInput<'_>) {

View File

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

View File

@ -8,12 +8,12 @@ use rocket_contrib::templates::Template;
macro_rules! dispatch { macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({ ($method:expr, $path:expr, $test_fn:expr) => ({
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
$test_fn(&client, client.req($method, $path).dispatch()); $test_fn(&client, client.req($method, $path).dispatch().await);
}) })
} }
#[test] #[rocket::async_test]
fn test_root() { async fn test_root() {
// Check that the redirect works. // Check that the redirect works.
for method in &[Get, Head] { for method in &[Get, Head] {
dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| { dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| {
@ -33,13 +33,13 @@ fn test_root() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap(); let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound); assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected)); assert_eq!(response.body_string().await, Some(expected));
}); });
} }
} }
#[test] #[rocket::async_test]
fn test_name() { async fn test_name() {
// Check that the /hello/<name> route works. // Check that the /hello/<name> route works.
dispatch!(Get, "/hello/Jack%20Daniels", |client: &Client, mut response: LocalResponse<'_>| { dispatch!(Get, "/hello/Jack%20Daniels", |client: &Client, mut response: LocalResponse<'_>| {
let context = TemplateContext { let context = TemplateContext {
@ -51,12 +51,12 @@ fn test_name() {
let expected = Template::show(client.rocket(), "index", &context).unwrap(); let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected)); assert_eq!(response.body_string().await, Some(expected));
}); });
} }
#[test] #[rocket::async_test]
fn test_404() { async fn test_404() {
// Check that the error catcher works. // Check that the error catcher works.
dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| { dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| {
let mut map = std::collections::HashMap::new(); let mut map = std::collections::HashMap::new();
@ -64,6 +64,6 @@ fn test_404() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap(); let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound); 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}; use rocket::{self, routes, local::Client};
#[test] #[rocket::async_test]
fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello, Rust 2018!".into())); assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into()));
} }
// Tests unrelated to the example. // Tests unrelated to the example.
@ -34,17 +34,17 @@ mod scoped_uri_tests {
use rocket::local::Client; use rocket::local::Client;
#[test] #[rocket::async_test]
fn test_inner_hello() { async fn test_inner_hello() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello! Try /Rust%202018.".into())); assert_eq!(response.body_string().await, Some("Hello! Try /Rust%202018.".into()));
} }
#[test] #[rocket::async_test]
fn test_hello_name() { async fn test_hello_name() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut response = client.get("/Rust%202018").dispatch(); let mut response = client.get("/Rust%202018").dispatch().await;
assert_eq!(response.body_string_wait().unwrap(), "Hello, Rust 2018! This is /Rust%202018."); 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() 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(); 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(); let client = client();
assert_eq!(client.get(uri).dispatch().status(), Status::NotFound); assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound);
} }
#[test] #[rocket::async_test]
fn test_hello() { async fn test_hello() {
for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] { for &(name, age) in &[("Mike", 22), ("Michael", 80), ("A", 0), ("a", 127)] {
test(&format!("/hello/{}/{}", name, age), test(format!("/hello/{}/{}", name, age),
format!("Hello, {} year old named {}!", age, name)); format!("Hello, {} year old named {}!", age, name)).await;
} }
} }
#[test] #[rocket::async_test]
fn test_failing_hello() { async fn test_failing_hello() {
test_404("/hello/Mike/1000"); test_404("/hello/Mike/1000").await;
test_404("/hello/Mike/-129"); test_404("/hello/Mike/-129").await;
test_404("/hello/Mike/-1"); test_404("/hello/Mike/-1").await;
} }
#[test] #[rocket::async_test]
fn test_hi() { async fn test_hi() {
for name in &["Mike", "A", "123", "hi", "c"] { 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; use rocket::local::Client;
#[test] #[rocket::async_test]
fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello, world!".into())); 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::local::Client;
use rocket::http::{Status, ContentType}; use rocket::http::{Status, ContentType};
#[test] #[rocket::async_test]
fn bad_get_put() { async fn bad_get_put() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Try to get a message with an ID that doesn't exist. // 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); 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("error"));
assert!(body.contains("Resource was not found.")); assert!(body.contains("Resource was not found."));
// Try to get a message with an invalid ID. // Try to get a message with an invalid ID.
let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch(); let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch().await;
let body = res.body_string_wait().unwrap(); let body = res.body_string().await.unwrap();
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
assert!(body.contains("error")); assert!(body.contains("error"));
// Try to put a message without a proper body. // 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); assert_eq!(res.status(), Status::BadRequest);
// Try to put a message for an ID that doesn't exist. // Try to put a message for an ID that doesn't exist.
let res = client.put("/message/80") let res = client.put("/message/80")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(r#"{ "contents": "Bye bye, world!" }"#) .body(r#"{ "contents": "Bye bye, world!" }"#)
.dispatch(); .dispatch().await;
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
} }
#[test] #[rocket::async_test]
fn post_get_put_get() { async fn post_get_put_get() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Check that a message with ID 1 doesn't exist. // 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); assert_eq!(res.status(), Status::NotFound);
// Add a new message with ID 1. // Add a new message with ID 1.
let res = client.post("/message/1") let res = client.post("/message/1")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(r#"{ "contents": "Hello, world!" }"#) .body(r#"{ "contents": "Hello, world!" }"#)
.dispatch(); .dispatch().await;
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
// Check that the message exists with the correct contents. // 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); 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("Hello, world!"));
// Change the message contents. // Change the message contents.
let res = client.put("/message/1") let res = client.put("/message/1")
.header(ContentType::JSON) .header(ContentType::JSON)
.body(r#"{ "contents": "Bye bye, world!" }"#) .body(r#"{ "contents": "Bye bye, world!" }"#)
.dispatch(); .dispatch().await;
assert_eq!(res.status(), Status::Ok); assert_eq!(res.status(), Status::Ok);
// Check that the message exists with the updated contents. // 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); 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("Hello, world!"));
assert!(body.contains("Bye bye, world!")); assert!(body.contains("Bye bye, world!"));
} }

View File

@ -1,13 +1,13 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
#[test] #[rocket::async_test]
fn test_push_pop() { async fn test_push_pop() {
let client = Client::new(super::rocket()).unwrap(); 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); assert_eq!(response.status(), Status::Ok);
let mut response = client.get("/pop").dispatch(); let mut response = client.get("/pop").dispatch().await;
assert_eq!(response.body_string_wait(), Some("test1".to_string())); 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}; use rocket::http::{ContentType, Status};
fn test(uri: &str, content_type: ContentType, status: Status, body: String) { fn test(uri: &str, content_type: ContentType, status: Status, body: String) {
let client = Client::new(rocket()).unwrap(); rocket::async_test(async move {
let mut response = client.get(uri).header(content_type).dispatch(); let client = Client::new(rocket()).unwrap();
assert_eq!(response.status(), status); let mut response = client.get(uri).header(content_type).dispatch().await;
assert_eq!(response.body_string_wait(), Some(body)); assert_eq!(response.status(), status);
assert_eq!(response.body_string().await, Some(body));
})
} }
#[test] #[test]
@ -39,14 +41,14 @@ fn test_upload() {
let response = client.post("/upload") let response = client.post("/upload")
.header(ContentType::Plain) .header(ContentType::Plain)
.body(&expected_body) .body(&expected_body)
.dispatch(); .dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
// Ensure we get back the same body. // 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.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected_body)); assert_eq!(response.body_string().await, Some(expected_body));
} }
#[test] #[test]

View File

@ -8,27 +8,27 @@ struct Message {
contents: String contents: String
} }
#[test] #[rocket::async_test]
fn msgpack_get() { async fn msgpack_get() {
let client = Client::new(rocket()).unwrap(); 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.status(), Status::Ok);
assert_eq!(res.content_type(), Some(ContentType::MsgPack)); assert_eq!(res.content_type(), Some(ContentType::MsgPack));
// Check that the message is `[1, "Hello, world!"]` // 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]); &[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
} }
#[test] #[rocket::async_test]
fn msgpack_post() { async fn msgpack_post() {
// Dispatch request with a message of `[2, "Goodbye, world!"]`. // Dispatch request with a message of `[2, "Goodbye, world!"]`.
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut res = client.post("/message") let mut res = client.post("/message")
.header(ContentType::MsgPack) .header(ContentType::MsgPack)
.body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33]) .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.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 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.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 client = client();
let response = client.get(uri).dispatch(); let response = client.get(uri).dispatch().await;
let location_headers: Vec<_> = response.headers().get("Location").collect(); let location_headers: Vec<_> = response.headers().get("Location").collect();
assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.status(), Status::SeeOther);
assert_eq!(location_headers, vec![expected_location]); assert_eq!(location_headers, vec![expected_location]);
} }
#[test] #[rocket::async_test]
fn test() { async fn test() {
test_200("/users/Sergio", "Hello, Sergio!"); test_200("/users/Sergio", "Hello, Sergio!").await;
test_200("/users/login", 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] #[rocket::async_test]
fn test_redirects() { async fn test_redirects() {
test_303("/", "/users/login"); test_303("/", "/users/login").await;
test_303("/users/unknown", "/users/login"); 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()) from.rfind('/').map(|i| &from[(i + 1)..]).map(|s| s.trim_end().to_string())
} }
#[test] #[rocket::async_test]
fn check_index() { async fn check_index() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Ensure the index returns what we expect. // 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.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain)); 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 { async fn upload_paste(client: &Client, body: &str) -> String {
let mut response = client.post("/").body(body).dispatch(); let mut response = client.post("/").body(body).dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::Plain)); 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 { async fn download_paste(client: &Client, id: &str) -> String {
let mut response = client.get(format!("/{}", id)).dispatch(); let mut response = client.get(format!("/{}", id)).dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
response.body_string_wait().unwrap() response.body_string().await.unwrap()
} }
#[test] #[rocket::async_test]
fn pasting() { async fn pasting() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
// Do a trivial upload, just to make sure it works. // Do a trivial upload, just to make sure it works.
let body_1 = "Hello, world!"; let body_1 = "Hello, world!";
let id_1 = upload_paste(&client, body_1); let id_1 = upload_paste(&client, body_1).await;
assert_eq!(download_paste(&client, &id_1), body_1); assert_eq!(download_paste(&client, &id_1).await, body_1);
// Make sure we can keep getting that paste. // Make sure we can keep getting that paste.
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), body_1); assert_eq!(download_paste(&client, &id_1).await, body_1);
assert_eq!(download_paste(&client, &id_1), body_1); assert_eq!(download_paste(&client, &id_1).await, body_1);
// Upload some unicode. // Upload some unicode.
let body_2 = "こんにちは"; let body_2 = "こんにちは";
let id_2 = upload_paste(&client, body_2); let id_2 = upload_paste(&client, body_2).await;
assert_eq!(download_paste(&client, &id_2), body_2); assert_eq!(download_paste(&client, &id_2).await, body_2);
// Make sure we can get both pastes. // Make sure we can get both pastes.
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_2), body_2); assert_eq!(download_paste(&client, &id_2).await, body_2);
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_2), body_2); assert_eq!(download_paste(&client, &id_2).await, body_2);
// Now a longer upload. // Now a longer upload.
let body_3 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed 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. in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum."; officia deserunt mollit anim id est laborum.";
let id_3 = upload_paste(&client, body_3); let id_3 = upload_paste(&client, body_3).await;
assert_eq!(download_paste(&client, &id_3), body_3); assert_eq!(download_paste(&client, &id_3).await, body_3);
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_2), body_2); assert_eq!(download_paste(&client, &id_2).await, body_2);
} }

View File

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

View File

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

View File

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

View File

@ -6,10 +6,10 @@ fn client() -> Client {
Client::new(rocket).unwrap() Client::new(rocket).unwrap()
} }
#[test] #[rocket::async_test]
fn test_root() { async fn test_root() {
let client = client(); let client = client();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert!(response.body().is_none()); assert!(response.body().is_none());
assert_eq!(response.status(), Status::SeeOther); assert_eq!(response.status(), Status::SeeOther);
@ -22,9 +22,9 @@ fn test_root() {
} }
} }
#[test] #[rocket::async_test]
fn test_login() { async fn test_login() {
let client = client(); let client = client();
let mut r = client.get("/login").dispatch(); let mut r = client.get("/login").dispatch().await;
assert_eq!(r.body_string_wait(), Some("Hi! Please log in before continuing.".into())); 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::local::Client;
use rocket::http::Header; 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 client = Client::new(super::rocket()).unwrap();
let mut req = client.get("/"); let mut req = client.get("/");
for header in headers.iter().cloned() { for header in headers.iter().cloned() {
req.add_header(header); req.add_header(header);
} }
let mut response = req.dispatch(); let mut response = req.dispatch().await;
let expect = format!("Your request contained {} headers!", headers.len()); 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] #[rocket::async_test]
fn test_n_headers() { async fn test_n_headers() {
for i in 0..50 { for i in 0..50 {
let headers = (0..i) let headers = (0..i)
.map(|n| Header::new(n.to_string(), n.to_string())) .map(|n| Header::new(n.to_string(), n.to_string()))
.collect(); .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 super::{rocket, Atomics};
use rocket::local::Client; use rocket::local::Client;
#[test] #[rocket::async_test]
fn test() { async fn test() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
client.get("/").dispatch(); client.get("/").dispatch().await;
let atomics = client.rocket().state::<Atomics>().unwrap(); let atomics = client.rocket().state::<Atomics>().unwrap();
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 2); 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()) 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") let response = client.post("/login")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("username={}&password={}", user, pass)) .body(format!("username={}&password={}", user, pass))
.dispatch(); .dispatch().await;
user_id_cookie(&response) user_id_cookie(&response)
} }
#[test] #[rocket::async_test]
fn redirect_on_index() { async fn redirect_on_index() {
let client = Client::new(rocket()).unwrap(); 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.status(), Status::SeeOther);
assert_eq!(response.headers().get_one("Location"), Some("/login")); assert_eq!(response.headers().get_one("Location"), Some("/login"));
} }
#[test] #[rocket::async_test]
fn can_login() { async fn can_login() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
let mut response = client.get("/login").dispatch(); let mut response = client.get("/login").dispatch().await;
let body = response.body_string_wait().unwrap(); let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Please login to continue.")); assert!(body.contains("Please login to continue."));
} }
#[test] #[rocket::async_test]
fn login_fails() { async fn login_fails() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
assert!(login(&client, "Seergio", "password").is_none()); assert!(login(&client, "Seergio", "password").await.is_none());
assert!(login(&client, "Sergio", "idontknow").is_none()); assert!(login(&client, "Sergio", "idontknow").await.is_none());
} }
#[test] #[rocket::async_test]
fn login_logout_succeeds() { async fn login_logout_succeeds() {
let client = Client::new(rocket()).unwrap(); 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. // Ensure we're logged in.
let mut response = client.get("/").cookie(login_cookie.clone()).dispatch(); let mut response = client.get("/").cookie(login_cookie.clone()).dispatch().await;
let body = response.body_string_wait().unwrap(); let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Logged in with user ID 1")); assert!(body.contains("Logged in with user ID 1"));
// One more. // 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.status(), Status::SeeOther);
assert_eq!(response.headers().get_one("Location"), Some("/")); assert_eq!(response.headers().get_one("Location"), Some("/"));
// Logout. // 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"); let cookie = user_id_cookie(&response).expect("logout cookie");
assert!(cookie.value().is_empty()); assert!(cookie.value().is_empty());
@ -73,8 +73,8 @@ fn login_logout_succeeds() {
assert_eq!(response.headers().get_one("Location"), Some("/login")); assert_eq!(response.headers().get_one("Location"), Some("/login"));
// The page should show the success message, and no errors. // The page should show the success message, and no errors.
let mut response = client.get("/login").dispatch(); let mut response = client.get("/login").dispatch().await;
let body = response.body_string().unwrap(); let body = response.body_string().await.unwrap();
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert!(body.contains("Successfully logged out.")); assert!(body.contains("Successfully logged out."));
assert!(!body.contains("Error")); assert!(!body.contains("Error"));

View File

@ -1,28 +1,28 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
fn register_hit(client: &Client) { async fn register_hit(client: &Client) {
let response = client.get("/").dispatch(); let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
} }
fn get_count(client: &Client) -> usize { async fn get_count(client: &Client) -> usize {
let mut response = client.get("/count").dispatch(); let mut response = client.get("/count").dispatch().await;
response.body_string_wait().and_then(|s| s.parse().ok()).unwrap() response.body_string().await.and_then(|s| s.parse().ok()).unwrap()
} }
#[test] #[rocket::async_test]
fn test_count() { async fn test_count() {
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).unwrap();
// Count should start at 0. // 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); } for _ in 0..99 { register_hit(&client).await; }
assert_eq!(get_count(&client), 99); assert_eq!(get_count(&client).await, 99);
register_hit(&client); register_hit(&client).await;
assert_eq!(get_count(&client), 100); assert_eq!(get_count(&client).await, 100);
} }
#[test] #[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>> where T: Into<Option<&'static str>>
{ {
let client = Client::new(rocket()).unwrap(); 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); assert_eq!(response.status(), status);
let body_data = response.body_bytes().await; let body_data = response.body_bytes().await;
@ -28,37 +28,29 @@ fn read_file_content(path: &str) -> Vec<u8> {
file_content file_content
} }
#[test] #[rocket::async_test]
fn test_index_html() { async fn test_index_html() {
rocket::async_test(async { test_query_file("/", "static/index.html", Status::Ok).await;
test_query_file("/", "static/index.html", Status::Ok).await; test_query_file("/?v=1", "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_query_file("/?this=should&be=ignored", "static/index.html", Status::Ok).await;
})
} }
#[test] #[rocket::async_test]
fn test_hidden_file() { async 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", "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", "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_query_file("/hidden/hi.txt?v=1&a=b", "static/hidden/hi.txt", Status::Ok).await;
})
} }
#[test] #[rocket::async_test]
fn test_icon_file() { async 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; 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] #[rocket::async_test]
fn test_invalid_path() { async 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", 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;
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; use rocket::local::Client;
#[test] #[rocket::async_test]
fn test_root() { async fn test_root() {
let client = Client::new(super::rocket()).unwrap(); 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'. // 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); assert_eq!(res_str.len(), 25000);
for byte in res_str.as_bytes() { for byte in res_str.as_bytes() {
assert_eq!(*byte, b'a'); assert_eq!(*byte, b'a');
} }
} }
#[test] #[rocket::async_test]
fn test_file() { async fn test_file() {
// Create the 'big_file' // Create the 'big_file'
const CONTENTS: &str = "big_file contents...not so big here"; const CONTENTS: &str = "big_file contents...not so big here";
let mut file = File::create(super::FILENAME).expect("create big_file"); let mut file = File::create(super::FILENAME).expect("create big_file");
@ -25,8 +25,8 @@ fn test_file() {
// Get the big file contents, hopefully. // Get the big file contents, hopefully.
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).unwrap();
let mut res = client.get("/big_file").dispatch(); let mut res = client.get("/big_file").dispatch().await;
assert_eq!(res.body_string_wait(), Some(CONTENTS.into())); assert_eq!(res.body_string().await, Some(CONTENTS.into()));
// Delete the 'big_file'. // Delete the 'big_file'.
fs::remove_file(super::FILENAME).expect("remove 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 { macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({ ($method:expr, $path:expr, $test_fn:expr) => ({
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).unwrap();
$test_fn(&client, client.req($method, $path).dispatch()); $test_fn(&client, client.req($method, $path).dispatch().await);
}) })
} }
#[test] #[rocket::async_test]
fn test_root() { async fn test_root() {
// Check that the redirect works. // Check that the redirect works.
for method in &[Get, Head] { for method in &[Get, Head] {
dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| { dispatch!(*method, "/", |_: &Client, mut response: LocalResponse<'_>| {
@ -32,13 +32,13 @@ fn test_root() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap(); let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound); assert_eq!(response.status(), Status::NotFound);
assert_eq!(response.body_string_wait(), Some(expected)); assert_eq!(response.body_string().await, Some(expected));
}); });
} }
} }
#[test] #[rocket::async_test]
fn test_name() { async fn test_name() {
// Check that the /hello/<name> route works. // Check that the /hello/<name> route works.
dispatch!(Get, "/hello/Jack", |client: &Client, mut response: LocalResponse<'_>| { dispatch!(Get, "/hello/Jack", |client: &Client, mut response: LocalResponse<'_>| {
let context = super::TemplateContext { let context = super::TemplateContext {
@ -48,12 +48,12 @@ fn test_name() {
let expected = Template::show(client.rocket(), "index", &context).unwrap(); let expected = Template::show(client.rocket(), "index", &context).unwrap();
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
assert_eq!(response.body_string_wait(), Some(expected)); assert_eq!(response.body_string().await, Some(expected));
}); });
} }
#[test] #[rocket::async_test]
fn test_404() { async fn test_404() {
// Check that the error catcher works. // Check that the error catcher works.
dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| { dispatch!(Get, "/hello/", |client: &Client, mut response: LocalResponse<'_>| {
let mut map = std::collections::HashMap::new(); let mut map = std::collections::HashMap::new();
@ -61,6 +61,6 @@ fn test_404() {
let expected = Template::show(client.rocket(), "error/404", &map).unwrap(); let expected = Template::show(client.rocket(), "error/404", &map).unwrap();
assert_eq!(response.status(), Status::NotFound); 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::local::Client;
use rocket::http::Status; use rocket::http::Status;
#[test] #[rocket::async_test]
fn test_hello() { async fn test_hello() {
let client = Client::new(rocket()).unwrap(); 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.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; use rocket::local::Client;
#[test] #[rocket::async_test]
fn hello_world() { async fn hello_world() {
let rocket = rocket::ignite().mount("/", routes![super::hello]); let rocket = rocket::ignite().mount("/", routes![super::hello]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).unwrap();
let mut response = client.get("/").dispatch(); let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string_wait(), Some("Hello, world!".into())); 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 { macro_rules! run_test {
(|$client:ident, $conn:ident| $block:expr) => ({ (|$client:ident, $conn:ident| $block:expr) => ({
let _lock = DB_LOCK.lock(); 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") client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.body("description=My+first+task") .body("description=My+first+task")
.dispatch(); .dispatch().await;
// Ensure we have one more task in the database. // Ensure we have one more task in the database.
let new_tasks = Task::all(&conn).unwrap(); let new_tasks = Task::all(&conn).unwrap();
@ -46,7 +49,7 @@ fn test_insertion_deletion() {
// Issue a request to delete the task. // Issue a request to delete the task.
let id = new_tasks[0].id.unwrap(); let id = new_tasks[0].id.unwrap();
client.delete(format!("/todo/{}", id)).dispatch(); client.delete(format!("/todo/{}", id)).dispatch().await;
// Ensure it's gone. // Ensure it's gone.
let final_tasks = Task::all(&conn).unwrap(); let final_tasks = Task::all(&conn).unwrap();
@ -64,17 +67,17 @@ fn test_toggle() {
client.post("/todo") client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.body("description=test_for_completion") .body("description=test_for_completion")
.dispatch(); .dispatch().await;
let task = Task::all(&conn).unwrap()[0].clone(); let task = Task::all(&conn).unwrap()[0].clone();
assert_eq!(task.completed, false); assert_eq!(task.completed, false);
// Issue a request to toggle the task; ensure it is completed. // 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); assert_eq!(Task::all(&conn).unwrap()[0].completed, true);
// Issue a request to toggle the task; ensure it's not completed again. // 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); assert_eq!(Task::all(&conn).unwrap()[0].completed, false);
}) })
} }
@ -83,7 +86,6 @@ fn test_toggle() {
fn test_many_insertions() { fn test_many_insertions() {
const ITER: usize = 100; const ITER: usize = 100;
let rng = thread_rng();
run_test!(|client, conn| { run_test!(|client, conn| {
// Get the number of tasks initially. // Get the number of tasks initially.
let init_num = Task::all(&conn).unwrap().len(); let init_num = Task::all(&conn).unwrap().len();
@ -91,11 +93,11 @@ fn test_many_insertions() {
for i in 0..ITER { for i in 0..ITER {
// Issue a request to insert a new task with a random description. // 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") client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.body(format!("description={}", desc)) .body(format!("description={}", desc))
.dispatch(); .dispatch().await;
// Record the description we choose for this iteration. // Record the description we choose for this iteration.
descs.insert(0, desc); 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. // Submit an empty form. We should get a 422 but no flash error.
let res = client.post("/todo") let res = client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.dispatch(); .dispatch().await;
let mut cookies = res.headers().get("Set-Cookie"); let mut cookies = res.headers().get("Set-Cookie");
assert_eq!(res.status(), Status::UnprocessableEntity); assert_eq!(res.status(), Status::UnprocessableEntity);
@ -128,7 +130,7 @@ fn test_bad_form_submissions() {
let res = client.post("/todo") let res = client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.body("description=") .body("description=")
.dispatch(); .dispatch().await;
let mut cookies = res.headers().get("Set-Cookie"); let mut cookies = res.headers().get("Set-Cookie");
assert!(cookies.any(|value| value.contains("error"))); assert!(cookies.any(|value| value.contains("error")));
@ -137,7 +139,7 @@ fn test_bad_form_submissions() {
let res = client.post("/todo") let res = client.post("/todo")
.header(ContentType::Form) .header(ContentType::Form)
.body("evil=smile") .body("evil=smile")
.dispatch(); .dispatch().await;
let mut cookies = res.headers().get("Set-Cookie"); let mut cookies = res.headers().get("Set-Cookie");
assert_eq!(res.status(), Status::UnprocessableEntity); assert_eq!(res.status(), Status::UnprocessableEntity);

View File

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

View File

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