Make 'Fairing::on_attach()' async.

This transitively requires that 'Rocket::inspect()', 'Client::new()',
and 'Client::untracked()' also become async.
This commit is contained in:
Jeb Rosen 2020-06-14 08:57:53 -07:00 committed by Sergio Benitez
parent dea940c7a8
commit b0238e5110
78 changed files with 394 additions and 316 deletions

View File

@ -93,8 +93,8 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea
pub fn fairing() -> impl ::rocket::fairing::Fairing { pub fn fairing() -> impl ::rocket::fairing::Fairing {
use #databases::Poolable; use #databases::Poolable;
::rocket::fairing::AdHoc::on_attach(#fairing_name, |mut rocket| { ::rocket::fairing::AdHoc::on_attach(#fairing_name, |mut rocket| async {
let pool = #databases::database_config(#name, rocket.inspect().config()) let pool = #databases::database_config(#name, rocket.inspect().await.config())
.map(<#conn_type>::pool); .map(<#conn_type>::pool);
match pool { match pool {

View File

@ -548,9 +548,9 @@ pub enum ConfigError {
/// # .extra("databases", databases) /// # .extra("databases", databases)
/// # .expect("custom config okay"); /// # .expect("custom config okay");
/// # /// #
/// # rocket::custom(config).attach(AdHoc::on_attach("Testing", |mut rocket| { /// # rocket::custom(config).attach(AdHoc::on_attach("Testing", |mut rocket| async {
/// # { /// # {
/// let manifest = rocket.inspect(); /// let manifest = rocket.inspect().await;
/// let config = database_config("my_db", manifest.config()).unwrap(); /// let config = database_config("my_db", manifest.config()).unwrap();
/// assert_eq!(config.url, "db/db.sqlite"); /// assert_eq!(config.url, "db/db.sqlite");
/// assert_eq!(config.pool_size, 25); /// assert_eq!(config.pool_size, 25);

View File

@ -151,8 +151,8 @@ impl Fairing for TemplateFairing {
/// The user's callback, if any was supplied, is called to customize the /// The user's callback, if any was supplied, is called to customize the
/// template engines. In debug mode, the `ContextManager::new` method /// template engines. In debug mode, the `ContextManager::new` method
/// initializes a directory watcher for auto-reloading of templates. /// initializes a directory watcher for auto-reloading of templates.
fn on_attach(&self, mut rocket: Rocket) -> Result<Rocket, Rocket> { async fn on_attach(&self, mut rocket: Rocket) -> Result<Rocket, Rocket> {
let manifest = rocket.inspect(); let manifest = rocket.inspect().await;
let config = manifest.config(); let config = manifest.config();
let mut template_root = config.root_relative(DEFAULT_TEMPLATE_DIR); let mut template_root = config.root_relative(DEFAULT_TEMPLATE_DIR);
match config.get_str("template_dir") { match config.get_str("template_dir") {

View File

@ -331,8 +331,9 @@ impl Template {
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// fn main() { /// fn main() {
/// # rocket::async_test(async {
/// let rocket = rocket::ignite().attach(Template::fairing()); /// let rocket = rocket::ignite().attach(Template::fairing());
/// let client = Client::new(rocket).expect("valid rocket"); /// let client = Client::new(rocket).await.expect("valid rocket");
/// ///
/// // Create a `context`. Here, just an empty `HashMap`. /// // Create a `context`. Here, just an empty `HashMap`.
/// let mut context = HashMap::new(); /// let mut context = HashMap::new();
@ -340,6 +341,7 @@ impl Template {
/// # context.insert("test", "test"); /// # context.insert("test", "test");
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let template = Template::show(client.manifest(), "index", context); /// let template = Template::show(client.manifest(), "index", context);
/// # });
/// } /// }
/// ``` /// ```
#[inline] #[inline]

View File

@ -22,8 +22,8 @@ mod rusqlite_integration_test {
#[database("test_db")] #[database("test_db")]
struct SqliteDb(pub rusqlite::Connection); struct SqliteDb(pub rusqlite::Connection);
#[test] #[rocket::async_test]
fn deref_mut_impl_present() { async fn deref_mut_impl_present() {
let mut test_db: BTreeMap<String, Value> = BTreeMap::new(); let mut test_db: BTreeMap<String, Value> = BTreeMap::new();
let mut test_db_opts: BTreeMap<String, Value> = BTreeMap::new(); let mut test_db_opts: BTreeMap<String, Value> = BTreeMap::new();
test_db_opts.insert("url".into(), Value::String(":memory:".into())); test_db_opts.insert("url".into(), Value::String(":memory:".into()));
@ -34,7 +34,7 @@ mod rusqlite_integration_test {
.unwrap(); .unwrap();
let mut rocket = rocket::custom(config).attach(SqliteDb::fairing()); let mut rocket = rocket::custom(config).attach(SqliteDb::fairing());
let mut conn = SqliteDb::get_one(rocket.inspect()).expect("unable to get connection"); let mut conn = SqliteDb::get_one(rocket.inspect().await).expect("unable to get connection");
// Rusqlite's `transaction()` method takes `&mut self`; this tests the // Rusqlite's `transaction()` method takes `&mut self`; this tests the
// presence of a `DerefMut` trait on the generated connection type. // presence of a `DerefMut` trait on the generated connection type.
@ -43,8 +43,8 @@ mod rusqlite_integration_test {
tx.commit().expect("committed transaction"); tx.commit().expect("committed transaction");
} }
#[test] #[rocket::async_test]
fn deref_impl_present() { async fn deref_impl_present() {
let mut test_db: BTreeMap<String, Value> = BTreeMap::new(); let mut test_db: BTreeMap<String, Value> = BTreeMap::new();
let mut test_db_opts: BTreeMap<String, Value> = BTreeMap::new(); let mut test_db_opts: BTreeMap<String, Value> = BTreeMap::new();
test_db_opts.insert("url".into(), Value::String(":memory:".into())); test_db_opts.insert("url".into(), Value::String(":memory:".into()));
@ -55,7 +55,7 @@ mod rusqlite_integration_test {
.unwrap(); .unwrap();
let mut rocket = rocket::custom(config).attach(SqliteDb::fairing()); let mut rocket = rocket::custom(config).attach(SqliteDb::fairing());
let conn = SqliteDb::get_one(rocket.inspect()).expect("unable to get connection"); let conn = SqliteDb::get_one(rocket.inspect().await).expect("unable to get connection");
let _: i32 = conn.query_row("SELECT 1", &[] as &[&dyn ToSql], |row| row.get(0)).expect("get row"); let _: i32 = conn.query_row("SELECT 1", &[] as &[&dyn ToSql], |row| row.get(0)).expect("get row");
} }
} }

View File

@ -34,7 +34,7 @@ mod helmet_tests {
macro_rules! dispatch { macro_rules! dispatch {
($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).await.unwrap();
let response = client.get("/").dispatch().await; let response = client.get("/").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
$closure(response) $closure(response)

View File

@ -73,7 +73,7 @@ mod static_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_static_no_index() { async fn test_static_no_index() {
let client = Client::new(rocket()).expect("valid rocket"); let client = Client::new(rocket()).await.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;
@ -81,7 +81,7 @@ mod static_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_static_hidden() { async fn test_static_hidden() {
let client = Client::new(rocket()).expect("valid rocket"); let client = Client::new(rocket()).await.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;
@ -89,7 +89,7 @@ mod static_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_static_index() { async fn test_static_index() {
let client = Client::new(rocket()).expect("valid rocket"); let client = Client::new(rocket()).await.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;
@ -101,7 +101,7 @@ mod static_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_static_all() { async fn test_static_all() {
let client = Client::new(rocket()).expect("valid rocket"); let client = Client::new(rocket()).await.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;
@ -133,7 +133,7 @@ mod static_tests {
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).await.expect("valid rocket");
let mut response = client.get("/default/ireallydontexist").dispatch().await; let mut response = client.get("/default/ireallydontexist").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);

View File

@ -49,10 +49,10 @@ mod templates_tests {
const ESCAPED_EXPECTED: &'static str const ESCAPED_EXPECTED: &'static str
= "\nh_start\ntitle: _test_\nh_end\n\n\n&lt;script &#x2F;&gt;\n\nfoot\n"; = "\nh_start\ntitle: _test_\nh_end\n\n\n&lt;script &#x2F;&gt;\n\nfoot\n";
#[test] #[rocket::async_test]
fn test_tera_templates() { async fn test_tera_templates() {
let mut rocket = rocket(); let mut rocket = rocket();
let manifest = rocket.inspect(); let manifest = rocket.inspect().await;
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("title", "_test_"); map.insert("title", "_test_");
map.insert("content", "<script />"); map.insert("content", "<script />");
@ -68,7 +68,7 @@ mod templates_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_template_metadata_with_tera() { async fn test_template_metadata_with_tera() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let response = client.get("/tera/txt_test").dispatch().await; let response = client.get("/tera/txt_test").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
@ -94,10 +94,10 @@ mod templates_tests {
const EXPECTED: &'static str const EXPECTED: &'static str
= "Hello _test_!\n\n<main> &lt;script /&gt; hi </main>\nDone.\n\n"; = "Hello _test_!\n\n<main> &lt;script /&gt; hi </main>\nDone.\n\n";
#[test] #[rocket::async_test]
fn test_handlebars_templates() { async fn test_handlebars_templates() {
let mut rocket = rocket(); let mut rocket = rocket();
let manifest = rocket.inspect(); let manifest = rocket.inspect().await;
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("title", "_test_"); map.insert("title", "_test_");
map.insert("content", "<script /> hi"); map.insert("content", "<script /> hi");
@ -109,7 +109,7 @@ mod templates_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_template_metadata_with_handlebars() { async fn test_template_metadata_with_handlebars() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let response = client.get("/hbs/test").dispatch().await; let response = client.get("/hbs/test").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
@ -146,7 +146,7 @@ mod templates_tests {
write_file(&reload_path, INITIAL_TEXT); write_file(&reload_path, INITIAL_TEXT);
// 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()).await.unwrap();
let res = client.get("/is_reloading").dispatch().await; let res = client.get("/is_reloading").dispatch().await;
if res.status() != Status::Ok { if res.status() != Status::Ok {
return; return;

View File

@ -36,7 +36,7 @@ foo!("/hello/<name>", name);
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/easy/327").dispatch().await; let mut response = client.get("/easy/327").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "easy id: 327"); assert_eq!(response.body_string().await.unwrap(), "easy id: 327");
@ -62,7 +62,7 @@ index!(i32);
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "Thing: 100"); assert_eq!(response.body_string().await.unwrap(), "Thing: 100");

View File

@ -23,7 +23,7 @@ pub enum Foo<'r> {
#[rocket::async_test] #[rocket::async_test]
async fn responder_foo() { async fn responder_foo() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).await.expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();
@ -72,7 +72,7 @@ pub struct Bar<'r> {
#[rocket::async_test] #[rocket::async_test]
async fn responder_bar() { async fn responder_bar() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).await.expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();
@ -97,7 +97,7 @@ pub struct Baz {
#[rocket::async_test] #[rocket::async_test]
async fn responder_baz() { async fn responder_baz() {
let client = Client::new(rocket::ignite()).expect("valid rocket"); let client = Client::new(rocket::ignite()).await.expect("valid rocket");
let local_req = client.get("/"); let local_req = client.get("/");
let req = local_req.inner(); let req = local_req.inner();

View File

@ -44,7 +44,7 @@ fn simple(simple: Simple) -> String { simple.0 }
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.post("/f") let mut response = client.post("/f")
.header(ContentType::Form) .header(ContentType::Form)

View File

@ -39,7 +39,7 @@ async fn test_formats() {
.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).await.unwrap();
let mut response = client.post("/").header(ContentType::JSON).dispatch().await; let mut response = client.post("/").header(ContentType::JSON).dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "json"); assert_eq!(response.body_string().await.unwrap(), "json");
@ -85,7 +85,7 @@ 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]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let foo_a = Accept::new(&[MediaType::new("application", "foo").into()]); let foo_a = Accept::new(&[MediaType::new("application", "foo").into()]);
let foo_ct = ContentType::new("application", "foo"); let foo_ct = ContentType::new("application", "foo");

View File

@ -21,7 +21,7 @@ fn get3(_number: u64) -> &'static str { "3" }
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/0").dispatch().await; let mut response = client.get("/0").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "0"); assert_eq!(response.body_string().await.unwrap(), "0");
@ -41,12 +41,12 @@ async fn test_ranking() {
#[get("/<_n>")] #[get("/<_n>")]
fn get0b(_n: u8) { } fn get0b(_n: u8) { }
#[test] #[rocket::async_test]
fn test_rank_collision() { async fn test_rank_collision() {
use rocket::error::LaunchErrorKind; use rocket::error::LaunchErrorKind;
let rocket = rocket::ignite().mount("/", routes![get0, get0b]); let rocket = rocket::ignite().mount("/", routes![get0, get0b]);
let client_result = Client::new(rocket); let client_result = Client::new(rocket).await;
match client_result.as_ref().map_err(|e| e.kind()) { match client_result.as_ref().map_err(|e| e.kind()) {
Err(LaunchErrorKind::Collision(..)) => { /* o.k. */ }, Err(LaunchErrorKind::Collision(..)) => { /* o.k. */ },
Ok(_) => panic!("client succeeded unexpectedly"), Ok(_) => panic!("client succeeded unexpectedly"),

View File

@ -85,7 +85,7 @@ async fn test_full_route() {
.mount("/1", routes![post1]) .mount("/1", routes![post1])
.mount("/2", routes![post2]); .mount("/2", routes![post2]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let a = "A%20A"; let a = "A%20A";
let name = "Bob%20McDonald"; let name = "Bob%20McDonald";

View File

@ -174,9 +174,9 @@
//! //!
//! fn main() { //! fn main() {
//! rocket::ignite() //! rocket::ignite()
//! .attach(AdHoc::on_attach("Token Config", |mut rocket| { //! .attach(AdHoc::on_attach("Token Config", |mut rocket| async {
//! println!("Adding token managed state from config..."); //! println!("Adding token managed state from config...");
//! let token_val = rocket.inspect().config().get_int("token").unwrap_or(-1); //! let token_val = rocket.inspect().await.config().get_int("token").unwrap_or(-1);
//! Ok(rocket.manage(Token(token_val))) //! Ok(rocket.manage(Token(token_val)))
//! })) //! }))
//! # ; //! # ;

View File

@ -1,6 +1,6 @@
use std::sync::Mutex; use std::sync::Mutex;
use futures_util::future::BoxFuture; use futures_util::future::{Future, BoxFuture};
use crate::{Manifest, Rocket, Request, Response, Data}; use crate::{Manifest, Rocket, Request, Response, Data};
use crate::fairing::{Fairing, Kind, Info}; use crate::fairing::{Fairing, Kind, Info};
@ -46,7 +46,7 @@ pub struct AdHoc {
enum AdHocKind { enum AdHocKind {
/// An ad-hoc **attach** fairing. Called when the fairing is attached. /// An ad-hoc **attach** fairing. Called when the fairing is attached.
Attach(Mutex<Option<Box<dyn FnOnce(Rocket) -> Result<Rocket, Rocket> + Send + 'static>>>), Attach(Mutex<Option<Box<dyn FnOnce(Rocket) -> BoxFuture<'static, Result<Rocket, Rocket>> + Send + 'static>>>),
/// An ad-hoc **launch** fairing. Called just before Rocket launches. /// An ad-hoc **launch** fairing. Called just before Rocket launches.
Launch(Mutex<Option<Box<dyn FnOnce(&Manifest) + Send + 'static>>>), Launch(Mutex<Option<Box<dyn FnOnce(&Manifest) + Send + 'static>>>),
/// An ad-hoc **request** fairing. Called when a request is received. /// An ad-hoc **request** fairing. Called when a request is received.
@ -66,12 +66,14 @@ impl AdHoc {
/// use rocket::fairing::AdHoc; /// use rocket::fairing::AdHoc;
/// ///
/// // The no-op attach fairing. /// // The no-op attach fairing.
/// let fairing = AdHoc::on_attach("No-Op", |rocket| Ok(rocket)); /// let fairing = AdHoc::on_attach("No-Op", |rocket| async { Ok(rocket) });
/// ``` /// ```
pub fn on_attach<F: Send + 'static>(name: &'static str, f: F) -> AdHoc pub fn on_attach<F, Fut>(name: &'static str, f: F) -> AdHoc
where F: FnOnce(Rocket) -> Result<Rocket, Rocket> where
F: FnOnce(Rocket) -> Fut + Send + 'static,
Fut: Future<Output=Result<Rocket, Rocket>> + Send + 'static,
{ {
AdHoc { name, kind: AdHocKind::Attach(Mutex::new(Some(Box::new(f)))) } AdHoc { name, kind: AdHocKind::Attach(Mutex::new(Some(Box::new(|rocket| Box::pin(f(rocket)))))) }
} }
/// Constructs an `AdHoc` launch fairing named `name`. The function `f` will /// Constructs an `AdHoc` launch fairing named `name`. The function `f` will
@ -153,11 +155,13 @@ impl Fairing for AdHoc {
Info { name: self.name, kind } Info { name: self.name, kind }
} }
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { async fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
if let AdHocKind::Attach(ref mutex) = self.kind { if let AdHocKind::Attach(ref mutex) = self.kind {
let mut opt = mutex.lock().expect("AdHoc::Attach lock"); let f = mutex.lock()
let f = opt.take().expect("internal error: `on_attach` one-call invariant broken"); .expect("AdHoc::Attach lock")
f(rocket) .take()
.expect("internal error: `on_attach` one-call invariant broken");
f(rocket).await
} else { } else {
Ok(rocket) Ok(rocket)
} }

View File

@ -20,12 +20,12 @@ impl Fairings {
Fairings::default() Fairings::default()
} }
pub fn attach(&mut self, fairing: Box<dyn Fairing>, mut rocket: Rocket) -> Rocket { pub async fn attach(&mut self, fairing: Box<dyn Fairing>, mut rocket: Rocket) -> Rocket {
// Run the `on_attach` callback if this is an 'attach' fairing. // Run the `on_attach` callback if this is an 'attach' fairing.
let kind = fairing.info().kind; let kind = fairing.info().kind;
let name = fairing.info().name; let name = fairing.info().name;
if kind.is(Kind::Attach) { if kind.is(Kind::Attach) {
rocket = fairing.on_attach(rocket) rocket = fairing.on_attach(rocket).await
.unwrap_or_else(|r| { self.attach_failures.push(name); r }) .unwrap_or_else(|r| { self.attach_failures.push(name); r })
} }

View File

@ -207,7 +207,7 @@ pub use self::info_kind::{Info, Kind};
/// # unimplemented!() /// # unimplemented!()
/// } /// }
/// ///
/// fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { /// async fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
/// /* ... */ /// /* ... */
/// # unimplemented!() /// # unimplemented!()
/// } /// }
@ -415,7 +415,7 @@ pub trait Fairing: Send + Sync + 'static {
/// ## Default Implementation /// ## Default Implementation
/// ///
/// The default implementation of this method simply returns `Ok(rocket)`. /// The default implementation of this method simply returns `Ok(rocket)`.
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { Ok(rocket) } async fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { Ok(rocket) }
/// The launch callback. /// The launch callback.
/// ///
@ -465,8 +465,8 @@ impl<T: Fairing> Fairing for std::sync::Arc<T> {
} }
#[inline] #[inline]
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> { async fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
(self as &T).on_attach(rocket) (self as &T).on_attach(rocket).await
} }
#[inline] #[inline]

View File

@ -55,13 +55,13 @@ use crate::error::LaunchError;
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// # let _ = async { /// # rocket::async_test(async {
/// let rocket = rocket::ignite(); /// let rocket = rocket::ignite();
/// let client = Client::new(rocket).expect("valid rocket"); /// let client = Client::new(rocket).await.expect("valid rocket");
/// let response = client.post("/") /// let response = client.post("/")
/// .body("Hello, world!") /// .body("Hello, world!")
/// .dispatch().await; /// .dispatch().await;
/// # }; /// # });
/// ``` /// ```
/// ///
/// [`new()`]: #method.new /// [`new()`]: #method.new
@ -78,8 +78,8 @@ impl Client {
/// Constructs a new `Client`. If `tracked` is `true`, an empty `CookieJar` /// Constructs a new `Client`. If `tracked` is `true`, an empty `CookieJar`
/// is created for cookie tracking. Otherwise, the internal `CookieJar` is /// is created for cookie tracking. Otherwise, the internal `CookieJar` is
/// set to `None`. /// set to `None`.
fn _new(rocket: Rocket, tracked: bool) -> Result<Client, LaunchError> { async fn _new(rocket: Rocket, tracked: bool) -> Result<Client, LaunchError> {
let mut manifest = rocket.actualize_and_take_manifest(); let mut manifest = rocket.actualize_and_take_manifest().await;
manifest.prelaunch_check()?; manifest.prelaunch_check()?;
let cookies = match tracked { let cookies = match tracked {
@ -117,11 +117,13 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # let _ = async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// # };
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn new(rocket: Rocket) -> Result<Client, LaunchError> { pub async fn new(rocket: Rocket) -> Result<Client, LaunchError> {
Client::_new(rocket, true) Client::_new(rocket, true).await
} }
/// Construct a new `Client` from an instance of `Rocket` _without_ cookie /// Construct a new `Client` from an instance of `Rocket` _without_ cookie
@ -142,11 +144,13 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::untracked(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::untracked(rocket::ignite()).await.expect("valid rocket");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn untracked(rocket: Rocket) -> Result<Client, LaunchError> { pub async fn untracked(rocket: Rocket) -> Result<Client, LaunchError> {
Client::_new(rocket, false) Client::_new(rocket, false).await
} }
/// Returns a reference to the `Manifest` of the `Rocket` this client is /// Returns a reference to the `Manifest` of the `Rocket` this client is
@ -157,11 +161,13 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// # rocket::async_test(async {
/// let my_rocket = rocket::ignite(); /// let my_rocket = rocket::ignite();
/// let client = Client::new(my_rocket).expect("valid rocket"); /// let client = Client::new(my_rocket).await.expect("valid rocket");
/// ///
/// // get access to the manifest within `client` /// // get access to the manifest within `client`
/// let manifest = client.manifest(); /// let manifest = client.manifest();
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn manifest(&self) -> &Manifest { pub fn manifest(&self) -> &Manifest {
@ -180,8 +186,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.get("/hello"); /// let req = client.get("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn get<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> { pub fn get<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
@ -200,8 +208,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.put("/hello"); /// let req = client.put("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn put<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> { pub fn put<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
@ -221,11 +231,13 @@ impl Client {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::ContentType; /// use rocket::http::ContentType;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// ///
/// let req = client.post("/hello") /// let req = client.post("/hello")
/// .body("field=value&otherField=123") /// .body("field=value&otherField=123")
/// .header(ContentType::Form); /// .header(ContentType::Form);
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn post<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> { pub fn post<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
@ -244,8 +256,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.delete("/hello"); /// let req = client.delete("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn delete<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c> pub fn delete<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
@ -266,8 +280,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.options("/hello"); /// let req = client.options("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn options<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c> pub fn options<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
@ -288,8 +304,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.head("/hello"); /// let req = client.head("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn head<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c> pub fn head<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
@ -310,8 +328,10 @@ impl Client {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.patch("/hello"); /// let req = client.patch("/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn patch<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c> pub fn patch<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
@ -333,8 +353,10 @@ impl Client {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::Method; /// use rocket::http::Method;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.req(Method::Get, "/hello"); /// let req = client.req(Method::Get, "/hello");
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c> pub fn req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c>

View File

@ -23,8 +23,10 @@
//! ```rust //! ```rust
//! # use rocket::local::Client; //! # use rocket::local::Client;
//! # let rocket = rocket::ignite(); //! # let rocket = rocket::ignite();
//! let client = Client::new(rocket).expect("valid rocket instance"); //! # rocket::async_test(async {
//! let client = Client::new(rocket).await.expect("valid rocket instance");
//! # let _ = client; //! # let _ = client;
//! # });
//! ``` //! ```
//! //!
//! 3. Construct requests using the `Client` instance. //! 3. Construct requests using the `Client` instance.
@ -32,9 +34,11 @@
//! ```rust //! ```rust
//! # use rocket::local::Client; //! # use rocket::local::Client;
//! # let rocket = rocket::ignite(); //! # let rocket = rocket::ignite();
//! # let client = Client::new(rocket).unwrap(); //! # rocket::async_test(async {
//! # let client = Client::new(rocket).await.unwrap();
//! let req = client.get("/"); //! let req = client.get("/");
//! # let _ = req; //! # let _ = req;
//! # });
//! ``` //! ```
//! //!
//! 3. Dispatch the request to retrieve the response. //! 3. Dispatch the request to retrieve the response.
@ -42,12 +46,12 @@
//! ```rust //! ```rust
//! # use rocket::local::Client; //! # use rocket::local::Client;
//! # let rocket = rocket::ignite(); //! # let rocket = rocket::ignite();
//! # let client = Client::new(rocket).unwrap(); //! # rocket::async_test(async {
//! # let client = Client::new(rocket).await.unwrap();
//! # let req = client.get("/"); //! # let req = client.get("/");
//! # let _ = async {
//! let response = req.dispatch().await; //! 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:
@ -55,13 +59,13 @@
//! ```rust //! ```rust
//! use rocket::local::Client; //! use rocket::local::Client;
//! //!
//! # let _ = async { //! # rocket::async_test(async {
//! let client = Client::new(rocket::ignite()).expect("valid rocket"); //! let client = Client::new(rocket::ignite()).await.expect("valid rocket");
//! let response = client.post("/") //! let response = client.post("/")
//! .body("Hello, world!") //! .body("Hello, world!")
//! .dispatch().await; //! .dispatch().await;
//! # let _ = response; //! # let _ = response;
//! # }; //! # });
//! ``` //! ```
//! //!
//! # Unit/Integration Testing //! # Unit/Integration Testing

View File

@ -28,12 +28,14 @@ use crate::local::Client;
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::{ContentType, Cookie}; /// use rocket::http::{ContentType, Cookie};
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.post("/") /// let req = client.post("/")
/// .header(ContentType::JSON) /// .header(ContentType::JSON)
/// .remote("127.0.0.1:8000".parse().unwrap()) /// .remote("127.0.0.1:8000".parse().unwrap())
/// .cookie(Cookie::new("name", "value")) /// .cookie(Cookie::new("name", "value"))
/// .body(r#"{ "value": 42 }"#); /// .body(r#"{ "value": 42 }"#);
/// # });
/// ``` /// ```
/// ///
/// # Dispatching /// # Dispatching
@ -125,9 +127,11 @@ impl<'c> LocalRequest<'c> {
/// ```rust /// ```rust
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// let client = Client::new(rocket::ignite()).expect("valid rocket"); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
/// let req = client.get("/"); /// let req = client.get("/");
/// let inner_req = req.inner(); /// let inner_req = req.inner();
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn inner(&self) -> &Request<'c> { pub fn inner(&self) -> &Request<'c> {
@ -166,9 +170,11 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::ContentType; /// use rocket::http::ContentType;
/// ///
/// # rocket::async_test(async {
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let client = Client::new(rocket::ignite()).unwrap(); /// let client = Client::new(rocket::ignite()).await.unwrap();
/// let req = client.get("/").header(ContentType::JSON); /// let req = client.get("/").header(ContentType::JSON);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self { pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self {
@ -186,9 +192,11 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::ContentType; /// use rocket::http::ContentType;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// let mut req = client.get("/"); /// let mut req = client.get("/");
/// req.add_header(ContentType::JSON); /// req.add_header(ContentType::JSON);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) { pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) {
@ -204,9 +212,11 @@ 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()).await.unwrap();
/// let address = "8.8.8.8:80".parse().unwrap(); /// let address = "8.8.8.8:80".parse().unwrap();
/// let req = client.get("/").remote(address); /// let req = client.get("/").remote(address);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn remote(mut self, address: SocketAddr) -> Self { pub fn remote(mut self, address: SocketAddr) -> Self {
@ -224,11 +234,13 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::Cookie; /// use rocket::http::Cookie;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let req = client.get("/") /// let req = client.get("/")
/// .cookie(Cookie::new("username", "sb")) /// .cookie(Cookie::new("username", "sb"))
/// .cookie(Cookie::new("user_id", "12")); /// .cookie(Cookie::new("user_id", "12"));
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn cookie(self, cookie: Cookie<'_>) -> Self { pub fn cookie(self, cookie: Cookie<'_>) -> Self {
@ -246,10 +258,12 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::Cookie; /// use rocket::http::Cookie;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// let cookies = vec![Cookie::new("a", "b"), Cookie::new("c", "d")]; /// let cookies = vec![Cookie::new("a", "b"), Cookie::new("c", "d")];
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let req = client.get("/").cookies(cookies); /// let req = client.get("/").cookies(cookies);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn cookies(self, cookies: Vec<Cookie<'_>>) -> Self { pub fn cookies(self, cookies: Vec<Cookie<'_>>) -> Self {
@ -275,9 +289,11 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::Cookie; /// use rocket::http::Cookie;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let req = client.get("/").private_cookie(Cookie::new("user_id", "sb")); /// let req = client.get("/").private_cookie(Cookie::new("user_id", "sb"));
/// # });
/// ``` /// ```
#[inline] #[inline]
#[cfg(feature = "private-cookies")] #[cfg(feature = "private-cookies")]
@ -301,11 +317,13 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::ContentType; /// use rocket::http::ContentType;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// # #[allow(unused_variables)] /// # #[allow(unused_variables)]
/// let req = client.post("/") /// let req = client.post("/")
/// .header(ContentType::JSON) /// .header(ContentType::JSON)
/// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#); /// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self { pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
@ -323,9 +341,11 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// use rocket::http::ContentType; /// use rocket::http::ContentType;
/// ///
/// let client = Client::new(rocket::ignite()).unwrap(); /// # rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).await.unwrap();
/// let mut req = client.post("/").header(ContentType::JSON); /// let mut req = client.post("/").header(ContentType::JSON);
/// req.set_body(r#"{ "key": "value", "array": [1, 2, 3], }"#); /// req.set_body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
/// # });
/// ``` /// ```
#[inline] #[inline]
pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) { pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) {
@ -342,8 +362,10 @@ 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()).await.unwrap();
/// let response = client.get("/").dispatch(); /// let response = client.get("/").dispatch();
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub async fn dispatch(mut self) -> LocalResponse<'c> { pub async fn dispatch(mut self) -> LocalResponse<'c> {
@ -371,7 +393,7 @@ impl<'c> LocalRequest<'c> {
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// rocket::async_test(async { /// rocket::async_test(async {
/// let client = Client::new(rocket::ignite()).unwrap(); /// let client = Client::new(rocket::ignite()).await.unwrap();
/// ///
/// let mut req = client.get("/"); /// let mut req = client.get("/");
/// let response_a = req.mut_dispatch().await; /// let response_a = req.mut_dispatch().await;

View File

@ -99,9 +99,11 @@ use crate::http::Status;
/// state.0.to_string() /// state.0.to_string()
/// } /// }
/// ///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(MyManagedState(127)); /// let mut rocket = rocket::ignite().manage(MyManagedState(127));
/// let state = State::from(rocket.inspect()).expect("managing `MyManagedState`"); /// let state = State::from(rocket.inspect().await).expect("managing `MyManagedState`");
/// assert_eq!(handler(state), "127"); /// assert_eq!(handler(state), "127");
/// # });
/// ``` /// ```
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct State<'r, T: Send + Sync + 'static>(&'r T); pub struct State<'r, T: Send + Sync + 'static>(&'r T);
@ -152,14 +154,16 @@ impl<'r, T: Send + Sync + 'static> State<'r, T> {
/// #[derive(Debug, PartialEq)] /// #[derive(Debug, PartialEq)]
/// struct Unmanaged(usize); /// struct Unmanaged(usize);
/// ///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(Managed(7)); /// let mut rocket = rocket::ignite().manage(Managed(7));
/// let manifest = rocket.inspect(); /// let manifest = rocket.inspect().await;
/// ///
/// let state: Option<State<Managed>> = State::from(manifest); /// let state: Option<State<Managed>> = State::from(manifest);
/// assert_eq!(state.map(|s| s.inner()), Some(&Managed(7))); /// assert_eq!(state.map(|s| s.inner()), Some(&Managed(7)));
/// ///
/// let state: Option<State<Unmanaged>> = State::from(manifest); /// let state: Option<State<Unmanaged>> = State::from(manifest);
/// assert_eq!(state, None); /// assert_eq!(state, None);
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn from(manifest: &'r Manifest) -> Option<Self> { pub fn from(manifest: &'r Manifest) -> Option<Self> {

View File

@ -52,7 +52,7 @@ impl<'r, R> Created<R> {
/// ///
/// # rocket::async_test(async move { /// # rocket::async_test(async move {
/// # let rocket = rocket::ignite().mount("/", routes![create]); /// # let rocket = rocket::ignite().mount("/", routes![create]);
/// # let client = Client::new(rocket).unwrap(); /// # let client = Client::new(rocket).await.unwrap();
/// let mut response = client.get("/").dispatch().await; /// let mut response = client.get("/").dispatch().await;
/// ///
/// let loc = response.headers().get_one("Location"); /// let loc = response.headers().get_one("Location");
@ -84,7 +84,7 @@ impl<'r, R> Created<R> {
/// ///
/// # rocket::async_test(async move { /// # rocket::async_test(async move {
/// # let rocket = rocket::ignite().mount("/", routes![create]); /// # let rocket = rocket::ignite().mount("/", routes![create]);
/// # let client = Client::new(rocket).unwrap(); /// # let client = Client::new(rocket).await.unwrap();
/// let mut response = client.get("/").dispatch().await; /// let mut response = client.get("/").dispatch().await;
/// ///
/// let body = response.body_string().await; /// let body = response.body_string().await;
@ -122,7 +122,7 @@ impl<'r, R> Created<R> {
/// ///
/// # rocket::async_test(async move { /// # rocket::async_test(async move {
/// # let rocket = rocket::ignite().mount("/", routes![create]); /// # let rocket = rocket::ignite().mount("/", routes![create]);
/// # let client = Client::new(rocket).unwrap(); /// # let client = Client::new(rocket).await.unwrap();
/// let mut response = client.get("/").dispatch().await; /// let mut response = client.get("/").dispatch().await;
/// ///
/// let body = response.body_string().await; /// let body = response.body_string().await;

View File

@ -407,13 +407,13 @@ impl Manifest {
} }
#[inline] #[inline]
fn _attach(mut self, fairing: Box<dyn Fairing>) -> Self { async fn _attach(mut self, fairing: Box<dyn Fairing>) -> Self {
// Attach (and run attach) fairings, which requires us to move `self`. // Attach (and run attach) fairings, which requires us to move `self`.
let mut fairings = mem::replace(&mut self.fairings, Fairings::new()); let mut fairings = mem::replace(&mut self.fairings, Fairings::new());
let mut rocket = Rocket { manifest: Some(self), pending: vec![] }; let mut rocket = Rocket { manifest: Some(self), pending: vec![] };
rocket = fairings.attach(fairing, rocket); rocket = fairings.attach(fairing, rocket).await;
self = rocket.actualize_and_take_manifest(); self = rocket.actualize_and_take_manifest().await;
// Make sure we keep all fairings around: the old and newly added ones! // Make sure we keep all fairings around: the old and newly added ones!
fairings.append(self.fairings); fairings.append(self.fairings);
@ -811,33 +811,50 @@ impl Rocket {
self self
} }
pub(crate) fn actualize_manifest(&mut self) { // Instead of requiring the user to individually `await` each call to
while !self.pending.is_empty() { // `attach()`, some operations are queued in `self.pending`. Functions that
// We need to preserve insertion order here, // want to provide read access to any data from the Manifest, such as
// so we can't use `self.pending.pop()` // `inspect()`, need to apply those pending operations first.
let op = self.pending.remove(0); //
let manifest = self.manifest.take().expect("TODO error message"); // This function returns a future that executes those pending operations,
self.manifest = Some(match op { // requiring only a single `await` at the call site. After completion,
BuildOperation::Mount(base, routes) => manifest._mount(base, routes), // `self.pending` will be empty and `self.manifest` will reflect all pending
BuildOperation::Register(catchers) => manifest._register(catchers), // changes.
BuildOperation::Manage(callback) => manifest._manage(callback), //
BuildOperation::Attach(fairing) => manifest._attach(fairing), // Note that this returns a boxed future, because `_attach()` calls this
}); // function again creating a cycle.
} pub(crate) fn actualize_manifest(&mut self) -> BoxFuture<'_, ()> {
Box::pin(async move {
while !self.pending.is_empty() {
// We need to preserve insertion order here,
// so we can't use `self.pending.pop()`
let op = self.pending.remove(0);
let manifest = self.manifest.take()
.expect("internal error: manifest was taken and not replaced. \
Was `inspect()` called but not polled to completion?");
self.manifest = Some(match op {
BuildOperation::Mount(base, routes) => manifest._mount(base, routes),
BuildOperation::Register(catchers) => manifest._register(catchers),
BuildOperation::Manage(callback) => manifest._manage(callback),
BuildOperation::Attach(fairing) => manifest._attach(fairing).await,
});
}
})
} }
pub(crate) fn actualize_and_take_manifest(mut self) -> Manifest { pub(crate) async fn actualize_and_take_manifest(mut self) -> Manifest {
self.actualize_manifest(); self.actualize_manifest().await;
self.manifest.take().expect("internal error: actualize_manifest() should have replaced self.manifest") self.manifest.take().expect("internal error: actualize_manifest() should have replaced self.manifest")
} }
/// Returns a `Future` that drives the server, listening for and dispathcing /// Returns a `Future` that drives the server, listening for and dispatching
/// requests to mounted routes and catchers. The `Future` completes when the /// requests to mounted routes and catchers. The `Future` completes when the
/// server is shut down (via a [`ShutdownHandle`] or encounters a fatal /// server is shut down, via a [`ShutdownHandle`], or encounters a fatal
/// error. If the `ctrl_c_shutdown` feature is enabled, the server will /// error. If the `ctrl_c_shutdown` feature is enabled, the server will
/// also shut down once `Ctrl-C` is pressed. /// also shut down once `Ctrl-C` is pressed.
/// ///
/// # Error /// # Error
///
/// If there is a problem starting the application, an [`Error`] is /// If there is a problem starting the application, an [`Error`] is
/// returned. Note that a value of type `Error` panics if dropped /// returned. Note that a value of type `Error` panics if dropped
/// without first being inspected. See the [`Error`] documentation for /// without first being inspected. See the [`Error`] documentation for
@ -859,11 +876,10 @@ impl Rocket {
use crate::error::Error::Launch; use crate::error::Error::Launch;
let mut manifest = self.actualize_and_take_manifest(); let mut manifest = self.actualize_and_take_manifest().await;
manifest.prelaunch_check().map_err(crate::error::Error::Launch)?; manifest.prelaunch_check().map_err(crate::error::Error::Launch)?;
let config = manifest.config(); let config = manifest.config();
let full_addr = format!("{}:{}", config.address, config.port); let full_addr = format!("{}:{}", config.address, config.port);
let addrs = match full_addr.to_socket_addrs() { let addrs = match full_addr.to_socket_addrs() {
Ok(a) => a.collect::<Vec<_>>(), Ok(a) => a.collect::<Vec<_>>(),
@ -961,13 +977,10 @@ impl Rocket {
/// rocket::ignite().launch(); /// rocket::ignite().launch();
/// # } /// # }
/// ``` /// ```
pub fn launch(mut self) -> Result<(), crate::error::Error> { pub fn launch(self) -> Result<(), crate::error::Error> {
let workers = self.inspect().config().workers as usize;
// Initialize the tokio runtime // Initialize the tokio runtime
let mut runtime = tokio::runtime::Builder::new() let mut runtime = tokio::runtime::Builder::new()
.threaded_scheduler() .threaded_scheduler()
.core_threads(workers)
.enable_all() .enable_all()
.build() .build()
.expect("Cannot build runtime!"); .expect("Cannot build runtime!");
@ -976,24 +989,27 @@ impl Rocket {
} }
pub(crate) fn _manifest(&self) -> &Manifest { pub(crate) fn _manifest(&self) -> &Manifest {
self.manifest.as_ref().expect("TODO error message") self.manifest.as_ref().expect("internal error: manifest was taken and not replaced. \
Was `inspect()` called but not polled to completion?")
} }
/// Access the current state of this `Rocket` instance. /// Access the current state of this `Rocket` instance.
/// ///
/// The `Mnaifest` type provides methods such as [`Manifest::routes`] /// The `Manifest` type provides methods such as [`Manifest::routes()`]
/// and [`Manifest::state`]. This method is called to get an `Manifest` /// and [`Manifest::state()`]. This method is called to get a `Manifest`
/// instance. /// instance.
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite(); /// let mut rocket = rocket::ignite();
/// let config = rocket.inspect().config(); /// let config = rocket.inspect().await.config();
/// # let _ = config; /// # let _ = config;
/// # });
/// ``` /// ```
pub fn inspect(&mut self) -> &Manifest { pub async fn inspect(&mut self) -> &Manifest {
self.actualize_manifest(); self.actualize_manifest().await;
self._manifest() self._manifest()
} }
} }
@ -1009,8 +1025,9 @@ impl Manifest {
/// # #![feature(proc_macro_hygiene)] /// # #![feature(proc_macro_hygiene)]
/// # use std::{thread, time::Duration}; /// # use std::{thread, time::Duration};
/// # /// #
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite(); /// let mut rocket = rocket::ignite();
/// let handle = rocket.inspect().get_shutdown_handle(); /// let handle = rocket.inspect().await.get_shutdown_handle();
/// ///
/// # if false { /// # if false {
/// thread::spawn(move || { /// thread::spawn(move || {
@ -1022,6 +1039,7 @@ impl Manifest {
/// let shutdown_result = rocket.launch(); /// let shutdown_result = rocket.launch();
/// assert!(shutdown_result.is_ok()); /// assert!(shutdown_result.is_ok());
/// # } /// # }
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn get_shutdown_handle(&self) -> ShutdownHandle { pub fn get_shutdown_handle(&self) -> ShutdownHandle {
@ -1045,11 +1063,12 @@ impl Manifest {
/// } /// }
/// ///
/// fn main() { /// fn main() {
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite() /// let mut rocket = rocket::ignite()
/// .mount("/", routes![hello]) /// .mount("/", routes![hello])
/// .mount("/hi", routes![hello]); /// .mount("/hi", routes![hello]);
/// ///
/// for route in rocket.inspect().routes() { /// for route in rocket.inspect().await.routes() {
/// match route.base() { /// match route.base() {
/// "/" => assert_eq!(route.uri.path(), "/hello"), /// "/" => assert_eq!(route.uri.path(), "/hello"),
/// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"), /// "/hi" => assert_eq!(route.uri.path(), "/hi/hello"),
@ -1057,7 +1076,8 @@ impl Manifest {
/// } /// }
/// } /// }
/// ///
/// assert_eq!(rocket.inspect().routes().count(), 2); /// assert_eq!(rocket.inspect().await.routes().count(), 2);
/// # });
/// } /// }
/// ``` /// ```
#[inline(always)] #[inline(always)]
@ -1074,11 +1094,13 @@ impl Manifest {
/// #[derive(PartialEq, Debug)] /// #[derive(PartialEq, Debug)]
/// struct MyState(&'static str); /// struct MyState(&'static str);
/// ///
/// # rocket::async_test(async {
/// let mut rocket = rocket::ignite().manage(MyState("hello!")); /// let mut rocket = rocket::ignite().manage(MyState("hello!"));
/// assert_eq!(rocket.inspect().state::<MyState>(), Some(&MyState("hello!"))); /// assert_eq!(rocket.inspect().await.state::<MyState>(), Some(&MyState("hello!")));
/// ///
/// let client = rocket::local::Client::new(rocket).expect("valid rocket"); /// let client = rocket::local::Client::new(rocket).await.expect("valid rocket");
/// assert_eq!(client.manifest().state::<MyState>(), Some(&MyState("hello!"))); /// assert_eq!(client.manifest().state::<MyState>(), Some(&MyState("hello!")));
/// # });
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> { pub fn state<T: Send + Sync + 'static>(&self) -> Option<&T> {

View File

@ -21,7 +21,7 @@ mod test_absolute_uris_okay {
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let response = client.get("/google").dispatch().await; let response = client.get("/google").dispatch().await;
let location = response.headers().get_one("Location"); let location = response.headers().get_one("Location");

View File

@ -22,7 +22,7 @@ mod conditionally_set_server_header {
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let response = client.get("/do_not_overwrite").dispatch().await; let response = client.get("/do_not_overwrite").dispatch().await;
let server = response.headers().get_one("Server"); let server = response.headers().get_one("Server");

View File

@ -48,7 +48,7 @@ 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).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "hello"); assert_eq!(response.body_string().await.unwrap(), "hello");

View File

@ -42,7 +42,7 @@ mod fairing_before_head_strip {
}) })
})); }));
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let mut response = client.head("/").dispatch().await; 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());
@ -73,7 +73,7 @@ mod fairing_before_head_strip {
}) })
})); }));
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let mut response = client.head("/").dispatch().await; 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

@ -30,7 +30,7 @@ mod flash_lazy_remove_tests {
async 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).await.unwrap();
// Ensure the cookie's not there at first. // Ensure the cookie's not there at first.
let response = client.get("/unused").dispatch().await; let response = client.get("/unused").dispatch().await;

View File

@ -22,7 +22,7 @@ mod tests {
#[rocket::async_test] #[rocket::async_test]
async 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])).await.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")
@ -33,7 +33,7 @@ mod tests {
#[rocket::async_test] #[rocket::async_test]
async 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])).await.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")

View File

@ -21,7 +21,7 @@ mod tests {
use rocket::http::Status; use rocket::http::Status;
async 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])).await.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))

View File

@ -47,7 +47,7 @@ mod head_handling_tests {
#[rocket::async_test] #[rocket::async_test]
async fn auto_head() { async fn auto_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); let client = Client::new(rocket::ignite().mount("/", routes())).await.unwrap();
let mut response = client.head("/").dispatch().await; 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).await; assert_empty_sized_body(response.body().unwrap(), 13).await;
@ -62,7 +62,7 @@ mod head_handling_tests {
#[rocket::async_test] #[rocket::async_test]
async fn user_head() { async fn user_head() {
let client = Client::new(rocket::ignite().mount("/", routes())).unwrap(); let client = Client::new(rocket::ignite().mount("/", routes())).await.unwrap();
let mut response = client.head("/other").dispatch().await; 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).await; assert_empty_sized_body(response.body().unwrap(), 17).await;

View File

@ -30,7 +30,7 @@ mod limits_tests {
#[rocket::async_test] #[rocket::async_test]
async 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)).await.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)
@ -41,7 +41,7 @@ mod limits_tests {
#[rocket::async_test] #[rocket::async_test]
async 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)).await.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)
@ -52,7 +52,7 @@ mod limits_tests {
#[rocket::async_test] #[rocket::async_test]
async 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)).await.unwrap();
let response = client.post("/") let response = client.post("/")
.body("value=Hello+world") .body("value=Hello+world")
.header(ContentType::Form) .header(ContentType::Form)
@ -63,7 +63,7 @@ mod limits_tests {
#[rocket::async_test] #[rocket::async_test]
async fn contracted() { async fn contracted() {
let client = Client::new(rocket_with_forms_limit(10)).unwrap(); let client = Client::new(rocket_with_forms_limit(10)).await.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)

View File

@ -63,7 +63,7 @@ mod local_request_content_type_tests {
#[rocket::async_test] #[rocket::async_test]
async fn has_no_ct() { async fn has_no_ct() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut req = client.post("/"); let mut req = client.post("/");
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Absent".to_string())); // assert_eq!(req.clone().dispatch().await.body_string().await, Some("Absent".to_string()));
@ -78,7 +78,7 @@ mod local_request_content_type_tests {
#[rocket::async_test] #[rocket::async_test]
async fn has_ct() { async fn has_ct() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut req = client.post("/").header(ContentType::JSON); let mut req = client.post("/").header(ContentType::JSON);
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Present".to_string())); // assert_eq!(req.clone().dispatch().await.body_string().await, Some("Present".to_string()));

View File

@ -26,7 +26,7 @@ mod private_cookie_test {
async 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).await.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().await; let mut response = req.dispatch().await;
@ -38,7 +38,7 @@ mod private_cookie_test {
async 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).await.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().await; let response = req.dispatch().await;

View File

@ -24,7 +24,7 @@ fn index(counter: State<'_, Counter>) -> String {
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![index]) .mount("/", routes![index])
.attach(AdHoc::on_attach("Outer", |rocket| { .attach(AdHoc::on_attach("Outer", |rocket| async {
let counter = Counter::default(); let counter = Counter::default();
counter.attach.fetch_add(1, Ordering::Relaxed); counter.attach.fetch_add(1, Ordering::Relaxed);
let rocket = rocket.manage(counter) let rocket = rocket.manage(counter)
@ -48,7 +48,7 @@ mod nested_fairing_attaches_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_counts() { async fn test_counts() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("1, 1".into())); assert_eq!(response.body_string().await, Some("1, 1".into()));

View File

@ -37,7 +37,7 @@ mod tests {
macro_rules! check_dispatch { macro_rules! check_dispatch {
($mount:expr, $ct:expr, $body:expr) => ( ($mount:expr, $ct:expr, $body:expr) => (
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut req = client.post($mount); let mut req = client.post($mount);
let ct: Option<ContentType> = $ct; let ct: Option<ContentType> = $ct;
if let Some(ct) = ct { if let Some(ct) = ct {

View File

@ -16,7 +16,7 @@ mod tests {
#[rocket::async_test] #[rocket::async_test]
async 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])).await.unwrap();
let response = client.get("/unknown").dispatch().await; let response = client.get("/unknown").dispatch().await;
println!("Response:\n{:?}", response); println!("Response:\n{:?}", response);

View File

@ -26,7 +26,7 @@ mod route_guard_tests {
.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).await.unwrap();
assert_path(&client, "/first/some/path").await; assert_path(&client, "/first/some/path").await;
assert_path(&client, "/second/some/path").await; assert_path(&client, "/second/some/path").await;
assert_path(&client, "/first/second/b/c").await; assert_path(&client, "/first/second/b/c").await;

View File

@ -38,7 +38,7 @@ mod tests {
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]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
// We construct a path that matches each of the routes above. We ensure the // We construct a path that matches each of the routes above. We ensure the
// prefix is stripped, confirming that dynamic segments are working. // prefix is stripped, confirming that dynamic segments are working.

View File

@ -27,13 +27,13 @@ mod strict_and_lenient_forms_tests {
const FIELD_VALUE: &str = "just_some_value"; const FIELD_VALUE: &str = "just_some_value";
fn client() -> Client { async fn client() -> Client {
Client::new(rocket::ignite().mount("/", routes![strict, lenient])).unwrap() Client::new(rocket::ignite().mount("/", routes![strict, lenient])).await.unwrap()
} }
#[rocket::async_test] #[rocket::async_test]
async fn test_strict_form() { async fn test_strict_form() {
let client = client(); let client = client().await;
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))
@ -52,7 +52,7 @@ mod strict_and_lenient_forms_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_lenient_form() { async fn test_lenient_form() {
let client = client(); let client = client().await;
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))

View File

@ -35,7 +35,7 @@ mod tests {
#[rocket::async_test] #[rocket::async_test]
async 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()).await.unwrap();
let response = client.get("/raw").dispatch().await; let response = client.get("/raw").dispatch().await;
let location: Vec<_> = response.headers().get("location").collect(); let location: Vec<_> = response.headers().get("location").collect();
@ -50,7 +50,7 @@ mod tests {
#[rocket::async_test] #[rocket::async_test]
async fn uri_percent_encoding_get() { async fn uri_percent_encoding_get() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let name = Uri::percent_encode(NAME); let name = Uri::percent_encode(NAME);
let mut response = client.get(format!("/hello/{}", name)).dispatch().await; let mut response = client.get(format!("/hello/{}", name)).dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);

View File

@ -55,15 +55,15 @@ pub fn test_config(environment: Environment) {
std::env::set_var("ROCKET_ENV", environment.to_string()); std::env::set_var("ROCKET_ENV", environment.to_string());
let rocket = rocket::ignite() let rocket = rocket::ignite()
.attach(AdHoc::on_attach("Local Config", |mut rocket| { .attach(AdHoc::on_attach("Local Config", |mut rocket| async {
println!("Attaching local config."); println!("Attaching local config.");
let config = rocket.inspect().config().clone(); let config = rocket.inspect().await.config().clone();
Ok(rocket.manage(LocalConfig(config))) Ok(rocket.manage(LocalConfig(config)))
})) }))
.mount("/", routes![check_config]); .mount("/", routes![check_config]);
rocket::async_test(async move { rocket::async_test(async move {
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let response = client.get("/check_config").dispatch().await; let response = client.get("/check_config").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);
}) })

View File

@ -9,7 +9,7 @@ async fn test<H>(method: Method, uri: &str, header: H, status: Status, body: Str
.mount("/hello", routes![super::get_hello, super::post_hello]) .mount("/hello", routes![super::get_hello, super::post_hello])
.register(catchers![super::not_found]); .register(catchers![super::not_found]);
let client = Client::new(rocket).unwrap(); let client = Client::new(rocket).await.unwrap();
let mut response = client.req(method, uri).header(header).dispatch().await; 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().await, Some(body)); assert_eq!(response.body_string().await, Some(body));

View File

@ -7,7 +7,7 @@ use rocket_contrib::templates::Template;
#[rocket::async_test] #[rocket::async_test]
async fn test_submit() { async fn test_submit() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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!")
@ -23,7 +23,7 @@ async fn test_submit() {
async 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()).await.unwrap();
let mut response = match optional_cookie { let mut response = match optional_cookie {
Some(cookie) => client.get("/").cookie(cookie).dispatch().await, Some(cookie) => client.get("/").cookie(cookie).dispatch().await,
None => client.get("/").dispatch().await, None => client.get("/").dispatch().await,
@ -35,7 +35,7 @@ async fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: Stri
#[rocket::async_test] #[rocket::async_test]
async fn test_index() { async fn test_index() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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();

View File

@ -6,7 +6,7 @@ async fn test(uri: &str, status: Status, body: String) {
.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).await.unwrap();
let mut response = client.get(uri).dispatch().await; let mut response = client.get(uri).dispatch().await;
assert_eq!(response.status(), status); assert_eq!(response.status(), status);
assert_eq!(response.body_string().await, Some(body)); assert_eq!(response.body_string().await, Some(body));

View File

@ -67,9 +67,9 @@ fn rocket() -> rocket::Rocket {
rocket::ignite() rocket::ignite()
.mount("/", routes![hello, token]) .mount("/", routes![hello, token])
.attach(Counter::default()) .attach(Counter::default())
.attach(AdHoc::on_attach("Token State", |mut rocket| { .attach(AdHoc::on_attach("Token State", |mut rocket| async {
println!("Adding token managed state..."); println!("Adding token managed state...");
let token_val = rocket.inspect().config().get_int("token").unwrap_or(-1); let token_val = rocket.inspect().await.config().get_int("token").unwrap_or(-1);
Ok(rocket.manage(Token(token_val))) Ok(rocket.manage(Token(token_val)))
})) }))
.attach(AdHoc::on_launch("Launch Message", |_| { .attach(AdHoc::on_launch("Launch Message", |_| {

View File

@ -3,14 +3,14 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async fn rewrite_get_put() { async fn rewrite_get_put() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, fairings!".into())); assert_eq!(response.body_string().await, Some("Hello, fairings!".into()));
} }
#[rocket::async_test] #[rocket::async_test]
async fn counts() { async fn counts() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
// Issue 1 GET request. // Issue 1 GET request.
client.get("/").dispatch().await; client.get("/").dispatch().await;
@ -30,7 +30,7 @@ async fn counts() {
#[rocket::async_test] #[rocket::async_test]
async fn token() { async fn token() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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().await; let mut res = client.get("/token").dispatch().await;

View File

@ -14,31 +14,29 @@ impl fmt::Display for FormOption {
} }
} }
fn assert_form_eq(client: &Client, form_str: &str, expected: String) { async fn assert_form_eq(client: &Client, form_str: &str, expected: String) {
rocket::async_test(async move { let mut res = client.post("/")
let mut res = client.post("/") .header(ContentType::Form)
.header(ContentType::Form) .body(form_str)
.body(form_str) .dispatch().await;
.dispatch().await;
assert_eq!(res.body_string().await, Some(expected)); assert_eq!(res.body_string().await, Some(expected));
})
} }
fn assert_valid_form(client: &Client, input: &FormInput<'_>) { async fn assert_valid_form(client: &Client, input: &FormInput<'_>) {
let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}", let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
input.checkbox, input.number, input.radio, input.password, input.checkbox, input.number, input.radio, input.password,
input.text_area, input.select); input.text_area, input.select);
assert_form_eq(client, &f, format!("{:?}", input)); assert_form_eq(client, &f, format!("{:?}", input)).await;
} }
fn assert_valid_raw_form(client: &Client, form_str: &str, input: &FormInput<'_>) { async fn assert_valid_raw_form(client: &Client, form_str: &str, input: &FormInput<'_>) {
assert_form_eq(client, form_str, format!("{:?}", input)); assert_form_eq(client, form_str, format!("{:?}", input)).await;
} }
#[test] #[rocket::async_test]
fn test_good_forms() { async fn test_good_forms() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut input = FormInput { let mut input = FormInput {
checkbox: true, checkbox: true,
number: 310, number: 310,
@ -48,137 +46,137 @@ fn test_good_forms() {
select: FormOption::B select: FormOption::B
}; };
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.checkbox = false; input.checkbox = false;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.number = 0; input.number = 0;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.number = 120; input.number = 120;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.number = 133; input.number = 133;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.radio = FormOption::B; input.radio = FormOption::B;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.radio = FormOption::C; input.radio = FormOption::C;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.password = "".into(); input.password = "".into();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.password = "----90138490285u2o3hndslkv".into(); input.password = "----90138490285u2o3hndslkv".into();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.password = "hi".into(); input.password = "hi".into();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.text_area = "".to_string(); input.text_area = "".to_string();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.text_area = "----90138490285u2o3hndslkv".to_string(); input.text_area = "----90138490285u2o3hndslkv".to_string();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.text_area = "hey".to_string(); input.text_area = "hey".to_string();
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.select = FormOption::A; input.select = FormOption::A;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
input.select = FormOption::C; input.select = FormOption::C;
assert_valid_form(&client, &input); assert_valid_form(&client, &input).await;
// checkbox need not be present; defaults to false; accepts 'on' and 'off' // checkbox need not be present; defaults to false; accepts 'on' and 'off'
assert_valid_raw_form(&client, assert_valid_raw_form(&client,
"number=133&type=c&password=hi&textarea=hey&select=c", "number=133&type=c&password=hi&textarea=hey&select=c",
&input); &input).await;
assert_valid_raw_form(&client, assert_valid_raw_form(&client,
"checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c", "checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c",
&input); &input).await;
input.checkbox = true; input.checkbox = true;
assert_valid_raw_form(&client, assert_valid_raw_form(&client,
"checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c", "checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c",
&input); &input).await;
} }
fn assert_invalid_form(client: &Client, vals: &mut [&str; 6]) { async fn assert_invalid_form(client: &Client, vals: &mut [&str; 6]) {
let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}", let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]); vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
assert_form_eq(client, &s, format!("Invalid form input: {}", s)); assert_form_eq(client, &s, format!("Invalid form input: {}", s)).await;
*vals = ["true", "1", "a", "hi", "hey", "b"]; *vals = ["true", "1", "a", "hi", "hey", "b"];
} }
fn assert_invalid_raw_form(client: &Client, form_str: &str) { async fn assert_invalid_raw_form(client: &Client, form_str: &str) {
assert_form_eq(client, form_str, format!("Invalid form input: {}", form_str)); assert_form_eq(client, form_str, format!("Invalid form input: {}", form_str)).await;
} }
#[test] #[rocket::async_test]
fn check_semantically_invalid_forms() { async fn check_semantically_invalid_forms() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"]; let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
form_vals[0] = "not true"; form_vals[0] = "not true";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[0] = "bing"; form_vals[0] = "bing";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[0] = "true0"; form_vals[0] = "true0";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[0] = " false"; form_vals[0] = " false";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[1] = "-1"; form_vals[1] = "-1";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[1] = "1e10"; form_vals[1] = "1e10";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[1] = "-1-1"; form_vals[1] = "-1-1";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[1] = "NaN"; form_vals[1] = "NaN";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[2] = "A?"; form_vals[2] = "A?";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[2] = " B"; form_vals[2] = " B";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[2] = "d"; form_vals[2] = "d";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[2] = "100"; form_vals[2] = "100";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[2] = ""; form_vals[2] = "";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
// password and textarea are always valid, so we skip them // password and textarea are always valid, so we skip them
form_vals[5] = "A."; form_vals[5] = "A.";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[5] = "b "; form_vals[5] = "b ";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[5] = "d"; form_vals[5] = "d";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[5] = "-a"; form_vals[5] = "-a";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
form_vals[5] = ""; form_vals[5] = "";
assert_invalid_form(&client, &mut form_vals); assert_invalid_form(&client, &mut form_vals).await;
// now forms with missing fields // now forms with missing fields
assert_invalid_raw_form(&client, "number=10&type=a&password=hi&textarea=hey"); assert_invalid_raw_form(&client, "number=10&type=a&password=hi&textarea=hey").await;
assert_invalid_raw_form(&client, "number=10&radio=a&password=hi&textarea=hey&select=b"); assert_invalid_raw_form(&client, "number=10&radio=a&password=hi&textarea=hey&select=b").await;
assert_invalid_raw_form(&client, "number=10&password=hi&select=b"); assert_invalid_raw_form(&client, "number=10&password=hi&select=b").await;
assert_invalid_raw_form(&client, "number=10&select=b"); assert_invalid_raw_form(&client, "number=10&select=b").await;
assert_invalid_raw_form(&client, "password=hi&select=b"); assert_invalid_raw_form(&client, "password=hi&select=b").await;
assert_invalid_raw_form(&client, "password=hi"); assert_invalid_raw_form(&client, "password=hi").await;
assert_invalid_raw_form(&client, ""); assert_invalid_raw_form(&client, "").await;
} }
#[test] #[rocket::async_test]
fn check_structurally_invalid_forms() { async fn check_structurally_invalid_forms() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
assert_invalid_raw_form(&client, "==&&&&&&=="); assert_invalid_raw_form(&client, "==&&&&&&==").await;
assert_invalid_raw_form(&client, "a&=b"); assert_invalid_raw_form(&client, "a&=b").await;
assert_invalid_raw_form(&client, "="); assert_invalid_raw_form(&client, "=").await;
} }
#[test] #[rocket::async_test]
fn check_bad_utf8() { async fn check_bad_utf8() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
unsafe { unsafe {
let bad_str = std::str::from_utf8_unchecked(b"a=\xff"); let bad_str = std::str::from_utf8_unchecked(b"a=\xff");
assert_form_eq(&client, bad_str, "Form input was invalid UTF-8.".into()); assert_form_eq(&client, bad_str, "Form input was invalid UTF-8.".into()).await;
} }
} }

View File

@ -6,7 +6,7 @@ fn test_login<T>(user: &str, pass: &str, age: &str, status: Status, body: T)
where T: Into<Option<&'static str>> + Send where T: Into<Option<&'static str>> + Send
{ {
rocket::async_test(async move { rocket::async_test(async move {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let query = format!("username={}&password={}&age={}", user, pass, age); let query = format!("username={}&password={}&age={}", user, pass, age);
let mut response = client.post("/login") let mut response = client.post("/login")
.header(ContentType::Form) .header(ContentType::Form)
@ -47,7 +47,7 @@ fn test_invalid_age() {
fn check_bad_form(form_str: &str, status: Status) { fn check_bad_form(form_str: &str, status: Status) {
rocket::async_test(async { rocket::async_test(async {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let response = client.post("/login") let response = client.post("/login")
.header(ContentType::Form) .header(ContentType::Form)
.body(form_str) .body(form_str)

View File

@ -7,7 +7,7 @@ use rocket_contrib::templates::Template;
macro_rules! dispatch { macro_rules! dispatch {
($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({ ($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({
let $client = Client::new(rocket()).unwrap(); let $client = Client::new(rocket()).await.unwrap();
let mut $response = $client.req($method, $path).dispatch().await; let mut $response = $client.req($method, $path).dispatch().await;
$body $body
}) })

View File

@ -3,7 +3,7 @@ use rocket::{self, routes, local::Client};
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into())); assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into()));
} }
@ -36,14 +36,14 @@ mod scoped_uri_tests {
#[rocket::async_test] #[rocket::async_test]
async fn test_inner_hello() { async fn test_inner_hello() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello! Try /Rust%202018.".into())); assert_eq!(response.body_string().await, Some("Hello! Try /Rust%202018.".into()));
} }
#[rocket::async_test] #[rocket::async_test]
async fn test_hello_name() { async fn test_hello_name() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get("/Rust%202018").dispatch().await; let mut response = client.get("/Rust%202018").dispatch().await;
assert_eq!(response.body_string().await.unwrap(), "Hello, Rust 2018! This is /Rust%202018."); assert_eq!(response.body_string().await.unwrap(), "Hello, Rust 2018! This is /Rust%202018.");
} }

View File

@ -1,17 +1,17 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
fn client() -> Client { async fn client() -> Client {
Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).unwrap() Client::new(rocket::ignite().mount("/", routes![super::hello, super::hi])).await.unwrap()
} }
async fn test(uri: String, expected: String) { async fn test(uri: String, expected: String) {
let client = client(); let client = client().await;
assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected)); assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected));
} }
async fn test_404(uri: &'static str) { async fn test_404(uri: &'static str) {
let client = client(); let client = client().await;
assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound); assert_eq!(client.get(uri).dispatch().await.status(), Status::NotFound);
} }

View File

@ -3,7 +3,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into())); assert_eq!(response.body_string().await, Some("Hello, world!".into()));
} }

View File

@ -4,7 +4,7 @@ use rocket::http::{Status, ContentType};
#[rocket::async_test] #[rocket::async_test]
async fn bad_get_put() { async fn bad_get_put() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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().await; let mut res = client.get("/message/99").header(ContentType::JSON).dispatch().await;
@ -35,7 +35,7 @@ async fn bad_get_put() {
#[rocket::async_test] #[rocket::async_test]
async fn post_get_put_get() { async fn post_get_put_get() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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().await; let res = client.get("/message/1").header(ContentType::JSON).dispatch().await;

View File

@ -3,7 +3,7 @@ use rocket::http::Status;
#[rocket::async_test] #[rocket::async_test]
async fn test_push_pop() { async fn test_push_pop() {
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).await.unwrap();
let response = client.put("/push?event=test1").dispatch().await; let response = client.put("/push?event=test1").dispatch().await;
assert_eq!(response.status(), Status::Ok); assert_eq!(response.status(), Status::Ok);

View File

@ -4,7 +4,7 @@ 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) {
rocket::async_test(async move { rocket::async_test(async move {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get(uri).header(content_type).dispatch().await; let mut response = client.get(uri).header(content_type).dispatch().await;
assert_eq!(response.status(), status); assert_eq!(response.status(), status);
assert_eq!(response.body_string().await, Some(body)); assert_eq!(response.body_string().await, Some(body));
@ -32,7 +32,7 @@ fn test_echo() {
#[rocket::async_test] #[rocket::async_test]
async fn test_upload() { async fn test_upload() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let expected_body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \ let expected_body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, \
sed do eiusmod tempor incididunt ut labore et dolore \ sed do eiusmod tempor incididunt ut labore et dolore \
magna aliqua".to_string(); magna aliqua".to_string();

View File

@ -10,7 +10,7 @@ struct Message {
#[rocket::async_test] #[rocket::async_test]
async fn msgpack_get() { async fn msgpack_get() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch().await; 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));
@ -23,7 +23,7 @@ async fn msgpack_get() {
#[rocket::async_test] #[rocket::async_test]
async 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()).await.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])

View File

@ -1,22 +1,22 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
fn client() -> Client { async fn client() -> Client {
let rocket = rocket::ignite() let rocket = rocket::ignite()
.mount("/", routes![super::root, super::user, super::login]); .mount("/", routes![super::root, super::user, super::login]);
Client::new(rocket).unwrap() Client::new(rocket).await.unwrap()
} }
async fn test_200(uri: &str, expected_body: &str) { async fn test_200(uri: &str, expected_body: &str) {
let client = client(); let client = client().await;
let mut response = client.get(uri).dispatch().await; 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().await, Some(expected_body.to_string())); assert_eq!(response.body_string().await, Some(expected_body.to_string()));
} }
async fn test_303(uri: &str, expected_location: &str) { async fn test_303(uri: &str, expected_location: &str) {
let client = client(); let client = client().await;
let response = client.get(uri).dispatch().await; 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);

View File

@ -8,7 +8,7 @@ fn extract_id(from: &str) -> Option<String> {
#[rocket::async_test] #[rocket::async_test]
async fn check_index() { async fn check_index() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
// Ensure the index returns what we expect. // Ensure the index returns what we expect.
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
@ -32,7 +32,7 @@ async fn download_paste(client: &Client, id: &str) -> String {
#[rocket::async_test] #[rocket::async_test]
async fn pasting() { async fn pasting() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.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!";

View File

@ -4,7 +4,7 @@ use rocket::http::Status;
macro_rules! run_test { macro_rules! run_test {
($query:expr, |$response:ident| $body:expr) => ({ ($query:expr, |$response:ident| $body:expr) => ({
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
#[allow(unused_mut)] #[allow(unused_mut)]
let mut $response = client.get(format!("/hello{}", $query)).dispatch().await; let mut $response = client.get(format!("/hello{}", $query)).dispatch().await;
$body $body

View File

@ -2,7 +2,7 @@ use rocket::local::Client;
async fn test(uri: String, 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).await.unwrap();
let mut response = client.get(&uri).dispatch().await; let mut response = client.get(&uri).dispatch().await;
assert_eq!(response.body_string().await, Some(expected)); assert_eq!(response.body_string().await, Some(expected));
} }

View File

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

View File

@ -9,7 +9,7 @@ const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!";
#[rocket::async_test] #[rocket::async_test]
async fn test_index() { async fn test_index() {
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).await.unwrap();
let mut res = client.get("/").dispatch().await; let mut res = client.get("/").dispatch().await;
assert_eq!(res.body_string().await, Some(super::index().to_string())); assert_eq!(res.body_string().await, Some(super::index().to_string()));
} }
@ -21,7 +21,7 @@ async fn test_raw_upload() {
let _ = fs::remove_file(&upload_file); let _ = fs::remove_file(&upload_file);
// Do the upload. Make sure we get the expected results. // Do the upload. Make sure we get the expected results.
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).await.unwrap();
let mut res = client.post("/upload") let mut res = client.post("/upload")
.header(ContentType::Plain) .header(ContentType::Plain)
.body(UPLOAD_CONTENTS) .body(UPLOAD_CONTENTS)

View File

@ -1,14 +1,14 @@
use rocket::local::Client; use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
fn client() -> Client { async fn client() -> Client {
let rocket = rocket::ignite().mount("/", routes![super::root, super::login]); let rocket = rocket::ignite().mount("/", routes![super::root, super::login]);
Client::new(rocket).unwrap() Client::new(rocket).await.unwrap()
} }
#[rocket::async_test] #[rocket::async_test]
async fn test_root() { async fn test_root() {
let client = client(); let client = client().await;
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert!(response.body().is_none()); assert!(response.body().is_none());
@ -24,7 +24,7 @@ async fn test_root() {
#[rocket::async_test] #[rocket::async_test]
async fn test_login() { async fn test_login() {
let client = client(); let client = client().await;
let mut r = client.get("/login").dispatch().await; let mut r = client.get("/login").dispatch().await;
assert_eq!(r.body_string().await, Some("Hi! Please log in before continuing.".into())); assert_eq!(r.body_string().await, Some("Hi! Please log in before continuing.".into()));
} }

View File

@ -36,7 +36,7 @@ mod test {
use rocket::http::Header; use rocket::http::Header;
async 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()).await.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);

View File

@ -5,7 +5,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async fn test() { async fn test() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
client.get("/sync").dispatch().await; client.get("/sync").dispatch().await;
let atomics = client.manifest().state::<Atomics>().unwrap(); let atomics = client.manifest().state::<Atomics>().unwrap();

View File

@ -24,7 +24,7 @@ async fn login(client: &Client, user: &str, pass: &str) -> Option<Cookie<'static
#[rocket::async_test] #[rocket::async_test]
async fn redirect_on_index() { async fn redirect_on_index() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let response = client.get("/").dispatch().await; 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"));
@ -32,7 +32,7 @@ async fn redirect_on_index() {
#[rocket::async_test] #[rocket::async_test]
async fn can_login() { async fn can_login() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut response = client.get("/login").dispatch().await; let mut response = client.get("/login").dispatch().await;
let body = response.body_string().await.unwrap(); let body = response.body_string().await.unwrap();
@ -42,14 +42,14 @@ async fn can_login() {
#[rocket::async_test] #[rocket::async_test]
async fn login_fails() { async fn login_fails() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
assert!(login(&client, "Seergio", "password").await.is_none()); assert!(login(&client, "Seergio", "password").await.is_none());
assert!(login(&client, "Sergio", "idontknow").await.is_none()); assert!(login(&client, "Sergio", "idontknow").await.is_none());
} }
#[rocket::async_test] #[rocket::async_test]
async fn login_logout_succeeds() { async fn login_logout_succeeds() {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let login_cookie = login(&client, "Sergio", "password").await.expect("logged in"); let login_cookie = login(&client, "Sergio", "password").await.expect("logged in");
// Ensure we're logged in. // Ensure we're logged in.

View File

@ -13,7 +13,7 @@ async fn get_count(client: &Client) -> usize {
#[rocket::async_test] #[rocket::async_test]
async fn test_count() { async fn test_count() {
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).await.unwrap();
// Count should start at 0. // Count should start at 0.
assert_eq!(get_count(&client).await, 0); assert_eq!(get_count(&client).await, 0);
@ -25,13 +25,13 @@ async fn test_count() {
assert_eq!(get_count(&client).await, 100); assert_eq!(get_count(&client).await, 100);
} }
#[test] #[rocket::async_test]
fn test_raw_state_count() { async fn test_raw_state_count() {
use rocket::State; use rocket::State;
use super::{count, index}; use super::{count, index};
let mut rocket = super::rocket(); let mut rocket = super::rocket();
let manifest = rocket.inspect(); let manifest = rocket.inspect().await;
assert_eq!(count(State::from(manifest).unwrap()), "0"); assert_eq!(count(State::from(manifest).unwrap()), "0");
assert!(index(State::from(manifest).unwrap()).0.contains("Visits: 1")); assert!(index(State::from(manifest).unwrap()).0.contains("Visits: 1"));

View File

@ -9,7 +9,7 @@ use super::rocket;
async fn test_query_file<T> (path: &str, file: T, status: Status) 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()).await.unwrap();
let mut response = client.get(path).dispatch().await; let mut response = client.get(path).dispatch().await;
assert_eq!(response.status(), status); assert_eq!(response.status(), status);

View File

@ -5,7 +5,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async fn test_root() { async fn test_root() {
let client = Client::new(super::rocket()).unwrap(); let client = Client::new(super::rocket()).await.unwrap();
let mut res = client.get("/").dispatch().await; let mut res = client.get("/").dispatch().await;
// Check that we have exactly 25,000 'a'. // Check that we have exactly 25,000 'a'.
@ -24,7 +24,7 @@ async fn test_file() {
file.write_all(CONTENTS.as_bytes()).expect("write to big_file"); file.write_all(CONTENTS.as_bytes()).expect("write to big_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()).await.unwrap();
let mut res = client.get("/big_file").dispatch().await; let mut res = client.get("/big_file").dispatch().await;
assert_eq!(res.body_string().await, Some(CONTENTS.into())); assert_eq!(res.body_string().await, Some(CONTENTS.into()));

View File

@ -6,7 +6,7 @@ use rocket_contrib::templates::Template;
macro_rules! dispatch { macro_rules! dispatch {
($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({ ($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({
let $client = Client::new(rocket()).unwrap(); let $client = Client::new(rocket()).await.unwrap();
let mut $response = $client.req($method, $path).dispatch().await; let mut $response = $client.req($method, $path).dispatch().await;
$body $body
}) })

View File

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

View File

@ -3,7 +3,7 @@ use rocket::local::Client;
#[rocket::async_test] #[rocket::async_test]
async 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).await.unwrap();
let mut response = client.get("/").dispatch().await; let mut response = client.get("/").dispatch().await;
assert_eq!(response.body_string().await, Some("Hello, world!".into())); assert_eq!(response.body_string().await, Some("Hello, world!".into()));
} }

View File

@ -93,8 +93,8 @@ fn index(msg: Option<FlashMessage<'_, '_>>, conn: DbConn) -> Template {
}) })
} }
fn run_db_migrations(mut rocket: Rocket) -> Result<Rocket, Rocket> { async fn run_db_migrations(mut rocket: Rocket) -> Result<Rocket, Rocket> {
let conn = DbConn::get_one(rocket.inspect()).expect("database connection"); let conn = DbConn::get_one(rocket.inspect().await).expect("database connection");
match embedded_migrations::run(&*conn) { match embedded_migrations::run(&*conn) {
Ok(()) => Ok(rocket), Ok(()) => Ok(rocket),
Err(e) => { Err(e) => {

View File

@ -17,8 +17,8 @@ macro_rules! run_test {
rocket::async_test(async move { rocket::async_test(async move {
let mut rocket = super::rocket(); let mut rocket = super::rocket();
let db = super::DbConn::get_one(rocket.inspect()); let db = super::DbConn::get_one(rocket.inspect().await);
let $client = Client::new(rocket).expect("Rocket client"); let $client = Client::new(rocket).await.expect("Rocket client");
let $conn = db.expect("failed to get database connection for testing"); let $conn = db.expect("failed to get database connection for testing");
Task::delete_all(&$conn).expect("failed to delete all tasks for testing"); Task::delete_all(&$conn).expect("failed to delete all tasks for testing");

View File

@ -3,13 +3,13 @@ use rocket::local::Client;
use rocket::http::Status; use rocket::http::Status;
async fn test(uri: &str, expected: &str) { async fn test(uri: &str, expected: &str) {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let mut res = client.get(uri).dispatch().await; let mut res = client.get(uri).dispatch().await;
assert_eq!(res.body_string().await, Some(expected.into())); assert_eq!(res.body_string().await, Some(expected.into()));
} }
async fn test_404(uri: &str) { async fn test_404(uri: &str) {
let client = Client::new(rocket()).unwrap(); let client = Client::new(rocket()).await.unwrap();
let res = client.get(uri).dispatch().await; let res = client.get(uri).dispatch().await;
assert_eq!(res.status(), Status::NotFound); assert_eq!(res.status(), Status::NotFound);
} }

View File

@ -210,7 +210,7 @@ fn main() {
rocket::ignite() rocket::ignite()
.mount("/", routes![assets]) .mount("/", routes![assets])
.attach(AdHoc::on_attach("Assets Config", |mut rocket| { .attach(AdHoc::on_attach("Assets Config", |mut rocket| {
let assets_dir = rocket.inspect().config() let assets_dir = rocket.inspect().await.config()
.get_str("assets_dir") .get_str("assets_dir")
.unwrap_or("assets/") .unwrap_or("assets/")
.to_string(); .to_string();