mirror of https://github.com/rwf2/Rocket.git
Add blocking variant of 'local'.
This commit adds the 'local::blocking' module and moves the existing asynchronous testing to 'local::asynchronous'. It also includes several changes to improve the local API, bringing it to parity (and beyond) with master. These changes are: * 'LocalRequest' implements 'Clone'. * 'LocalResponse' doesn't implement 'DerefMut<Target=Response>'. Instead, direct methods on the type, such as 'into_string()', can be used to read the 'Response'. * 'Response::body()' returns an '&ResponseBody' as opposed to '&mut ResponseBody', which is returned by a new 'Response::body_mut()'. * '&ResponseBody' implements 'known_size()` to retrieve a body's size, if it is known. Co-authored-by: Jeb Rosen <jeb@jebrosen.com>
This commit is contained in:
parent
824de061c3
commit
03127f4dae
|
@ -328,7 +328,7 @@ impl Template {
|
|||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// use rocket_contrib::templates::Template;
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::local::asynchronous::Client;
|
||||
///
|
||||
/// fn main() {
|
||||
/// # rocket::async_test(async {
|
||||
|
|
|
@ -9,7 +9,7 @@ mod compress_responder_tests {
|
|||
use rocket::http::hyper::header::{ContentEncoding, Encoding};
|
||||
use rocket::http::Status;
|
||||
use rocket::http::{ContentType, Header};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::response::{Content, Response};
|
||||
use rocket_contrib::compression::Compress;
|
||||
|
||||
|
@ -80,7 +80,7 @@ mod compress_responder_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
@ -104,7 +104,7 @@ mod compress_responder_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
@ -131,7 +131,7 @@ mod compress_responder_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x == "gzip"));
|
||||
let mut s = String::new();
|
||||
GzDecoder::new(&response.body_bytes().unwrap()[..])
|
||||
GzDecoder::new(&response.into_bytes().unwrap()[..])
|
||||
.read_to_string(&mut s)
|
||||
.expect("decompress response");
|
||||
assert_eq!(s, String::from(HELLO));
|
||||
|
@ -154,7 +154,7 @@ mod compress_responder_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x == "gzip"));
|
||||
let mut s = String::new();
|
||||
GzDecoder::new(&response.body_bytes().unwrap()[..])
|
||||
GzDecoder::new(&response.into_bytes().unwrap()[..])
|
||||
.read_to_string(&mut s)
|
||||
.expect("decompress response");
|
||||
assert_eq!(s, String::from(HELLO));
|
||||
|
@ -173,7 +173,7 @@ mod compress_responder_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ mod compress_responder_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
@ -215,7 +215,7 @@ mod compress_responder_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ mod compress_responder_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ mod compression_fairing_tests {
|
|||
use rocket::http::hyper::header::{ContentEncoding, Encoding};
|
||||
use rocket::http::Status;
|
||||
use rocket::http::{ContentType, Header};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::response::{Content, Response};
|
||||
use rocket_contrib::compression::Compression;
|
||||
|
||||
|
@ -99,7 +99,7 @@ mod compression_fairing_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
@ -123,7 +123,7 @@ mod compression_fairing_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
@ -150,7 +150,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x == "gzip"));
|
||||
let mut s = String::new();
|
||||
GzDecoder::new(&response.body_bytes().unwrap()[..])
|
||||
GzDecoder::new(&response.into_bytes().unwrap()[..])
|
||||
.read_to_string(&mut s)
|
||||
.expect("decompress response");
|
||||
assert_eq!(s, String::from(HELLO));
|
||||
|
@ -173,7 +173,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x == "gzip"));
|
||||
let mut s = String::new();
|
||||
GzDecoder::new(&response.body_bytes().unwrap()[..])
|
||||
GzDecoder::new(&response.into_bytes().unwrap()[..])
|
||||
.read_to_string(&mut s)
|
||||
.expect("decompress response");
|
||||
assert_eq!(s, String::from(HELLO));
|
||||
|
@ -192,7 +192,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ mod compression_fairing_tests {
|
|||
.get("Content-Encoding")
|
||||
.any(|x| x != "identity"));
|
||||
assert_eq!(
|
||||
String::from_utf8(response.body_bytes().unwrap()).unwrap(),
|
||||
String::from_utf8(response.into_bytes().unwrap()).unwrap(),
|
||||
String::from(HELLO)
|
||||
);
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ mod compression_fairing_tests {
|
|||
.any(|x| x == "br"));
|
||||
let mut body_plain = Cursor::new(Vec::<u8>::new());
|
||||
brotli::BrotliDecompress(
|
||||
&mut Cursor::new(response.body_bytes().unwrap()),
|
||||
&mut Cursor::new(response.into_bytes().unwrap()),
|
||||
&mut body_plain,
|
||||
)
|
||||
.expect("decompress response");
|
||||
|
|
|
@ -7,7 +7,7 @@ extern crate rocket;
|
|||
#[cfg(feature = "helmet")]
|
||||
mod helmet_tests {
|
||||
use rocket::http::{Status, uri::Uri};
|
||||
use rocket::local::{Client, LocalResponse};
|
||||
use rocket::local::asynchronous::{Client, LocalResponse};
|
||||
|
||||
use rocket_contrib::helmet::*;
|
||||
use time::Duration;
|
||||
|
|
|
@ -8,7 +8,7 @@ mod static_tests {
|
|||
use rocket::{self, Rocket, Route};
|
||||
use rocket_contrib::serve::{StaticFiles, Options};
|
||||
use rocket::http::Status;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
fn static_root() -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
|
@ -47,7 +47,7 @@ mod static_tests {
|
|||
|
||||
async fn assert_file(client: &Client, prefix: &str, path: &str, exists: bool) {
|
||||
let full_path = format!("/{}/{}", prefix, path);
|
||||
let mut response = client.get(full_path).dispatch().await;
|
||||
let response = client.get(full_path).dispatch().await;
|
||||
if exists {
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
|
@ -59,7 +59,7 @@ mod static_tests {
|
|||
let mut file = File::open(path).expect("open file");
|
||||
let mut expected_contents = String::new();
|
||||
file.read_to_string(&mut expected_contents).expect("read file");
|
||||
assert_eq!(response.body_string().await, Some(expected_contents));
|
||||
assert_eq!(response.into_string().await, Some(expected_contents));
|
||||
} else {
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
}
|
||||
|
@ -135,13 +135,13 @@ mod static_tests {
|
|||
let rocket = rocket().mount("/default", routes![catch_one, catch_two]);
|
||||
let client = Client::new(rocket).await.expect("valid rocket");
|
||||
|
||||
let mut response = client.get("/default/ireallydontexist").dispatch().await;
|
||||
let response = client.get("/default/ireallydontexist").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await.unwrap(), "ireallydontexist");
|
||||
assert_eq!(response.into_string().await.unwrap(), "ireallydontexist");
|
||||
|
||||
let mut response = client.get("/default/idont/exist").dispatch().await;
|
||||
let response = client.get("/default/idont/exist").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await.unwrap(), "idont/exist");
|
||||
assert_eq!(response.into_string().await.unwrap(), "idont/exist");
|
||||
|
||||
assert_all(&client, "both", REGULAR_FILES, true).await;
|
||||
assert_all(&client, "both", HIDDEN_FILES, true).await;
|
||||
|
|
|
@ -42,7 +42,7 @@ mod templates_tests {
|
|||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use rocket::http::Status;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
const UNESCAPED_EXPECTED: &'static str
|
||||
= "\nh_start\ntitle: _test_\nh_end\n\n\n<script />\n\nfoot\n";
|
||||
|
@ -89,7 +89,7 @@ mod templates_tests {
|
|||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use rocket::http::Status;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
const EXPECTED: &'static str
|
||||
= "Hello _test_!\n\n<main> <script /> hi </main>\nDone.\n\n";
|
||||
|
@ -128,7 +128,7 @@ mod templates_tests {
|
|||
use std::io::Write;
|
||||
use std::time::Duration;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
const RELOAD_TEMPLATE: &str = "hbs/reload";
|
||||
const INITIAL_TEXT: &str = "initial";
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[get("/easy/<id>")]
|
||||
fn easy(id: i32) -> String {
|
||||
|
@ -38,14 +38,14 @@ async fn test_reexpansion() {
|
|||
let rocket = rocket::ignite().mount("/", routes![easy, hard, hi]);
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.get("/easy/327").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "easy id: 327");
|
||||
let response = client.get("/easy/327").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "easy id: 327");
|
||||
|
||||
let mut response = client.get("/hard/72").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "hard id: 72");
|
||||
let response = client.get("/hard/72").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "hard id: 72");
|
||||
|
||||
let mut response = client.get("/hello/fish").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "fish");
|
||||
let response = client.get("/hello/fish").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "fish");
|
||||
}
|
||||
|
||||
macro_rules! index {
|
||||
|
@ -64,6 +64,6 @@ async fn test_index() {
|
|||
let rocket = rocket::ignite().mount("/", routes![index]).manage(100i32);
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "Thing: 100");
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "Thing: 100");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::response::Responder;
|
||||
use rocket::http::{Status, ContentType, Cookie};
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::{Request, Data, Outcome::*};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::request::Form;
|
||||
use rocket::data::{self, FromDataSimple};
|
||||
use rocket::http::{RawStr, ContentType, Status};
|
||||
|
@ -46,16 +46,16 @@ async fn test_data() {
|
|||
let rocket = rocket::ignite().mount("/", routes![form, simple]);
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.post("/f")
|
||||
let response = client.post("/f")
|
||||
.header(ContentType::Form)
|
||||
.body("field=this%20is%20here")
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await.unwrap(), "this is here");
|
||||
assert_eq!(response.into_string().await.unwrap(), "this is here");
|
||||
|
||||
let mut response = client.post("/s").body("this is here").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "this is here");
|
||||
let response = client.post("/s").body("this is here").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "this is here");
|
||||
|
||||
let mut response = client.post("/s").body("this%20is%20here").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "this%20is%20here");
|
||||
let response = client.post("/s").body("this%20is%20here").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "this%20is%20here");
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{ContentType, MediaType, Accept, Status};
|
||||
|
||||
// Test that known formats work as expected, including not colliding.
|
||||
|
@ -41,26 +41,26 @@ async fn test_formats() {
|
|||
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.post("/").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "json");
|
||||
let response = client.post("/").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "json");
|
||||
|
||||
let mut response = client.post("/").header(ContentType::MsgPack).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "msgpack_long");
|
||||
let response = client.post("/").header(ContentType::MsgPack).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "msgpack_long");
|
||||
|
||||
let mut response = client.post("/").header(ContentType::XML).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "xml");
|
||||
let response = client.post("/").header(ContentType::XML).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "xml");
|
||||
|
||||
let mut response = client.get("/").header(Accept::Plain).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "plain");
|
||||
let response = client.get("/").header(Accept::Plain).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "plain");
|
||||
|
||||
let mut response = client.get("/").header(Accept::Binary).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "binary");
|
||||
let response = client.get("/").header(Accept::Binary).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "binary");
|
||||
|
||||
let mut response = client.get("/").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "plain");
|
||||
let response = client.get("/").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "plain");
|
||||
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "plain");
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "plain");
|
||||
|
||||
let response = client.put("/").header(ContentType::HTML).dispatch().await;
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
|
@ -92,20 +92,20 @@ async fn test_custom_formats() {
|
|||
let bar_baz_ct = ContentType::new("bar", "baz");
|
||||
let bar_baz_a = Accept::new(&[MediaType::new("bar", "baz").into()]);
|
||||
|
||||
let mut response = client.get("/").header(foo_a).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "get_foo");
|
||||
let response = client.get("/").header(foo_a).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "get_foo");
|
||||
|
||||
let mut response = client.post("/").header(foo_ct).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "post_foo");
|
||||
let response = client.post("/").header(foo_ct).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "post_foo");
|
||||
|
||||
let mut response = client.get("/").header(bar_baz_a).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "get_bar_baz");
|
||||
let response = client.get("/").header(bar_baz_a).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "get_bar_baz");
|
||||
|
||||
let mut response = client.put("/").header(bar_baz_ct).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "put_bar_baz");
|
||||
let response = client.put("/").header(bar_baz_ct).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "put_bar_baz");
|
||||
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "get_foo");
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "get_foo");
|
||||
|
||||
let response = client.put("/").header(ContentType::HTML).dispatch().await;
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#[macro_use] extern crate rocket;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
// Test that manual/auto ranking works as expected.
|
||||
|
||||
|
@ -23,17 +23,17 @@ async fn test_ranking() {
|
|||
let rocket = rocket::ignite().mount("/", routes![get0, get1, get2, get3]);
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.get("/0").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "0");
|
||||
let response = client.get("/0").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "0");
|
||||
|
||||
let mut response = client.get(format!("/{}", 1 << 8)).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "1");
|
||||
let response = client.get(format!("/{}", 1 << 8)).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "1");
|
||||
|
||||
let mut response = client.get(format!("/{}", 1 << 16)).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "2");
|
||||
let response = client.get(format!("/{}", 1 << 16)).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "2");
|
||||
|
||||
let mut response = client.get(format!("/{}", 1u64 << 32)).dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "3");
|
||||
let response = client.get(format!("/{}", 1u64 << 32)).dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "3");
|
||||
}
|
||||
|
||||
// Test a collision due to same auto rank.
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::path::PathBuf;
|
|||
|
||||
use rocket::{Request, Outcome::*};
|
||||
use rocket::http::ext::Normalize;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::data::{self, Data, FromDataSimple};
|
||||
use rocket::request::Form;
|
||||
use rocket::http::{Status, RawStr, ContentType};
|
||||
|
@ -105,24 +105,24 @@ async fn test_full_route() {
|
|||
let response = client.post(format!("/1{}", uri)).body(simple).dispatch().await;
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
|
||||
let mut response = client
|
||||
let response = client
|
||||
.post(format!("/1{}", uri))
|
||||
.header(ContentType::JSON)
|
||||
.body(simple)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
|
||||
assert_eq!(response.into_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
|
||||
sky, name, "A A", "inside", path, simple, expected_uri));
|
||||
|
||||
let response = client.post(format!("/2{}", uri)).body(simple).dispatch().await;
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
|
||||
let mut response = client
|
||||
let response = client
|
||||
.post(format!("/2{}", uri))
|
||||
.header(ContentType::JSON)
|
||||
.body(simple)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
|
||||
assert_eq!(response.into_string().await.unwrap(), format!("({}, {}, {}, {}, {}, {}) ({})",
|
||||
sky, name, "A A", "inside", path, simple, expected_uri));
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ pear = "0.1"
|
|||
atty = "0.2"
|
||||
async-trait = "0.1"
|
||||
ref-cast = "1.0"
|
||||
atomic = "0.4"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "0.2.9"
|
||||
|
|
|
@ -22,7 +22,7 @@ mod benches {
|
|||
|
||||
use super::rocket;
|
||||
use self::test::Bencher;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::{Accept, ContentType};
|
||||
|
||||
fn client(_rocket: rocket::Rocket) -> Option<Client> {
|
||||
|
@ -32,28 +32,28 @@ mod benches {
|
|||
#[bench]
|
||||
fn accept_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut request = client.get("/").header(Accept::JSON);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
let request = client.get("/").header(Accept::JSON);
|
||||
b.iter(|| { request.clone().dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn wrong_accept_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut request = client.get("/").header(Accept::HTML);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
let request = client.get("/").header(Accept::HTML);
|
||||
b.iter(|| { request.clone().dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn content_type_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut request = client.post("/").header(ContentType::JSON);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
let request = client.post("/").header(ContentType::JSON);
|
||||
b.iter(|| { request.clone().dispatch(); });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn wrong_content_type_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut request = client.post("/").header(ContentType::Plain);
|
||||
b.iter(|| { request.mut_dispatch(); });
|
||||
let request = client.post("/").header(ContentType::Plain);
|
||||
b.iter(|| { request.clone().dispatch(); });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ mod benches {
|
|||
|
||||
use super::rocket;
|
||||
use self::test::Bencher;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::{Accept, ContentType};
|
||||
|
||||
fn client(_rocket: rocket::Rocket) -> Option<Client> {
|
||||
|
@ -46,14 +46,15 @@ mod benches {
|
|||
#[bench]
|
||||
fn accept_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut requests = vec![];
|
||||
requests.push(client.get("/").header(Accept::JSON));
|
||||
requests.push(client.get("/").header(Accept::HTML));
|
||||
requests.push(client.get("/").header(Accept::Plain));
|
||||
let requests = vec![
|
||||
client.get("/").header(Accept::JSON),
|
||||
client.get("/").header(Accept::HTML),
|
||||
client.get("/").header(Accept::Plain),
|
||||
];
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.mut_dispatch();
|
||||
for request in &requests {
|
||||
request.clone().dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -61,14 +62,15 @@ mod benches {
|
|||
#[bench]
|
||||
fn content_type_format(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut requests = vec![];
|
||||
requests.push(client.post("/").header(ContentType::JSON));
|
||||
requests.push(client.post("/").header(ContentType::HTML));
|
||||
requests.push(client.post("/").header(ContentType::Plain));
|
||||
let requests = vec![
|
||||
client.post("/").header(ContentType::JSON),
|
||||
client.post("/").header(ContentType::HTML),
|
||||
client.post("/").header(ContentType::Plain),
|
||||
];
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.mut_dispatch();
|
||||
for request in &requests {
|
||||
request.clone().dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ mod benches {
|
|||
|
||||
use super::{hello_world_rocket, rocket};
|
||||
use self::test::Bencher;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::blocking::Client;
|
||||
|
||||
fn client(_rocket: rocket::Rocket) -> Option<Client> {
|
||||
unimplemented!("waiting for sync-client");
|
||||
|
@ -57,20 +57,18 @@ mod benches {
|
|||
#[bench]
|
||||
fn bench_hello_world(b: &mut Bencher) {
|
||||
let client = client(hello_world_rocket()).unwrap();
|
||||
let mut request = client.get("/");
|
||||
|
||||
b.iter(|| {
|
||||
request.mut_dispatch();
|
||||
client.get("/").dispatch();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_single_get_index(b: &mut Bencher) {
|
||||
let client = client(rocket()).unwrap();
|
||||
let mut request = client.get("/");
|
||||
|
||||
b.iter(|| {
|
||||
request.mut_dispatch();
|
||||
client.get("/").dispatch();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -85,8 +83,8 @@ mod benches {
|
|||
requests.push(client.post("/"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.mut_dispatch();
|
||||
for request in &requests {
|
||||
request.clone().dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -102,8 +100,8 @@ mod benches {
|
|||
requests.push(client.get("/123"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.mut_dispatch();
|
||||
for request in &requests {
|
||||
request.clone().dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -125,8 +123,8 @@ mod benches {
|
|||
requests.push(client.get("/123"));
|
||||
|
||||
b.iter(|| {
|
||||
for request in requests.iter_mut() {
|
||||
request.mut_dispatch();
|
||||
for request in &requests {
|
||||
request.clone().dispatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
use std::sync::RwLock;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::local::asynchronous::LocalRequest;
|
||||
use crate::rocket::{Rocket, Cargo};
|
||||
use crate::http::{Method, private::CookieJar};
|
||||
use crate::error::LaunchError;
|
||||
|
||||
pub struct Client {
|
||||
cargo: Cargo,
|
||||
pub(crate) cookies: Option<RwLock<CookieJar>>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub(crate) async fn _new(
|
||||
mut rocket: Rocket,
|
||||
tracked: bool
|
||||
) -> Result<Client, LaunchError> {
|
||||
rocket.prelaunch_check().await?;
|
||||
|
||||
let cookies = match tracked {
|
||||
true => Some(RwLock::new(CookieJar::new())),
|
||||
false => None
|
||||
};
|
||||
|
||||
Ok(Client { cargo: rocket.into_cargo().await, cookies })
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// WARNING: This is unstable! Do not use this method outside of Rocket!
|
||||
pub fn _test<T, F: FnOnce(Self) -> T + Send>(f: F) -> T {
|
||||
crate::async_test(async {
|
||||
let rocket = crate::ignite();
|
||||
let client = Client::new(rocket).await.expect("valid rocket");
|
||||
f(client)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn _cargo(&self) -> &Cargo {
|
||||
&self.cargo
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn _req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
LocalRequest::new(self, method, uri.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl_client!("use rocket::local::asynchronous::Client;" @async await Client);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Client;
|
||||
|
||||
fn assert_sync_send<T: Sync + Send>() {}
|
||||
|
||||
#[test]
|
||||
fn test_local_client_impl_send_sync() {
|
||||
assert_sync_send::<Client>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
mod client;
|
||||
mod request;
|
||||
mod response;
|
||||
|
||||
pub use client::*;
|
||||
pub use request::*;
|
||||
pub use response::*;
|
|
@ -0,0 +1,107 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::{Request, Data};
|
||||
use crate::http::{Status, Method, uri::Origin, ext::IntoOwned};
|
||||
|
||||
use super::{Client, LocalResponse};
|
||||
|
||||
pub struct LocalRequest<'c> {
|
||||
client: &'c Client,
|
||||
request: Request<'c>,
|
||||
data: Vec<u8>,
|
||||
uri: Cow<'c, str>,
|
||||
}
|
||||
|
||||
impl<'c> LocalRequest<'c> {
|
||||
pub(crate) fn new(
|
||||
client: &'c Client,
|
||||
method: Method,
|
||||
uri: Cow<'c, str>
|
||||
) -> LocalRequest<'c> {
|
||||
// We set a dummy string for now and check the user's URI on dispatch.
|
||||
let request = Request::new(client.rocket(), method, Origin::dummy());
|
||||
|
||||
// Set up any cookies we know about.
|
||||
if let Some(ref jar) = client.cookies {
|
||||
let cookies = jar.read().expect("LocalRequest::new() read lock");
|
||||
for cookie in cookies.iter() {
|
||||
request.cookies().add_original(cookie.clone().into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
LocalRequest { client, request, uri, data: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn _request(&self) -> &Request<'c> {
|
||||
&self.request
|
||||
}
|
||||
|
||||
pub(crate) fn _request_mut(&mut self) -> &mut Request<'c> {
|
||||
&mut self.request
|
||||
}
|
||||
|
||||
pub(crate) fn _body_mut(&mut self) -> &mut Vec<u8> {
|
||||
&mut self.data
|
||||
}
|
||||
|
||||
// This method should _never_ be publicly exposed!
|
||||
#[inline(always)]
|
||||
fn long_lived_request<'a>(&mut self) -> &'a mut Request<'c> {
|
||||
// FIXME: Whatever. I'll kill this.
|
||||
unsafe { &mut *(&mut self.request as *mut _) }
|
||||
}
|
||||
|
||||
// Performs the actual dispatch.
|
||||
// TODO.async: @jebrosen suspects there might be actual UB in here after all,
|
||||
// and now we just went and mixed threads into it
|
||||
async fn _dispatch(mut self) -> LocalResponse<'c> {
|
||||
// First, validate the URI, returning an error response (generated from
|
||||
// an error catcher) immediately if it's invalid.
|
||||
if let Ok(uri) = Origin::parse(&self.uri) {
|
||||
self.request.set_uri(uri.into_owned());
|
||||
} else {
|
||||
error!("Malformed request URI: {}", self.uri);
|
||||
let res = self.client.rocket()
|
||||
.handle_error(Status::BadRequest, self.long_lived_request());
|
||||
|
||||
return LocalResponse { _request: self.request, inner: res.await };
|
||||
}
|
||||
|
||||
// Actually dispatch the request.
|
||||
let response = self.client.rocket()
|
||||
.dispatch(self.long_lived_request(), Data::local(self.data))
|
||||
.await;
|
||||
|
||||
// If the client is tracking cookies, updates the internal cookie jar
|
||||
// with the changes reflected by `response`.
|
||||
if let Some(ref jar) = self.client.cookies {
|
||||
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
|
||||
let current_time = time::OffsetDateTime::now_utc();
|
||||
for cookie in response.cookies() {
|
||||
if let Some(expires) = cookie.expires() {
|
||||
if expires <= current_time {
|
||||
jar.force_remove(cookie);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
jar.add(cookie.into_owned());
|
||||
}
|
||||
}
|
||||
|
||||
LocalResponse { _request: self.request, inner: response }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> Clone for LocalRequest<'c> {
|
||||
fn clone(&self) -> Self {
|
||||
LocalRequest {
|
||||
client: self.client,
|
||||
request: self.request.clone(),
|
||||
data: self.data.clone(),
|
||||
uri: self.uri.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_request!("use rocket::local::asynchronous::Client;" @async await LocalRequest);
|
|
@ -0,0 +1,22 @@
|
|||
use crate::{Request, Response};
|
||||
|
||||
pub struct LocalResponse<'c> {
|
||||
pub(in super) _request: Request<'c>,
|
||||
pub(in super) inner: Response<'c>,
|
||||
}
|
||||
|
||||
impl<'c> LocalResponse<'c> {
|
||||
fn _response(&self) -> &Response<'c> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub(crate) async fn _into_string(mut self) -> Option<String> {
|
||||
self.inner.body_string().await
|
||||
}
|
||||
|
||||
pub(crate) async fn _into_bytes(mut self) -> Option<Vec<u8>> {
|
||||
self.inner.body_bytes().await
|
||||
}
|
||||
}
|
||||
|
||||
impl_response!("use rocket::local::asynchronous::Client;" @async await LocalResponse);
|
|
@ -0,0 +1,81 @@
|
|||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use crate::error::LaunchError;
|
||||
use crate::http::Method;
|
||||
use crate::local::{asynchronous, blocking::LocalRequest};
|
||||
use crate::rocket::{Rocket, Cargo};
|
||||
|
||||
pub struct Client {
|
||||
pub(crate) inner: asynchronous::Client,
|
||||
runtime: RefCell<tokio::runtime::Runtime>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
fn _new(rocket: Rocket, tracked: bool) -> Result<Client, LaunchError> {
|
||||
let mut runtime = tokio::runtime::Builder::new()
|
||||
.basic_scheduler()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("create tokio runtime");
|
||||
|
||||
// Initialize the Rocket instance
|
||||
let inner = runtime.block_on(asynchronous::Client::_new(rocket, tracked))?;
|
||||
Ok(Self { inner, runtime: RefCell::new(runtime) })
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
/// WARNING: This is unstable! Do not use this method outside of Rocket!
|
||||
pub fn _test<T, F: FnOnce(Self) -> T + Send>(f: F) -> T {
|
||||
let rocket = crate::ignite();
|
||||
let client = Client::new(rocket).expect("valid rocket");
|
||||
f(client)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn block_on<F, R>(&self, fut: F) -> R
|
||||
where F: std::future::Future<Output=R>,
|
||||
{
|
||||
self.runtime.borrow_mut().block_on(fut)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn _cargo(&self) -> &Cargo {
|
||||
self.inner._cargo()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn _req<'c, 'u: 'c, U>(
|
||||
&'c self,
|
||||
method: Method,
|
||||
uri: U
|
||||
) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
LocalRequest::new(self, method, uri.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl_client!("use rocket::local::blocking::Client;" Client);
|
||||
|
||||
#[cfg(doctest)]
|
||||
mod doctest {
|
||||
/// ```no_run
|
||||
/// // Just to ensure we get the path/form right in the following tests.
|
||||
/// use rocket::local::blocking::Client;
|
||||
///
|
||||
/// fn test<T>() {};
|
||||
/// test::<Client>();
|
||||
///
|
||||
/// fn is_send<T: Send>() {};
|
||||
/// is_send::<Client>();
|
||||
/// ```
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// use rocket::local::blocking::Client;
|
||||
///
|
||||
/// fn not_sync<T: Sync>() {};
|
||||
/// not_sync::<Client>();
|
||||
/// ```
|
||||
#[allow(dead_code)]
|
||||
fn test_not_sync_or_send() {}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// TODO: Explain difference from async Client
|
||||
//!
|
||||
//! Structures for local dispatching of requests, primarily for testing.
|
||||
//!
|
||||
//! This module allows for simple request dispatching against a local,
|
||||
//! non-networked instance of Rocket. The primary use of this module is to unit
|
||||
//! and integration test Rocket applications by crafting requests, dispatching
|
||||
//! them, and verifying the response.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! This module contains a [`Client`] structure that is used to create
|
||||
//! [`LocalRequest`] structures that can be dispatched against a given
|
||||
//! [`Rocket`](crate::Rocket) instance. Usage is straightforward:
|
||||
//!
|
||||
//! 1. Construct a `Rocket` instance that represents the application.
|
||||
//!
|
||||
//! ```rust
|
||||
//! let rocket = rocket::ignite();
|
||||
//! # let _ = rocket;
|
||||
//! ```
|
||||
//!
|
||||
//! 2. Construct a `Client` using the `Rocket` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::blocking::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! let client = Client::new(rocket).expect("valid rocket instance");
|
||||
//! # let _ = client;
|
||||
//! ```
|
||||
//!
|
||||
//! 3. Construct requests using the `Client` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::blocking::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # let client = Client::new(rocket).unwrap();
|
||||
//! let req = client.get("/");
|
||||
//! # let _ = req;
|
||||
//! ```
|
||||
//!
|
||||
//! 3. Dispatch the request to retrieve the response.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::blocking::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # let client = Client::new(rocket).unwrap();
|
||||
//! # let req = client.get("/");
|
||||
//! let response = req.dispatch();
|
||||
//! # let _ = response;
|
||||
//! ```
|
||||
//!
|
||||
//! All together and in idiomatic fashion, this might look like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::local::blocking::Client;
|
||||
//!
|
||||
//! let client = Client::new(rocket::ignite()).expect("valid rocket");
|
||||
//! let response = client.post("/")
|
||||
//! .body("Hello, world!")
|
||||
//! .dispatch();
|
||||
//! # let _ = response;
|
||||
//! ```
|
||||
//!
|
||||
//! # Unit/Integration Testing
|
||||
//!
|
||||
//! This module can be used to test a Rocket application by constructing
|
||||
//! requests via `Client` and validating the resulting response. As an example,
|
||||
//! consider the following complete "Hello, world!" application, with testing.
|
||||
//!
|
||||
//! ```rust
|
||||
//! #![feature(proc_macro_hygiene)]
|
||||
//!
|
||||
//! #[macro_use] extern crate rocket;
|
||||
//!
|
||||
//! #[get("/")]
|
||||
//! fn hello() -> &'static str {
|
||||
//! "Hello, world!"
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() { }
|
||||
//! #[cfg(test)]
|
||||
//! mod test {
|
||||
//! use super::{rocket, hello};
|
||||
//! use rocket::local::blocking::Client;
|
||||
//!
|
||||
//! fn test_hello_world() {
|
||||
//! // Construct a client to use for dispatching requests.
|
||||
//! let rocket = rocket::ignite().mount("/", routes![hello]);
|
||||
//! let client = Client::new(rocket).expect("valid rocket instance");
|
||||
//!
|
||||
//! // Dispatch a request to 'GET /' and validate the response.
|
||||
//! let mut response = client.get("/").dispatch();
|
||||
//! assert_eq!(response.into_string(), Some("Hello, world!".into()));
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Client`]: crate::local::blocking::Client
|
||||
//! [`LocalRequest`]: crate::local::blocking::LocalRequest
|
||||
|
||||
mod client;
|
||||
mod request;
|
||||
mod response;
|
||||
|
||||
pub use self::client::*;
|
||||
pub use self::request::*;
|
||||
pub use self::response::*;
|
|
@ -0,0 +1,43 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::{Request, http::Method, local::asynchronous};
|
||||
|
||||
use super::{Client, LocalResponse};
|
||||
#[derive(Clone)]
|
||||
pub struct LocalRequest<'c> {
|
||||
inner: asynchronous::LocalRequest<'c>,
|
||||
client: &'c Client,
|
||||
}
|
||||
|
||||
impl<'c> LocalRequest<'c> {
|
||||
#[inline]
|
||||
pub(crate) fn new(
|
||||
client: &'c Client,
|
||||
method: Method,
|
||||
uri: Cow<'c, str>
|
||||
) -> LocalRequest<'c> {
|
||||
let inner = asynchronous::LocalRequest::new(&client.inner, method, uri);
|
||||
Self { inner, client }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _request(&self) -> &Request<'c> {
|
||||
self.inner._request()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn _request_mut(&mut self) -> &mut Request<'c> {
|
||||
self.inner._request_mut()
|
||||
}
|
||||
|
||||
fn _body_mut(&mut self) -> &mut Vec<u8> {
|
||||
self.inner._body_mut()
|
||||
}
|
||||
|
||||
fn _dispatch(self) -> LocalResponse<'c> {
|
||||
let inner = self.client.block_on(self.inner.dispatch());
|
||||
LocalResponse { inner, client: self.client }
|
||||
}
|
||||
}
|
||||
|
||||
impl_request!("use rocket::local::blocking::Client;" LocalRequest);
|
|
@ -0,0 +1,24 @@
|
|||
use crate::{Response, local::asynchronous};
|
||||
|
||||
use super::Client;
|
||||
|
||||
pub struct LocalResponse<'c> {
|
||||
pub(in super) inner: asynchronous::LocalResponse<'c>,
|
||||
pub(in super) client: &'c Client,
|
||||
}
|
||||
|
||||
impl<'c> LocalResponse<'c> {
|
||||
fn _response(&self) -> &Response<'c> {
|
||||
&*self.inner
|
||||
}
|
||||
|
||||
fn _into_string(self) -> Option<String> {
|
||||
self.client.block_on(self.inner._into_string())
|
||||
}
|
||||
|
||||
fn _into_bytes(self) -> Option<Vec<u8>> {
|
||||
self.client.block_on(self.inner._into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl_response!("use rocket::local::blocking::Client;" LocalResponse);
|
|
@ -1,396 +1,238 @@
|
|||
use std::sync::RwLock;
|
||||
use std::borrow::Cow;
|
||||
//! A structure to construct requests for local dispatching.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! A `Client` is constructed via the [`new()`] or [`untracked()`] methods from
|
||||
//! an already constructed `Rocket` instance. Once a value of `Client` has been
|
||||
//! constructed, the [`LocalRequest`] constructor methods ([`get()`], [`put()`],
|
||||
//! [`post()`], and so on) can be used to create a `LocalRequest` for
|
||||
//! dispatching.
|
||||
//!
|
||||
//! See the [top-level documentation](crate::local) for more usage information.
|
||||
//!
|
||||
//! ## Cookie Tracking
|
||||
//!
|
||||
//! A `Client` constructed using [`new()`] propagates cookie changes made by
|
||||
//! responses to previously dispatched requests. In other words, if a previously
|
||||
//! dispatched request resulted in a response that adds a cookie, any future
|
||||
//! requests will contain that cookie. Similarly, cookies removed by a response
|
||||
//! won't be propagated further.
|
||||
//!
|
||||
//! This is typically the desired mode of operation for a `Client` as it removes
|
||||
//! the burden of manually tracking cookies. Under some circumstances, however,
|
||||
//! disabling this tracking may be desired. In these cases, use the
|
||||
//! [`untracked()`](Client::untracked()) constructor to create a `Client` that
|
||||
//! _will not_ track cookies.
|
||||
//!
|
||||
//! ### Synchronization
|
||||
//!
|
||||
//! While `Client` implements `Sync`, using it in a multithreaded environment
|
||||
//! while tracking cookies can result in surprising, non-deterministic behavior.
|
||||
//! This is because while cookie modifications are serialized, the exact
|
||||
//! ordering depends on when requests are dispatched. Specifically, when cookie
|
||||
//! tracking is enabled, all request dispatches are serialized, which in-turn
|
||||
//! serializes modifications to the internally tracked cookies.
|
||||
//!
|
||||
//! If possible, refrain from sharing a single instance of `Client` across
|
||||
//! multiple threads. Instead, prefer to create a unique instance of `Client`
|
||||
//! per thread. If it's not possible, ensure that either you are not depending
|
||||
//! on cookies, the ordering of their modifications, or both, or have arranged
|
||||
//! for dispatches to occur in a deterministic ordering.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! The following snippet creates a `Client` from a `Rocket` instance and
|
||||
//! dispatches a local request to `POST /` with a body of `Hello, world!`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::local::asynchronous::Client;
|
||||
//!
|
||||
//! # rocket::async_test(async {
|
||||
//! let rocket = rocket::ignite();
|
||||
//! let client = Client::new(rocket).await.expect("valid rocket");
|
||||
//! let response = client.post("/")
|
||||
//! .body("Hello, world!")
|
||||
//! .dispatch().await;
|
||||
//! # });
|
||||
//! ```
|
||||
//!
|
||||
//! [`new()`]: #method.new
|
||||
//! [`untracked()`]: #method.untracked
|
||||
//! [`get()`]: #method.get
|
||||
//! [`put()`]: #method.put
|
||||
//! [`post()`]: #method.post
|
||||
|
||||
use crate::rocket::{Rocket, Cargo};
|
||||
use crate::local::LocalRequest;
|
||||
use crate::http::{Method, private::CookieJar};
|
||||
use crate::error::LaunchError;
|
||||
macro_rules! req_method {
|
||||
($import:literal, $NAME:literal, $f:ident, $method:expr) => (
|
||||
req_method!(@
|
||||
$import,
|
||||
$NAME,
|
||||
concat!("let req = client.", stringify!($f), r#"("/hello");"#),
|
||||
$f,
|
||||
$method
|
||||
);
|
||||
);
|
||||
|
||||
/// A structure to construct requests for local dispatching.
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// A `Client` is constructed via the [`new()`] or [`untracked()`] methods from
|
||||
/// an already constructed `Rocket` instance. Once a value of `Client` has been
|
||||
/// constructed, the [`LocalRequest`] constructor methods ([`get()`], [`put()`],
|
||||
/// [`post()`], and so on) can be used to create a `LocalRequest` for
|
||||
/// dispatching.
|
||||
///
|
||||
/// See the [top-level documentation](crate::local) for more usage information.
|
||||
///
|
||||
/// ## Cookie Tracking
|
||||
///
|
||||
/// A `Client` constructed using [`new()`] propagates cookie changes made by
|
||||
/// responses to previously dispatched requests. In other words, if a previously
|
||||
/// dispatched request resulted in a response that adds a cookie, any future
|
||||
/// requests will contain that cookie. Similarly, cookies removed by a response
|
||||
/// won't be propagated further.
|
||||
///
|
||||
/// This is typically the desired mode of operation for a `Client` as it removes
|
||||
/// the burden of manually tracking cookies. Under some circumstances, however,
|
||||
/// disabling this tracking may be desired. In these cases, use the
|
||||
/// [`untracked()`](Client::untracked()) constructor to create a `Client` that
|
||||
/// _will not_ track cookies.
|
||||
///
|
||||
/// ### Synchronization
|
||||
///
|
||||
/// While `Client` implements `Sync`, using it in a multithreaded environment
|
||||
/// while tracking cookies can result in surprising, non-deterministic behavior.
|
||||
/// This is because while cookie modifications are serialized, the exact
|
||||
/// ordering depends on when requests are dispatched. Specifically, when cookie
|
||||
/// tracking is enabled, all request dispatches are serialized, which in-turn
|
||||
/// serializes modifications to the internally tracked cookies.
|
||||
///
|
||||
/// If possible, refrain from sharing a single instance of `Client` across
|
||||
/// multiple threads. Instead, prefer to create a unique instance of `Client`
|
||||
/// per thread. If it's not possible, ensure that either you are not depending
|
||||
/// on cookies, the ordering of their modifications, or both, or have arranged
|
||||
/// for dispatches to occur in a deterministic ordering.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// The following snippet creates a `Client` from a `Rocket` instance and
|
||||
/// dispatches a local request to `POST /` with a body of `Hello, world!`.
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let rocket = rocket::ignite();
|
||||
/// let client = Client::new(rocket).await.expect("valid rocket");
|
||||
/// let response = client.post("/")
|
||||
/// .body("Hello, world!")
|
||||
/// .dispatch().await;
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// [`new()`]: #method.new
|
||||
/// [`untracked()`]: #method.untracked
|
||||
/// [`get()`]: #method.get
|
||||
/// [`put()`]: #method.put
|
||||
/// [`post()`]: #method.post
|
||||
pub struct Client {
|
||||
cargo: Cargo,
|
||||
pub(crate) cookies: Option<RwLock<CookieJar>>,
|
||||
(@$import:literal, $NAME:literal, $use_it:expr, $f:ident, $method:expr) => (
|
||||
/// Create a local `
|
||||
#[doc = $NAME]
|
||||
/// ` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
#[doc = $use_it]
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn $f<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self.req($method, uri)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Constructs a new `Client`. If `tracked` is `true`, an empty `CookieJar`
|
||||
/// is created for cookie tracking. Otherwise, the internal `CookieJar` is
|
||||
/// set to `None`.
|
||||
async fn _new(mut rocket: Rocket, tracked: bool) -> Result<Client, LaunchError> {
|
||||
rocket.prelaunch_check().await?;
|
||||
let cookies = match tracked {
|
||||
true => Some(RwLock::new(CookieJar::new())),
|
||||
false => None
|
||||
};
|
||||
macro_rules! impl_client {
|
||||
($import:literal $(@$prefix:tt $suffix:tt)? $name:ident) =>
|
||||
{
|
||||
impl $name {
|
||||
/// Construct a new `Client` from an instance of `Rocket` with cookie
|
||||
/// tracking.
|
||||
///
|
||||
/// # Cookie Tracking
|
||||
///
|
||||
/// By default, a `Client` propagates cookie changes made by responses
|
||||
/// to previously dispatched requests. In other words, if a previously
|
||||
/// dispatched request resulted in a response that adds a cookie, any
|
||||
/// future requests will contain the new cookies. Similarly, cookies
|
||||
/// removed by a response won't be propagated further.
|
||||
///
|
||||
/// This is typically the desired mode of operation for a `Client` as it
|
||||
/// removes the burden of manually tracking cookies. Under some
|
||||
/// circumstances, however, disabling this tracking may be desired. The
|
||||
/// [`untracked()`](Client::untracked()) method creates a `Client` that
|
||||
/// _will not_ track cookies.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If launching the `Rocket` instance would fail, excepting network errors,
|
||||
/// the `LaunchError` is returned.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[doc = $import]
|
||||
///
|
||||
/// let rocket = rocket::ignite();
|
||||
/// let client = Client::new(rocket);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub $($prefix)? fn new(rocket: Rocket) -> Result<Self, LaunchError> {
|
||||
Self::_new(rocket, true) $(.$suffix)?
|
||||
}
|
||||
|
||||
Ok(Client { cargo: rocket.into_cargo().await, cookies })
|
||||
/// Construct a new `Client` from an instance of `Rocket` _without_
|
||||
/// cookie tracking.
|
||||
///
|
||||
/// # Cookie Tracking
|
||||
///
|
||||
/// Unlike the [`new()`](Client::new()) constructor, a `Client` returned
|
||||
/// from this method _does not_ automatically propagate cookie changes.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If launching the `Rocket` instance would fail, excepting network
|
||||
/// errors, the `LaunchError` is returned.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[doc = $import]
|
||||
///
|
||||
/// let rocket = rocket::ignite();
|
||||
/// let client = Client::untracked(rocket);
|
||||
/// ```
|
||||
pub $($prefix)? fn untracked(rocket: Rocket) -> Result<Self, LaunchError> {
|
||||
Self::_new(rocket, true) $(.$suffix)?
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Rocket` this client is creating requests
|
||||
/// for.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let rocket = client.rocket();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn rocket(&self) -> &Rocket {
|
||||
&*self._cargo()
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Cargo` of the `Rocket` this client is
|
||||
/// creating requests for.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let cargo = client.cargo();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn cargo(&self) -> &Cargo {
|
||||
self._cargo()
|
||||
}
|
||||
|
||||
req_method!($import, "GET", get, Method::Get);
|
||||
req_method!($import, "PUT", put, Method::Put);
|
||||
req_method!($import, "POST", post, Method::Post);
|
||||
req_method!($import, "DELETE", delete, Method::Delete);
|
||||
req_method!($import, "OPTIONS", options, Method::Options);
|
||||
req_method!($import, "HEAD", head, Method::Head);
|
||||
req_method!($import, "PATCH", patch, Method::Patch);
|
||||
|
||||
/// Create a local `GET` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of
|
||||
/// Rocket within `self`. The request is not dispatched automatically.
|
||||
/// To actually dispatch the request, call [`LocalRequest::dispatch()`]
|
||||
/// on the returned request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
#[doc = $import]
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// client.req(Method::Get, "/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn req<'c, 'u: 'c, U>(
|
||||
&'c self,
|
||||
method: Method,
|
||||
uri: U
|
||||
) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self._req(method, uri)
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a new `Client` from an instance of `Rocket` with cookie
|
||||
/// tracking.
|
||||
///
|
||||
/// # Cookie Tracking
|
||||
///
|
||||
/// By default, a `Client` propagates cookie changes made by responses to
|
||||
/// previously dispatched requests. In other words, if a previously
|
||||
/// dispatched request resulted in a response that adds a cookie, any future
|
||||
/// requests will contain the new cookies. Similarly, cookies removed by a
|
||||
/// response won't be propagated further.
|
||||
///
|
||||
/// This is typically the desired mode of operation for a `Client` as it
|
||||
/// removes the burden of manually tracking cookies. Under some
|
||||
/// circumstances, however, disabling this tracking may be desired. The
|
||||
/// [`untracked()`](Client::untracked()) method creates a `Client` that
|
||||
/// _will not_ track cookies.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If launching the `Rocket` instance would fail, excepting network errors,
|
||||
/// the `LaunchError` is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # let _ = async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// # };
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn new(rocket: Rocket) -> Result<Client, LaunchError> {
|
||||
Client::_new(rocket, true).await
|
||||
}
|
||||
|
||||
/// Construct a new `Client` from an instance of `Rocket` _without_ cookie
|
||||
/// tracking.
|
||||
///
|
||||
/// # Cookie Tracking
|
||||
///
|
||||
/// Unlike the [`new()`](Client::new()) constructor, a `Client` returned
|
||||
/// from this method _does not_ automatically propagate cookie changes.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If launching the `Rocket` instance would fail, excepting network errors,
|
||||
/// the `LaunchError` is returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::untracked(rocket::ignite()).await.expect("valid rocket");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn untracked(rocket: Rocket) -> Result<Client, LaunchError> {
|
||||
Client::_new(rocket, false).await
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Rocket` of the `Rocket` this client is
|
||||
/// creating requests for.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let my_rocket = rocket::ignite();
|
||||
/// let client = Client::new(my_rocket).await.expect("valid rocket");
|
||||
///
|
||||
/// let rocket = client.rocket();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn rocket(&self) -> &Rocket {
|
||||
&*self.cargo
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Rocket` of the `Rocket` this client is
|
||||
/// creating requests for.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let my_rocket = rocket::ignite();
|
||||
/// let client = Client::new(my_rocket).await.expect("valid rocket");
|
||||
///
|
||||
/// let cargo = client.cargo();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn cargo(&self) -> &Cargo {
|
||||
&self.cargo
|
||||
}
|
||||
|
||||
/// Create a local `GET` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.get("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn get<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Get, uri)
|
||||
}
|
||||
|
||||
/// Create a local `PUT` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.put("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn put<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Put, uri)
|
||||
}
|
||||
|
||||
/// Create a local `POST` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
///
|
||||
/// let req = client.post("/hello")
|
||||
/// .body("field=value&otherField=123")
|
||||
/// .header(ContentType::Form);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn post<'c, 'u: 'c, U: Into<Cow<'u, str>>>(&'c self, uri: U) -> LocalRequest<'c> {
|
||||
self.req(Method::Post, uri)
|
||||
}
|
||||
|
||||
/// Create a local `DELETE` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.delete("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn delete<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self.req(Method::Delete, uri)
|
||||
}
|
||||
|
||||
/// Create a local `OPTIONS` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.options("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn options<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self.req(Method::Options, uri)
|
||||
}
|
||||
|
||||
/// Create a local `HEAD` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.head("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn head<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self.req(Method::Head, uri)
|
||||
}
|
||||
|
||||
/// Create a local `PATCH` request to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.patch("/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn patch<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
self.req(Method::Patch, uri)
|
||||
}
|
||||
|
||||
/// Create a local request with method `method` to the URI `uri`.
|
||||
///
|
||||
/// When dispatched, the request will be served by the instance of Rocket
|
||||
/// within `self`. The request is not dispatched automatically. To actually
|
||||
/// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
|
||||
/// request.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::Method;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.req(Method::Get, "/hello");
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn req<'c, 'u: 'c, U>(&'c self, method: Method, uri: U) -> LocalRequest<'c>
|
||||
where U: Into<Cow<'u, str>>
|
||||
{
|
||||
LocalRequest::new(self, method, uri.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Client;
|
||||
|
||||
fn assert_sync<T: Sync>() {}
|
||||
|
||||
#[test]
|
||||
fn test_local_client_impl_sync() {
|
||||
assert_sync::<Client>();
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
//! 2. Construct a `Client` using the `Rocket` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # use rocket::local::asynchronous::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # rocket::async_test(async {
|
||||
//! let client = Client::new(rocket).await.expect("valid rocket instance");
|
||||
|
@ -32,7 +32,7 @@
|
|||
//! 3. Construct requests using the `Client` instance.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # use rocket::local::asynchronous::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # rocket::async_test(async {
|
||||
//! # let client = Client::new(rocket).await.unwrap();
|
||||
|
@ -44,7 +44,7 @@
|
|||
//! 3. Dispatch the request to retrieve the response.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use rocket::local::Client;
|
||||
//! # use rocket::local::asynchronous::Client;
|
||||
//! # let rocket = rocket::ignite();
|
||||
//! # rocket::async_test(async {
|
||||
//! # let client = Client::new(rocket).await.unwrap();
|
||||
|
@ -57,7 +57,7 @@
|
|||
//! All together and in idiomatic fashion, this might look like:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::local::Client;
|
||||
//! use rocket::local::asynchronous::Client;
|
||||
//!
|
||||
//! # rocket::async_test(async {
|
||||
//! let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
|
@ -88,7 +88,7 @@
|
|||
//! #[cfg(test)]
|
||||
//! mod test {
|
||||
//! use super::{rocket, hello};
|
||||
//! use rocket::local::Client;
|
||||
//! use rocket::local::asynchronous::Client;
|
||||
//!
|
||||
//! #[rocket::async_test]
|
||||
//! fn test_hello_world() {
|
||||
|
@ -98,16 +98,17 @@
|
|||
//!
|
||||
//! // Dispatch a request to 'GET /' and validate the response.
|
||||
//! let mut response = client.get("/").dispatch().await;
|
||||
//! assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
//! assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`Client`]: crate::local::Client
|
||||
//! [`Client`]: crate::local::asynchronous::Client
|
||||
//! [`LocalRequest`]: crate::local::LocalRequest
|
||||
|
||||
mod request;
|
||||
mod client;
|
||||
#[macro_use] mod client;
|
||||
#[macro_use] mod request;
|
||||
#[macro_use] mod response;
|
||||
|
||||
pub use self::request::{LocalResponse, LocalRequest};
|
||||
pub use self::client::Client;
|
||||
pub mod asynchronous;
|
||||
pub mod blocking;
|
||||
|
|
|
@ -1,627 +1,310 @@
|
|||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use std::net::SocketAddr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::borrow::Cow;
|
||||
//! A structure representing a local request as created by [`Client`].
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! A `LocalRequest` value is constructed via method constructors on [`Client`].
|
||||
//! Headers can be added via the [`header`] builder method and the
|
||||
//! [`add_header`] method. Cookies can be added via the [`cookie`] builder
|
||||
//! method. The remote IP address can be set via the [`remote`] builder method.
|
||||
//! The body of the request can be set via the [`body`] builder method or
|
||||
//! [`set_body`] method.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! The following snippet uses the available builder methods to construct a
|
||||
//! `POST` request to `/` with a JSON body:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use rocket::local::asynchronous::Client;
|
||||
//! use rocket::http::{ContentType, Cookie};
|
||||
//!
|
||||
//! # rocket::async_test(async {
|
||||
//! let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
//! let req = client.post("/")
|
||||
//! .header(ContentType::JSON)
|
||||
//! .remote("127.0.0.1:8000".parse().unwrap())
|
||||
//! .cookie(Cookie::new("name", "value"))
|
||||
//! .body(r#"{ "value": 42 }"#);
|
||||
//! # });
|
||||
//! ```
|
||||
//!
|
||||
//! # Dispatching
|
||||
//!
|
||||
//! A `LocalRequest` can be dispatched in one of two ways:
|
||||
//!
|
||||
//! 1. [`dispatch`]
|
||||
//!
|
||||
//! This method should always be preferred. The `LocalRequest` is consumed
|
||||
//! and a response is returned.
|
||||
//!
|
||||
//! 2. [`mut_dispatch`]
|
||||
//!
|
||||
//! This method should _only_ be used when either it is known that the
|
||||
//! application will not modify the request, or it is desired to see
|
||||
//! modifications to the request. No cloning occurs, and the request is not
|
||||
//! consumed.
|
||||
//!
|
||||
//! Additionally, note that `LocalRequest` implements `Clone`. As such, if the
|
||||
//! same request needs to be dispatched multiple times, the request can first be
|
||||
//! cloned and then dispatched: `request.clone().dispatch()`.
|
||||
//!
|
||||
//! [`Client`]: crate::local::asynchronous::Client
|
||||
//! [`header`]: #method.header
|
||||
//! [`add_header`]: #method.add_header
|
||||
//! [`cookie`]: #method.cookie
|
||||
//! [`remote`]: #method.remote
|
||||
//! [`body`]: #method.body
|
||||
//! [`set_body`]: #method.set_body
|
||||
//! [`dispatch`]: #method.dispatch
|
||||
//! [`mut_dispatch`]: #method.mut_dispatch
|
||||
|
||||
use crate::{Request, Response, Data};
|
||||
use crate::http::{Status, Method, Header, Cookie, uri::Origin, ext::IntoOwned};
|
||||
use crate::local::Client;
|
||||
macro_rules! impl_request {
|
||||
($import:literal $(@$prefix:tt $suffix:tt)? $name:ident) =>
|
||||
{
|
||||
impl<'c> $name<'c> {
|
||||
/// Retrieves the inner `Request` as seen by Rocket.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::Request;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let req = client.get("/");
|
||||
/// let inner: &Request = req.inner();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn inner(&self) -> &Request<'c> {
|
||||
self._request()
|
||||
}
|
||||
|
||||
/// A structure representing a local request as created by [`Client`].
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// A `LocalRequest` value is constructed via method constructors on [`Client`].
|
||||
/// Headers can be added via the [`header`] builder method and the
|
||||
/// [`add_header`] method. Cookies can be added via the [`cookie`] builder
|
||||
/// method. The remote IP address can be set via the [`remote`] builder method.
|
||||
/// The body of the request can be set via the [`body`] builder method or
|
||||
/// [`set_body`] method.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// The following snippet uses the available builder methods to construct a
|
||||
/// `POST` request to `/` with a JSON body:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::{ContentType, Cookie};
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.post("/")
|
||||
/// .header(ContentType::JSON)
|
||||
/// .remote("127.0.0.1:8000".parse().unwrap())
|
||||
/// .cookie(Cookie::new("name", "value"))
|
||||
/// .body(r#"{ "value": 42 }"#);
|
||||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// # Dispatching
|
||||
///
|
||||
/// A `LocalRequest` can be dispatched in one of two ways:
|
||||
///
|
||||
/// 1. [`dispatch`]
|
||||
///
|
||||
/// This method should always be preferred. The `LocalRequest` is consumed
|
||||
/// and a response is returned.
|
||||
///
|
||||
/// 2. [`mut_dispatch`]
|
||||
///
|
||||
/// This method should _only_ be used when either it is known that the
|
||||
/// application will not modify the request, or it is desired to see
|
||||
/// modifications to the request. No cloning occurs, and the request is not
|
||||
/// consumed.
|
||||
///
|
||||
/// Additionally, note that `LocalRequest` implements `Clone`. As such, if the
|
||||
/// same request needs to be dispatched multiple times, the request can first be
|
||||
/// cloned and then dispatched: `request.clone().dispatch()`.
|
||||
///
|
||||
/// [`Client`]: crate::local::Client
|
||||
/// [`header`]: #method.header
|
||||
/// [`add_header`]: #method.add_header
|
||||
/// [`cookie`]: #method.cookie
|
||||
/// [`remote`]: #method.remote
|
||||
/// [`body`]: #method.body
|
||||
/// [`set_body`]: #method.set_body
|
||||
/// [`dispatch`]: #method.dispatch
|
||||
/// [`mut_dispatch`]: #method.mut_dispatch
|
||||
pub struct LocalRequest<'c> {
|
||||
client: &'c Client,
|
||||
// This `Arc` exists so that we can transfer ownership to the `LocalResponse`
|
||||
// selectively on dispatch. This is necessary because responses may point
|
||||
// into the request, and thus the request and all of its data needs to be
|
||||
// alive while the response is accessible.
|
||||
//
|
||||
// Because both a `LocalRequest` and a `LocalResponse` can hold an `Arc` to
|
||||
// the same `Request`, _and_ the `LocalRequest` can mutate the request, we
|
||||
// must ensure that 1) neither `LocalRequest` not `LocalResponse` are `Sync`
|
||||
// or `Send` and 2) mutations carried out in `LocalRequest` are _stable_:
|
||||
// they never _remove_ data, and any reallocations (say, for vectors or
|
||||
// hashmaps) result in object pointers remaining the same. This means that
|
||||
// even if the `Request` is mutated by a `LocalRequest`, those mutations are
|
||||
// not observable by `LocalResponse`.
|
||||
//
|
||||
// The first is ensured by the embedding of the `Arc` type which is neither
|
||||
// `Send` nor `Sync`. The second is more difficult to argue. First, observe
|
||||
// that any methods of `LocalRequest` that _remove_ values from `Request`
|
||||
// only remove _Copy_ values, in particular, `SocketAddr`. Second, the
|
||||
// lifetime of the `Request` object is tied to the lifetime of the
|
||||
// `LocalResponse`, so references from `Request` cannot be dangling in
|
||||
// `Response`. And finally, observe how all of the data stored in `Request`
|
||||
// is converted into its owned counterpart before insertion, ensuring stable
|
||||
// addresses. Together, these properties guarantee the second condition.
|
||||
request: Arc<Request<'c>>,
|
||||
data: Vec<u8>,
|
||||
uri: Cow<'c, str>,
|
||||
}
|
||||
/// Add a header to this request.
|
||||
///
|
||||
/// Any type that implements `Into<Header>` can be used here. Among
|
||||
/// others, this includes [`ContentType`] and [`Accept`].
|
||||
///
|
||||
/// [`ContentType`]: crate::http::ContentType
|
||||
/// [`Accept`]: crate::http::Accept
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let req = client.get("/").header(ContentType::JSON);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn header<H>(mut self, header: H) -> Self
|
||||
where H: Into<crate::http::Header<'static>>
|
||||
{
|
||||
self._request_mut().add_header(header.into());
|
||||
self
|
||||
}
|
||||
|
||||
impl<'c> LocalRequest<'c> {
|
||||
#[inline(always)]
|
||||
pub(crate) fn new(
|
||||
client: &'c Client,
|
||||
method: Method,
|
||||
uri: Cow<'c, str>
|
||||
) -> LocalRequest<'c> {
|
||||
// We set a dummy string for now and check the user's URI on dispatch.
|
||||
let request = Request::new(client.rocket(), method, Origin::dummy());
|
||||
/// Adds a header to this request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let mut req = client.get("/");
|
||||
/// req.add_header(ContentType::JSON);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn add_header<H>(&mut self, header: H)
|
||||
where H: Into<crate::http::Header<'static>>
|
||||
{
|
||||
self._request_mut().add_header(header.into());
|
||||
}
|
||||
|
||||
// Set up any cookies we know about.
|
||||
if let Some(ref jar) = client.cookies {
|
||||
let cookies = jar.read().expect("LocalRequest::new() read lock");
|
||||
for cookie in cookies.iter() {
|
||||
request.cookies().add_original(cookie.clone().into_owned());
|
||||
/// Set the remote address of this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the remote address to "8.8.8.8:80":
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let address = "8.8.8.8:80".parse().unwrap();
|
||||
///
|
||||
/// let client: Client = client;
|
||||
/// let req = client.get("/").remote(address);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn remote(mut self, address: std::net::SocketAddr) -> Self {
|
||||
self._request_mut().set_remote(address);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a cookie to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let req = client.get("/")
|
||||
/// .cookie(Cookie::new("username", "sb"))
|
||||
/// .cookie(Cookie::new("user_id", "12"));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookie(self, cookie: crate::http::Cookie<'_>) -> Self {
|
||||
self._request().cookies().add_original(cookie.into_owned());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add all of the cookies in `cookies` to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let cookies = vec![Cookie::new("a", "b"), Cookie::new("c", "d")];
|
||||
/// let req = client.get("/").cookies(cookies);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookies(self, cookies: Vec<crate::http::Cookie<'_>>) -> Self {
|
||||
for cookie in cookies {
|
||||
self._request().cookies().add_original(cookie.into_owned());
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
// See the comments on the structure for what's going on here.
|
||||
let request = Arc::new(request);
|
||||
LocalRequest { client, request, uri, data: vec![] }
|
||||
}
|
||||
|
||||
/// Retrieves the inner `Request` as seen by Rocket.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.expect("valid rocket");
|
||||
/// let req = client.get("/");
|
||||
/// let inner_req = req.inner();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &Request<'c> {
|
||||
&*self.request
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn request_mut(&mut self) -> &mut Request<'c> {
|
||||
// See the comments in the structure for the argument of correctness.
|
||||
Arc::get_mut(&mut self.request).expect("mutable aliasing!")
|
||||
}
|
||||
|
||||
// This method should _never_ be publicly exposed!
|
||||
#[inline(always)]
|
||||
fn long_lived_request<'a>(&mut self) -> &'a mut Request<'c> {
|
||||
// See the comments in the structure for the argument of correctness.
|
||||
// Additionally, the caller must ensure that the owned instance of
|
||||
// `Arc<Request>` remains valid as long as the returned reference can be
|
||||
// accessed.
|
||||
unsafe { &mut *(self.request_mut() as *mut _) }
|
||||
}
|
||||
|
||||
/// Add a header to this request.
|
||||
///
|
||||
/// Any type that implements `Into<Header>` can be used here. Among others,
|
||||
/// this includes [`ContentType`] and [`Accept`].
|
||||
///
|
||||
/// [`ContentType`]: crate::http::ContentType
|
||||
/// [`Accept`]: crate::http::Accept
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let req = client.get("/").header(ContentType::JSON);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn header<H: Into<Header<'static>>>(mut self, header: H) -> Self {
|
||||
self.request_mut().add_header(header.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a header to this request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add the Content-Type header:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let mut req = client.get("/");
|
||||
/// req.add_header(ContentType::JSON);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn add_header<H: Into<Header<'static>>>(&mut self, header: H) {
|
||||
self.request_mut().add_header(header.into());
|
||||
}
|
||||
|
||||
/// Set the remote address of this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the remote address to "8.8.8.8:80":
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let address = "8.8.8.8:80".parse().unwrap();
|
||||
/// let req = client.get("/").remote(address);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn remote(mut self, address: SocketAddr) -> Self {
|
||||
self.request_mut().set_remote(address);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a cookie to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.get("/")
|
||||
/// .cookie(Cookie::new("username", "sb"))
|
||||
/// .cookie(Cookie::new("user_id", "12"));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookie(self, cookie: Cookie<'_>) -> Self {
|
||||
self.request.cookies().add_original(cookie.into_owned());
|
||||
self
|
||||
}
|
||||
|
||||
/// Add all of the cookies in `cookies` to this request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` cookie:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let cookies = vec![Cookie::new("a", "b"), Cookie::new("c", "d")];
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.get("/").cookies(cookies);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cookies(self, cookies: Vec<Cookie<'_>>) -> Self {
|
||||
for cookie in cookies {
|
||||
self.request.cookies().add_original(cookie.into_owned());
|
||||
/// Add a [private cookie] to this request.
|
||||
///
|
||||
/// This method is only available when the `private-cookies` feature is
|
||||
/// enabled.
|
||||
///
|
||||
/// [private cookie]: crate::http::Cookies::add_private()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` as a private cookie:
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let req = client.get("/").private_cookie(Cookie::new("user_id", "sb"));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(feature = "private-cookies")]
|
||||
pub fn private_cookie(self, cookie: crate::http::Cookie<'static>) -> Self {
|
||||
self._request().cookies().add_original_private(cookie);
|
||||
self
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a [private cookie] to this request.
|
||||
///
|
||||
/// This method is only available when the `private-cookies` feature is
|
||||
/// enabled.
|
||||
///
|
||||
/// [private cookie]: crate::http::Cookies::add_private()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Add `user_id` as a private cookie:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::Cookie;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.get("/").private_cookie(Cookie::new("user_id", "sb"));
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
#[cfg(feature = "private-cookies")]
|
||||
pub fn private_cookie(self, cookie: Cookie<'static>) -> Self {
|
||||
self.request.cookies().add_original_private(cookie);
|
||||
self
|
||||
}
|
||||
|
||||
// TODO: For CGI, we want to be able to set the body to be stdin without
|
||||
// actually reading everything into a vector. Can we allow that here while
|
||||
// keeping the simplicity? Looks like it would require us to reintroduce a
|
||||
// NetStream::Local(Box<Read>) or something like that.
|
||||
|
||||
/// Set the body (data) of the request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// # #[allow(unused_variables)]
|
||||
/// let req = client.post("/")
|
||||
/// .header(ContentType::JSON)
|
||||
/// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
|
||||
self.data = body.as_ref().into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the body (data) of the request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let mut req = client.post("/").header(ContentType::JSON);
|
||||
/// req.set_body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) {
|
||||
self.data = body.as_ref().into();
|
||||
}
|
||||
|
||||
/// Dispatches the request, returning the response.
|
||||
///
|
||||
/// This method consumes `self` and is the preferred mechanism for
|
||||
/// dispatching.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let response = client.get("/").dispatch();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn dispatch(mut self) -> LocalResponse<'c> {
|
||||
let r = self.long_lived_request();
|
||||
LocalRequest::_dispatch(self.client, r, self.request, &self.uri, self.data).await
|
||||
}
|
||||
|
||||
/// Dispatches the request, returning the response.
|
||||
///
|
||||
/// This method _does not_ consume or clone `self`. Any changes to the
|
||||
/// request that occur during handling will be visible after this method is
|
||||
/// called. For instance, body data is always consumed after a request is
|
||||
/// dispatched. As such, only the first call to `mut_dispatch` for a given
|
||||
/// `LocalRequest` will contains the original body data.
|
||||
///
|
||||
/// This method should _only_ be used when either it is known that
|
||||
/// the application will not modify the request, or it is desired to see
|
||||
/// modifications to the request. Prefer to use [`dispatch`] instead.
|
||||
///
|
||||
/// [`dispatch`]: #method.dispatch
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::Client;
|
||||
///
|
||||
/// rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
///
|
||||
/// let mut req = client.get("/");
|
||||
/// let response_a = req.mut_dispatch().await;
|
||||
/// // TODO.async: Annoying. Is this really a good example to show?
|
||||
/// drop(response_a);
|
||||
/// let response_b = req.mut_dispatch().await;
|
||||
/// })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub async fn mut_dispatch(&mut self) -> LocalResponse<'c> {
|
||||
let req = self.long_lived_request();
|
||||
let data = std::mem::replace(&mut self.data, vec![]);
|
||||
let rc_req = self.request.clone();
|
||||
LocalRequest::_dispatch(self.client, req, rc_req, &self.uri, data).await
|
||||
}
|
||||
|
||||
// Performs the actual dispatch.
|
||||
// TODO.async: @jebrosen suspects there might be actual UB in here after all,
|
||||
// and now we just went and mixed threads into it
|
||||
async fn _dispatch(
|
||||
client: &'c Client,
|
||||
request: &'c mut Request<'c>,
|
||||
owned_request: Arc<Request<'c>>,
|
||||
uri: &str,
|
||||
data: Vec<u8>
|
||||
) -> LocalResponse<'c> {
|
||||
let maybe_uri = Origin::parse(uri);
|
||||
|
||||
// First, validate the URI, returning an error response (generated from
|
||||
// an error catcher) immediately if it's invalid.
|
||||
if let Ok(uri) = maybe_uri {
|
||||
request.set_uri(uri.into_owned());
|
||||
} else {
|
||||
error!("Malformed request URI: {}", uri);
|
||||
let res = client.rocket().handle_error(Status::BadRequest, request).await;
|
||||
return LocalResponse { _request: owned_request, response: res };
|
||||
/// Set the body (data) of the request.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let req = client.post("/")
|
||||
/// .header(ContentType::JSON)
|
||||
/// .body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn body<S: AsRef<[u8]>>(mut self, body: S) -> Self {
|
||||
// TODO: For CGI, we want to be able to set the body to be stdin
|
||||
// without actually reading everything into a vector. Can we allow
|
||||
// that here while keeping the simplicity? Looks like it would
|
||||
// require us to reintroduce a NetStream::Local(Box<Read>) or
|
||||
// something like that.
|
||||
*self._body_mut() = body.as_ref().into();
|
||||
self
|
||||
}
|
||||
|
||||
// Actually dispatch the request.
|
||||
let response = client.rocket().dispatch(request, Data::local(data)).await;
|
||||
|
||||
// If the client is tracking cookies, updates the internal cookie jar
|
||||
// with the changes reflected by `response`.
|
||||
if let Some(ref jar) = client.cookies {
|
||||
let mut jar = jar.write().expect("LocalRequest::_dispatch() write lock");
|
||||
let current_time = time::OffsetDateTime::now_utc();
|
||||
for cookie in response.cookies() {
|
||||
if let Some(expires) = cookie.expires() {
|
||||
if expires <= current_time {
|
||||
jar.force_remove(cookie);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
jar.add(cookie.into_owned());
|
||||
}
|
||||
/// Set the body (data) of the request without consuming `self`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Set the body to be a JSON structure; also sets the Content-Type.
|
||||
///
|
||||
/// ```rust
|
||||
#[doc = $import]
|
||||
/// use rocket::http::ContentType;
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let mut req = client.post("/").header(ContentType::JSON);
|
||||
/// req.set_body(r#"{ "key": "value", "array": [1, 2, 3], }"#);
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn set_body<S: AsRef<[u8]>>(&mut self, body: S) {
|
||||
*self._body_mut() = body.as_ref().into();
|
||||
}
|
||||
|
||||
LocalResponse {
|
||||
_request: owned_request,
|
||||
response: response
|
||||
/// Dispatches the request, returning the response.
|
||||
///
|
||||
/// This method consumes `self` and is the preferred mechanism for
|
||||
/// dispatching.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket::local::asynchronous::Client;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let client = Client::new(rocket::ignite()).await.unwrap();
|
||||
/// let response = client.get("/").dispatch();
|
||||
/// # });
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub $($prefix)? fn dispatch(self) -> LocalResponse<'c> {
|
||||
self._dispatch()$(.$suffix)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LocalRequest<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.request, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure representing a response from dispatching a local request.
|
||||
///
|
||||
/// This structure is a thin wrapper around [`Response`]. It implements no
|
||||
/// methods of its own; all functionality is exposed via the [`Deref`] and
|
||||
/// [`DerefMut`] implementations with a target of `Response`. In other words,
|
||||
/// when invoking methods, a `LocalResponse` can be treated exactly as if it
|
||||
/// were a `Response`.
|
||||
pub struct LocalResponse<'c> {
|
||||
_request: Arc<Request<'c>>,
|
||||
response: Response<'c>,
|
||||
}
|
||||
|
||||
impl<'c> Deref for LocalResponse<'c> {
|
||||
type Target = Response<'c>;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Response<'c> {
|
||||
&self.response
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> DerefMut for LocalResponse<'c> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Response<'c> {
|
||||
&mut self.response
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for LocalResponse<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.response, f)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO.async: Figure out a way to accomplish this
|
||||
//impl<'c> Clone for LocalRequest<'c> {
|
||||
// fn clone(&self) -> LocalRequest<'c> {
|
||||
// LocalRequest {
|
||||
// client: self.client,
|
||||
// request: self.request.clone(),
|
||||
// data: self.data.clone(),
|
||||
// uri: self.uri.clone()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::Request;
|
||||
use crate::local::Client;
|
||||
|
||||
#[test]
|
||||
fn clone_unique_ptr() {
|
||||
let client = Client::new(crate::ignite()).unwrap();
|
||||
let r1 = client.get("/");
|
||||
let r2 = r1.clone();
|
||||
|
||||
assert_ne!(
|
||||
r1.inner() as *const Request<'_>,
|
||||
r2.inner() as *const Request<'_>
|
||||
);
|
||||
impl std::fmt::Debug for $name<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self._request().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// #[compile_fail]
|
||||
// fn local_req_not_sync() {
|
||||
// fn is_sync<T: Sync>() { }
|
||||
// is_sync::<::local::LocalRequest>();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[compile_fail]
|
||||
// fn local_req_not_send() {
|
||||
// fn is_send<T: Send>() { }
|
||||
// is_send::<::local::LocalRequest>();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[compile_fail]
|
||||
// fn local_req_not_sync() {
|
||||
// fn is_sync<T: Sync>() { }
|
||||
// is_sync::<::local::LocalResponse>();
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// #[compile_fail]
|
||||
// fn local_req_not_send() {
|
||||
// fn is_send<T: Send>() { }
|
||||
// is_send::<::local::LocalResponse>();
|
||||
// }
|
||||
|
||||
// This checks that a response can't outlive the `Client`.
|
||||
// #[compile_fail]
|
||||
// fn test() {
|
||||
// use {Rocket, local::Client};
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let res = {
|
||||
// let mut client = Client::new(rocket).unwrap();
|
||||
// client.get("/").dispatch()
|
||||
// };
|
||||
|
||||
// // let client = Client::new(rocket).unwrap();
|
||||
// // let res1 = client.get("/").dispatch();
|
||||
// // let res2 = client.get("/").dispatch();
|
||||
// }
|
||||
|
||||
// This checks that a response can't outlive the `Client`.
|
||||
// #[compile_fail]
|
||||
// fn test() {
|
||||
// use {Rocket, local::Client};
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let res = {
|
||||
// Client::new(rocket).unwrap()
|
||||
// .get("/").dispatch();
|
||||
// };
|
||||
|
||||
// // let client = Client::new(rocket).unwrap();
|
||||
// // let res1 = client.get("/").dispatch();
|
||||
// // let res2 = client.get("/").dispatch();
|
||||
// }
|
||||
|
||||
// This checks that a response can't outlive the `Client`, in this case, by
|
||||
// moving `client` while it is borrowed.
|
||||
// #[compile_fail]
|
||||
// fn test() {
|
||||
// use {Rocket, local::Client};
|
||||
|
||||
// let rocket = Rocket::ignite();
|
||||
// let client = Client::new(rocket).unwrap();
|
||||
|
||||
// let res = {
|
||||
// let x = client.get("/").dispatch();
|
||||
// let y = client.get("/").dispatch();
|
||||
// (x, y)
|
||||
// };
|
||||
|
||||
// let x = client;
|
||||
// }
|
||||
|
||||
// #[compile_fail]
|
||||
// fn test() {
|
||||
// use {Rocket, local::Client};
|
||||
|
||||
// let rocket1 = Rocket::ignite();
|
||||
// let rocket2 = Rocket::ignite();
|
||||
|
||||
// let client1 = Client::new(rocket1).unwrap();
|
||||
// let client2 = Client::new(rocket2).unwrap();
|
||||
|
||||
// let res = {
|
||||
// let mut res1 = client1.get("/");
|
||||
// res1.client = &client2;
|
||||
// res1
|
||||
// };
|
||||
|
||||
// drop(client1);
|
||||
// }
|
||||
}
|
||||
// TODO: Add test to check that `LocalRequest` is `Clone`.
|
||||
}}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
//! A structure representing a response from dispatching a local request.
|
||||
//!
|
||||
//! This structure is a thin wrapper around [`Response`]. It implements no
|
||||
//! methods of its own; all functionality is exposed via the [`Deref`] and
|
||||
//! [`DerefMut`] implementations with a target of `Response`. In other words,
|
||||
//! when invoking methods, a `LocalResponse` can be treated exactly as if it
|
||||
//! were a `Response`.
|
||||
|
||||
macro_rules! impl_response {
|
||||
($import:literal $(@$prefix:tt $suffix:tt)? $name:ident) =>
|
||||
{
|
||||
impl<'c> $name<'c> {
|
||||
/// Consumes `self` reads its body into a string. If `self` doesn't have
|
||||
/// a body, reading fails, or string conversion (for non-UTF-8 bodies)
|
||||
/// fails, returns `None`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let response = client.get("/").body("Hello!").dispatch();
|
||||
/// assert_eq!(response.into_string().unwrap(), "Hello!");
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub $($prefix)? fn into_string(self) -> Option<String> {
|
||||
self._into_string() $(.$suffix)?
|
||||
}
|
||||
|
||||
/// Consumes `self` and reads its body into a `Vec` of `u8` bytes. If
|
||||
/// `self` doesn't have a body or reading fails returns `None`. Note
|
||||
/// that `self`'s `body` is consumed after a call to this method.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,ignore
|
||||
#[doc = $import]
|
||||
///
|
||||
/// # Client::_test(|client| {
|
||||
/// let client: Client = client;
|
||||
/// let response = client.get("/").body("Hello!").dispatch();
|
||||
/// assert_eq!(response.into_bytes().unwrap(), "Hello!".as_bytes());
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub $($prefix)? fn into_bytes(self) -> Option<Vec<u8>> {
|
||||
self._into_bytes() $(.$suffix)?
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for LocalResponse<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self._response().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c> std::ops::Deref for LocalResponse<'c> {
|
||||
type Target = Response<'c>;
|
||||
|
||||
fn deref(&self) -> &Response<'c> {
|
||||
self._response()
|
||||
}
|
||||
}
|
||||
}}
|
|
@ -7,6 +7,7 @@ use std::str;
|
|||
use yansi::Paint;
|
||||
use state::{Container, Storage};
|
||||
use futures::future::BoxFuture;
|
||||
use atomic::Atomic;
|
||||
|
||||
use crate::request::{FromParam, FromSegments, FromRequest, Outcome};
|
||||
use crate::request::{FromFormValue, FormItems, FormItem};
|
||||
|
@ -27,16 +28,14 @@ type Indices = (usize, usize);
|
|||
/// should likely only be used when writing [`FromRequest`] implementations. It
|
||||
/// contains all of the information for a given web request except for the body
|
||||
/// data. This includes the HTTP method, URI, cookies, headers, and more.
|
||||
//#[derive(Clone)]
|
||||
pub struct Request<'r> {
|
||||
method: RwLock<Method>,
|
||||
method: Atomic<Method>,
|
||||
uri: Origin<'r>,
|
||||
headers: HeaderMap<'r>,
|
||||
remote: Option<SocketAddr>,
|
||||
pub(crate) state: RequestState<'r>,
|
||||
}
|
||||
|
||||
//#[derive(Clone)]
|
||||
pub(crate) struct RequestState<'r> {
|
||||
pub config: &'r Config,
|
||||
pub managed: &'r Container,
|
||||
|
@ -49,6 +48,42 @@ pub(crate) struct RequestState<'r> {
|
|||
pub cache: Arc<Container>,
|
||||
}
|
||||
|
||||
impl<'r> Request<'r> {
|
||||
pub(crate) fn clone(&self) -> Self {
|
||||
Request {
|
||||
method: Atomic::new(self.method()),
|
||||
uri: self.uri.clone(),
|
||||
headers: self.headers.clone(),
|
||||
remote: self.remote.clone(),
|
||||
state: self.state.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r> RequestState<'r> {
|
||||
fn clone(&self) -> RequestState<'r> {
|
||||
let route = self.route.try_read()
|
||||
.map(|r| r.clone())
|
||||
.unwrap_or(None);
|
||||
|
||||
let cookies = self.cookies.try_lock()
|
||||
.map(|j| j.clone())
|
||||
.unwrap_or_else(|_| Some(CookieJar::new()));
|
||||
|
||||
RequestState {
|
||||
config: self.config,
|
||||
managed: self.managed,
|
||||
path_segments: self.path_segments.clone(),
|
||||
query_items: self.query_items.clone(),
|
||||
route: RwLock::new(route),
|
||||
cookies: Mutex::new(cookies),
|
||||
accept: self.accept.clone(),
|
||||
content_type: self.content_type.clone(),
|
||||
cache: self.cache.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct IndexedFormItem {
|
||||
raw: Indices,
|
||||
|
@ -65,7 +100,7 @@ impl<'r> Request<'r> {
|
|||
uri: Origin<'s>
|
||||
) -> Request<'r> {
|
||||
let mut request = Request {
|
||||
method: RwLock::new(method),
|
||||
method: Atomic::new(method),
|
||||
uri: uri,
|
||||
headers: HeaderMap::new(),
|
||||
remote: None,
|
||||
|
@ -101,7 +136,7 @@ impl<'r> Request<'r> {
|
|||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn method(&self) -> Method {
|
||||
*self.method.read().unwrap()
|
||||
self.method.load(atomic::Ordering::Acquire)
|
||||
}
|
||||
|
||||
/// Set the method of `self`.
|
||||
|
@ -827,7 +862,7 @@ impl<'r> Request<'r> {
|
|||
/// during routing to override methods for re-routing.
|
||||
#[inline(always)]
|
||||
pub(crate) fn _set_method(&self, method: Method) {
|
||||
*self.method.write().unwrap() = method;
|
||||
self.method.store(method, atomic::Ordering::Release)
|
||||
}
|
||||
|
||||
/// Convert from Hyper types into a Rocket Request.
|
||||
|
|
|
@ -68,6 +68,13 @@ impl<A, B> Body<A, B>
|
|||
where A: AsyncRead + AsyncSeek + Send + Unpin,
|
||||
B: AsyncRead + Send + Unpin
|
||||
{
|
||||
pub fn known_size(&self) -> Option<usize> {
|
||||
match self {
|
||||
Body::Sized(_, Some(known)) => Some(*known),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to compute the size of `self` if it is `Body::Sized`. If it is
|
||||
/// not, simply returned `None`. Also returned `None` if determining the
|
||||
/// body's size failed.
|
||||
|
@ -904,8 +911,7 @@ impl<'r> Response<'r> {
|
|||
self.headers.remove(name);
|
||||
}
|
||||
|
||||
/// Returns a mutable borrow of the body of `self`, if there is one. The
|
||||
/// body is borrowed mutably to allow for reading.
|
||||
/// Returns an immutable borrow of the body of `self`, if there is one.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -919,11 +925,34 @@ impl<'r> Response<'r> {
|
|||
///
|
||||
/// let string = "Hello, world!";
|
||||
/// response.set_sized_body(string.len(), Cursor::new(string));
|
||||
/// assert_eq!(response.body_string().await, Some("Hello, world!".to_string()));
|
||||
/// assert!(response.body().is_some());
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn body(&mut self) -> Option<&mut ResponseBody<'r>> {
|
||||
pub fn body(&self) -> Option<&ResponseBody<'r>> {
|
||||
self.body.as_ref()
|
||||
}
|
||||
|
||||
/// Returns a mutable borrow of the body of `self`, if there is one. A
|
||||
/// mutable borrow allows for reading the body.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::io::Cursor;
|
||||
/// use rocket::Response;
|
||||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let mut response = Response::new();
|
||||
/// assert!(response.body().is_none());
|
||||
///
|
||||
/// let string = "Hello, world!";
|
||||
/// response.set_sized_body(string.len(), Cursor::new(string));
|
||||
/// assert!(response.body_mut().is_some());
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn body_mut(&mut self) -> Option<&mut ResponseBody<'r>> {
|
||||
self.body.as_mut()
|
||||
}
|
||||
|
||||
|
@ -1043,7 +1072,7 @@ impl<'r> Response<'r> {
|
|||
///
|
||||
/// let mut response = Response::new();
|
||||
/// response.set_sized_body(string.len(), Cursor::new(string));
|
||||
/// assert_eq!(response.body_string().await, Some("Hello, world!".to_string()));
|
||||
/// assert_eq!(response.body_string().await.unwrap(), "Hello, world!");
|
||||
/// # })
|
||||
/// ```
|
||||
pub fn set_sized_body<B, S>(&mut self, size: S, body: B)
|
||||
|
@ -1067,7 +1096,7 @@ impl<'r> Response<'r> {
|
|||
/// # rocket::async_test(async {
|
||||
/// let mut response = Response::new();
|
||||
/// response.set_streamed_body(repeat(97).take(5));
|
||||
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
||||
/// assert_eq!(response.body_string().await.unwrap(), "aaaaa");
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
|
@ -1087,7 +1116,7 @@ impl<'r> Response<'r> {
|
|||
/// # rocket::async_test(async {
|
||||
/// let mut response = Response::new();
|
||||
/// response.set_chunked_body(repeat(97).take(5), 10);
|
||||
/// assert_eq!(response.body_string().await, Some("aaaaa".to_string()));
|
||||
/// assert_eq!(response.body_string().await.unwrap(), "aaaaa");
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
|
@ -1114,7 +1143,7 @@ impl<'r> Response<'r> {
|
|||
/// let body = Body::Sized(Cursor::new(string), Some(string.len()));
|
||||
/// response.set_raw_body::<Cursor<&'static str>, Cursor<&'static str>>(body);
|
||||
///
|
||||
/// assert_eq!(response.body_string().await, Some("Hello!".to_string()));
|
||||
/// assert_eq!(response.body_string().await.unwrap(), "Hello!");
|
||||
/// # })
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
|
|
|
@ -42,7 +42,7 @@ impl<'r, R> Created<R> {
|
|||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # use rocket::{get, routes, local::Client};
|
||||
/// # use rocket::{get, routes, local::asynchronous::Client};
|
||||
/// use rocket::response::status;
|
||||
///
|
||||
/// #[get("/")]
|
||||
|
@ -53,7 +53,7 @@ impl<'r, R> Created<R> {
|
|||
/// # rocket::async_test(async move {
|
||||
/// # let rocket = rocket::ignite().mount("/", routes![create]);
|
||||
/// # let client = Client::new(rocket).await.unwrap();
|
||||
/// let mut response = client.get("/").dispatch().await;
|
||||
/// let response = client.get("/").dispatch().await;
|
||||
///
|
||||
/// let loc = response.headers().get_one("Location");
|
||||
/// assert_eq!(loc, Some("http://myservice.com/resource.json"));
|
||||
|
@ -73,7 +73,7 @@ impl<'r, R> Created<R> {
|
|||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # use rocket::{get, routes, local::Client};
|
||||
/// # use rocket::{get, routes, local::asynchronous::Client};
|
||||
/// use rocket::response::status;
|
||||
///
|
||||
/// #[get("/")]
|
||||
|
@ -85,16 +85,16 @@ impl<'r, R> Created<R> {
|
|||
/// # rocket::async_test(async move {
|
||||
/// # let rocket = rocket::ignite().mount("/", routes![create]);
|
||||
/// # let client = Client::new(rocket).await.unwrap();
|
||||
/// let mut response = client.get("/").dispatch().await;
|
||||
///
|
||||
/// let body = response.body_string().await;
|
||||
/// assert_eq!(body.unwrap(), "{ 'resource': 'Hello, world!' }");
|
||||
/// let response = client.get("/").dispatch().await;
|
||||
///
|
||||
/// let loc = response.headers().get_one("Location");
|
||||
/// assert_eq!(loc, Some("http://myservice.com/resource.json"));
|
||||
///
|
||||
/// let etag = response.headers().get_one("ETag");
|
||||
/// assert_eq!(etag, None);
|
||||
///
|
||||
/// let body = response.into_string().await;
|
||||
/// assert_eq!(body.unwrap(), "{ 'resource': 'Hello, world!' }");
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn body(mut self, responder: R) -> Self {
|
||||
|
@ -109,7 +109,7 @@ impl<'r, R> Created<R> {
|
|||
///
|
||||
/// ```rust
|
||||
/// # #![feature(proc_macro_hygiene)]
|
||||
/// # use rocket::{get, routes, local::Client};
|
||||
/// # use rocket::{get, routes, local::asynchronous::Client};
|
||||
/// use rocket::response::status;
|
||||
///
|
||||
/// #[get("/")]
|
||||
|
@ -121,16 +121,16 @@ impl<'r, R> Created<R> {
|
|||
/// # rocket::async_test(async move {
|
||||
/// # let rocket = rocket::ignite().mount("/", routes![create]);
|
||||
/// # let client = Client::new(rocket).await.unwrap();
|
||||
/// let mut response = client.get("/").dispatch().await;
|
||||
///
|
||||
/// let body = response.body_string().await;
|
||||
/// assert_eq!(body.unwrap(), "{ 'resource': 'Hello, world!' }");
|
||||
/// let response = client.get("/").dispatch().await;
|
||||
///
|
||||
/// let loc = response.headers().get_one("Location");
|
||||
/// assert_eq!(loc, Some("http://myservice.com/resource.json"));
|
||||
///
|
||||
/// let etag = response.headers().get_one("ETag");
|
||||
/// assert_eq!(etag, Some(r#""13046220615156895040""#));
|
||||
///
|
||||
/// let body = response.into_string().await;
|
||||
/// assert_eq!(body.unwrap(), "{ 'resource': 'Hello, world!' }");
|
||||
/// # });
|
||||
/// ```
|
||||
pub fn tagged_body(mut self, responder: R) -> Self where R: Hash {
|
||||
|
|
|
@ -263,7 +263,7 @@ impl Rocket {
|
|||
})
|
||||
};
|
||||
|
||||
match response.body() {
|
||||
match response.body_mut() {
|
||||
None => {
|
||||
hyp_res = hyp_res.header(header::CONTENT_LENGTH, "0");
|
||||
send_response(hyp_res, hyper::Body::empty())?;
|
||||
|
@ -1112,6 +1112,7 @@ impl Cargo {
|
|||
///
|
||||
/// # rocket::async_test(async {
|
||||
/// let mut rocket = rocket::ignite().manage(MyState("hello!"));
|
||||
///
|
||||
/// let cargo = rocket.inspect().await;
|
||||
/// assert_eq!(cargo.state::<MyState>(), Some(&MyState("hello!")));
|
||||
/// # });
|
||||
|
|
|
@ -16,7 +16,7 @@ fn rocket() -> Redirect {
|
|||
|
||||
mod test_absolute_uris_okay {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn redirect_works() {
|
||||
|
|
|
@ -17,7 +17,7 @@ fn use_default() { }
|
|||
|
||||
mod conditionally_set_server_header {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn do_not_overwrite_server_header() {
|
||||
|
|
|
@ -45,14 +45,14 @@ fn number(params: Form<ThingForm>) -> DerivedResponder {
|
|||
|
||||
#[rocket::async_test]
|
||||
async fn test_derive_reexports() {
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
let rocket = rocket::ignite().mount("/", routes![index, number]);
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "hello");
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "hello");
|
||||
|
||||
let mut response = client.get("/?thing=b").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "b");
|
||||
let response = client.get("/?thing=b").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "b");
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ mod fairing_before_head_strip {
|
|||
|
||||
use rocket::fairing::AdHoc;
|
||||
use rocket::http::Method;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
use rocket::State;
|
||||
|
||||
|
@ -43,7 +43,7 @@ mod fairing_before_head_strip {
|
|||
}));
|
||||
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
let mut response = client.head("/").dispatch().await;
|
||||
let response = client.head("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert!(response.body().is_none());
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ mod fairing_before_head_strip {
|
|||
}));
|
||||
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
let mut response = client.head("/").dispatch().await;
|
||||
let response = client.head("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert!(response.body().is_none());
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ fn used(flash: Option<FlashMessage<'_, '_>>) -> Option<String> {
|
|||
}
|
||||
|
||||
mod flash_lazy_remove_tests {
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -48,8 +48,8 @@ mod flash_lazy_remove_tests {
|
|||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
// Now use it.
|
||||
let mut response = client.get("/use").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some(FLASH_MESSAGE.into()));
|
||||
let response = client.get("/use").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some(FLASH_MESSAGE.into()));
|
||||
|
||||
// Now it should be gone.
|
||||
let response = client.get("/unused").dispatch().await;
|
||||
|
|
|
@ -17,18 +17,18 @@ fn bug(form_data: Form<FormData>) -> &'static str {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn method_eval() {
|
||||
let client = Client::new(rocket::ignite().mount("/", routes![bug])).await.unwrap();
|
||||
let mut response = client.post("/")
|
||||
let response = client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body("_method=patch&form_data=Form+data")
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await, Some("OK".into()));
|
||||
assert_eq!(response.into_string().await, Some("OK".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -16,19 +16,19 @@ fn bug(form_data: Form<FormData>) -> String {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::ContentType;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn check_decoding(raw: &str, decoded: &str) {
|
||||
let client = Client::new(rocket::ignite().mount("/", routes![bug])).await.unwrap();
|
||||
let mut response = client.post("/")
|
||||
let response = client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("form_data={}", raw))
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(Some(decoded.to_string()), response.body_string().await);
|
||||
assert_eq!(Some(decoded.to_string()), response.into_string().await);
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -22,49 +22,39 @@ fn other() -> content::Json<&'static str> {
|
|||
mod head_handling_tests {
|
||||
use super::*;
|
||||
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
use rocket::Route;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
use rocket::response::ResponseBody;
|
||||
|
||||
fn routes() -> Vec<Route> {
|
||||
routes![index, empty, other]
|
||||
}
|
||||
|
||||
async fn assert_empty_sized_body(body: &mut ResponseBody<'_>, expected_size: usize) {
|
||||
let size = body.size().await.expect("sized body");
|
||||
assert_eq!(size, expected_size);
|
||||
|
||||
let mut buffer = vec![];
|
||||
body.as_reader().read_to_end(&mut buffer).await.unwrap();
|
||||
assert_eq!(buffer.len(), 0);
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn auto_head() {
|
||||
let client = Client::new(rocket::ignite().mount("/", routes())).await.unwrap();
|
||||
let mut response = client.head("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_empty_sized_body(response.body().unwrap(), 13).await;
|
||||
let response = client.head("/").dispatch().await;
|
||||
|
||||
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
|
||||
assert_eq!(content_type, vec![ContentType::Plain.to_string()]);
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body().unwrap().known_size(), Some(13));
|
||||
assert!(response.into_bytes().await.unwrap().is_empty());
|
||||
|
||||
let mut response = client.head("/empty").dispatch().await;
|
||||
let response = client.head("/empty").dispatch().await;
|
||||
assert_eq!(response.status(), Status::NoContent);
|
||||
assert!(response.body_bytes().await.is_none());
|
||||
assert!(response.into_bytes().await.is_none());
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn user_head() {
|
||||
let client = Client::new(rocket::ignite().mount("/", routes())).await.unwrap();
|
||||
let mut response = client.head("/other").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_empty_sized_body(response.body().unwrap(), 17).await;
|
||||
let response = client.head("/other").dispatch().await;
|
||||
|
||||
let content_type: Vec<_> = response.headers().get("Content-Type").collect();
|
||||
assert_eq!(content_type, vec![ContentType::JSON.to_string()]);
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body().unwrap().known_size(), Some(17));
|
||||
assert!(response.into_bytes().await.unwrap().is_empty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ fn index(form: Form<Simple>) -> String {
|
|||
mod limits_tests {
|
||||
use rocket;
|
||||
use rocket::config::{Environment, Config, Limits};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn rocket_with_forms_limit(limit: u64) -> rocket::Rocket {
|
||||
|
@ -31,23 +31,23 @@ mod limits_tests {
|
|||
#[rocket::async_test]
|
||||
async fn large_enough() {
|
||||
let client = Client::new(rocket_with_forms_limit(128)).await.unwrap();
|
||||
let mut response = client.post("/")
|
||||
let response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await, Some("Hello world".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello world".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn just_large_enough() {
|
||||
let client = Client::new(rocket_with_forms_limit(17)).await.unwrap();
|
||||
let mut response = client.post("/")
|
||||
let response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await, Some("Hello world".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello world".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -64,11 +64,11 @@ mod limits_tests {
|
|||
#[rocket::async_test]
|
||||
async fn contracted() {
|
||||
let client = Client::new(rocket_with_forms_limit(10)).await.unwrap();
|
||||
let mut response = client.post("/")
|
||||
let response = client.post("/")
|
||||
.body("value=Hello+world")
|
||||
.header(ContentType::Form)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await, Some("Hell".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hell".into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ mod local_request_content_type_tests {
|
|||
use super::*;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::ContentType;
|
||||
|
||||
fn rocket() -> Rocket {
|
||||
|
@ -65,29 +65,29 @@ mod local_request_content_type_tests {
|
|||
async fn has_no_ct() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
let mut req = client.post("/");
|
||||
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Absent".to_string()));
|
||||
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Absent".to_string()));
|
||||
assert_eq!(req.dispatch().await.body_string().await, Some("Absent".to_string()));
|
||||
let req = client.post("/");
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Absent".to_string()));
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Absent".to_string()));
|
||||
assert_eq!(req.dispatch().await.into_string().await, Some("Absent".to_string()));
|
||||
|
||||
let mut req = client.post("/data");
|
||||
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Data Absent".to_string()));
|
||||
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Absent".to_string()));
|
||||
assert_eq!(req.dispatch().await.body_string().await, Some("Data Absent".to_string()));
|
||||
let req = client.post("/data");
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Data Absent".to_string()));
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Data Absent".to_string()));
|
||||
assert_eq!(req.dispatch().await.into_string().await, Some("Data Absent".to_string()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn has_ct() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
let mut req = client.post("/").header(ContentType::JSON);
|
||||
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Present".to_string()));
|
||||
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Present".to_string()));
|
||||
assert_eq!(req.dispatch().await.body_string().await, Some("Present".to_string()));
|
||||
let req = client.post("/").header(ContentType::JSON);
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Present".to_string()));
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Present".to_string()));
|
||||
assert_eq!(req.dispatch().await.into_string().await, Some("Present".to_string()));
|
||||
|
||||
let mut req = client.post("/data").header(ContentType::JSON);
|
||||
// assert_eq!(req.clone().dispatch().await.body_string().await, Some("Data Present".to_string()));
|
||||
assert_eq!(req.mut_dispatch().await.body_string().await, Some("Data Present".to_string()));
|
||||
assert_eq!(req.dispatch().await.body_string().await, Some("Data Present".to_string()));
|
||||
let req = client.post("/data").header(ContentType::JSON);
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Data Present".to_string()));
|
||||
assert_eq!(req.clone().dispatch().await.into_string().await, Some("Data Present".to_string()));
|
||||
assert_eq!(req.dispatch().await.into_string().await, Some("Data Present".to_string()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ mod private_cookie_test {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Cookie;
|
||||
use rocket::http::Status;
|
||||
|
||||
|
@ -28,10 +28,10 @@ mod private_cookie_test {
|
|||
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
let req = client.get("/").private_cookie(Cookie::new("cookie_name", "cookie_value"));
|
||||
let mut response = req.dispatch().await;
|
||||
let response = req.dispatch().await;
|
||||
|
||||
assert_eq!(response.body_string().await, Some("cookie_value".into()));
|
||||
assert_eq!(response.headers().get_one("Set-Cookie"), None);
|
||||
assert_eq!(response.into_string().await, Some("cookie_value".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -44,20 +44,20 @@ fn rocket() -> rocket::Rocket {
|
|||
|
||||
mod nested_fairing_attaches_tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_counts() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("1, 1".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("1, 1".into()));
|
||||
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("1, 2".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("1, 2".into()));
|
||||
|
||||
client.get("/").dispatch().await;
|
||||
client.get("/").dispatch().await;
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("1, 5".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("1, 5".into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
use rocket::Rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn rocket() -> Rocket {
|
||||
|
@ -44,12 +44,13 @@ mod tests {
|
|||
req.add_header(ct);
|
||||
}
|
||||
|
||||
let mut response = req.dispatch().await;
|
||||
let body_str = response.body_string().await;
|
||||
let response = req.dispatch().await;
|
||||
let status = response.status();
|
||||
let body_str = response.into_string().await;
|
||||
let body: Option<&'static str> = $body;
|
||||
match body {
|
||||
Some(string) => assert_eq!(body_str, Some(string.to_string())),
|
||||
None => assert_eq!(response.status(), Status::NotFound)
|
||||
None => assert_eq!(status, Status::NotFound)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ fn not_found() -> Redirect {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -13,11 +13,11 @@ fn files(route: &Route, path: PathBuf) -> String {
|
|||
|
||||
mod route_guard_tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
async fn assert_path(client: &Client, path: &str) {
|
||||
let mut res = client.get(path).dispatch().await;
|
||||
assert_eq!(res.body_string().await, Some(path.into()));
|
||||
let res = client.get(path).dispatch().await;
|
||||
assert_eq!(res.into_string().await, Some(path.into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -31,7 +31,7 @@ fn dual(user: String, path: Segments<'_>) -> String {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn segments_works() {
|
||||
|
@ -47,8 +47,8 @@ mod tests {
|
|||
"/static", "/point/static"]
|
||||
{
|
||||
let path = "this/is/the/path/we/want";
|
||||
let mut response = client.get(format!("{}/{}", prefix, path)).dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some(path.into()));
|
||||
let response = client.get(format!("{}/{}", prefix, path)).dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some(path.into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ fn lenient<'r>(form: LenientForm<MyForm<'r>>) -> String {
|
|||
|
||||
mod strict_and_lenient_forms_tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
const FIELD_VALUE: &str = "just_some_value";
|
||||
|
@ -34,13 +34,13 @@ mod strict_and_lenient_forms_tests {
|
|||
#[rocket::async_test]
|
||||
async fn test_strict_form() {
|
||||
let client = client().await;
|
||||
let mut response = client.post("/strict")
|
||||
let response = client.post("/strict")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("field={}", FIELD_VALUE))
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
|
||||
assert_eq!(response.into_string().await, Some(FIELD_VALUE.into()));
|
||||
|
||||
let response = client.post("/strict")
|
||||
.header(ContentType::Form)
|
||||
|
@ -53,20 +53,20 @@ mod strict_and_lenient_forms_tests {
|
|||
#[rocket::async_test]
|
||||
async fn test_lenient_form() {
|
||||
let client = client().await;
|
||||
let mut response = client.post("/lenient")
|
||||
let response = client.post("/lenient")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("field={}", FIELD_VALUE))
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
|
||||
assert_eq!(response.into_string().await, Some(FIELD_VALUE.into()));
|
||||
|
||||
let mut response = client.post("/lenient")
|
||||
let response = client.post("/lenient")
|
||||
.header(ContentType::Form)
|
||||
.body(format!("field={}&extra=whoops", FIELD_VALUE))
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(FIELD_VALUE.into()));
|
||||
assert_eq!(response.into_string().await, Some(FIELD_VALUE.into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ fn rocket() -> rocket::Rocket {
|
|||
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, uri::Uri};
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -52,8 +52,8 @@ mod tests {
|
|||
async fn uri_percent_encoding_get() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let name = Uri::percent_encode(NAME);
|
||||
let mut response = client.get(format!("/hello/{}", name)).dispatch().await;
|
||||
let response = client.get(format!("/hello/{}", name)).dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await.unwrap(), format!("Hello, {}!", NAME));
|
||||
assert_eq!(response.into_string().await.unwrap(), format!("Hello, {}!", NAME));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use rocket::{self, State};
|
|||
use rocket::fairing::AdHoc;
|
||||
use rocket::config::{self, Config, Environment, LoggingLevel};
|
||||
use rocket::http::Status;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
struct LocalConfig(Config);
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use super::Person;
|
||||
use rocket::http::{Accept, ContentType, Header, MediaType, Method, Status};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
async fn test<H>(method: Method, uri: &str, header: H, status: Status, body: String)
|
||||
where H: Into<Header<'static>>
|
||||
{
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.req(method, uri).header(header).dispatch().await;
|
||||
let response = client.req(method, uri).header(header).dispatch().await;
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string().await, Some(body));
|
||||
assert_eq!(response.into_string().await, Some(body));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::*;
|
||||
use rocket_contrib::templates::Template;
|
||||
|
||||
|
@ -24,13 +24,13 @@ async fn test_submit() {
|
|||
async fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: String) {
|
||||
// Attach a cookie if one is given.
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = match optional_cookie {
|
||||
let response = match optional_cookie {
|
||||
Some(cookie) => client.get("/").cookie(cookie).dispatch().await,
|
||||
None => client.get("/").dispatch().await,
|
||||
};
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(expected_body));
|
||||
assert_eq!(response.into_string().await, Some(expected_body));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn test(uri: &str, status: Status, body: String) {
|
||||
|
@ -7,9 +7,9 @@ async fn test(uri: &str, status: Status, body: String) {
|
|||
.register(catchers![super::not_found]);
|
||||
|
||||
let client = Client::new(rocket).await.unwrap();
|
||||
let mut response = client.get(uri).dispatch().await;
|
||||
let response = client.get(uri).dispatch().await;
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string().await, Some(body));
|
||||
assert_eq!(response.into_string().await, Some(body));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn rewrite_get_put() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Hello, fairings!".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Hello, fairings!".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -16,16 +16,16 @@ async fn counts() {
|
|||
client.get("/").dispatch().await;
|
||||
|
||||
// Check the GET count, taking into account _this_ GET request.
|
||||
let mut response = client.get("/counts").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Get: 2\nPost: 0".into()));
|
||||
let response = client.get("/counts").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Get: 2\nPost: 0".into()));
|
||||
|
||||
// Issue 1 more GET request and a POST.
|
||||
client.get("/").dispatch().await;
|
||||
client.post("/").dispatch().await;
|
||||
|
||||
// Check the counts.
|
||||
let mut response = client.get("/counts").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Get: 4\nPost: 1".into()));
|
||||
let response = client.get("/counts").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Get: 4\nPost: 1".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -33,6 +33,6 @@ async fn token() {
|
|||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
// Ensure the token is '123', which is what we have in `Rocket.toml`.
|
||||
let mut res = client.get("/token").dispatch().await;
|
||||
assert_eq!(res.body_string().await, Some("123".into()));
|
||||
let res = client.get("/token").dispatch().await;
|
||||
assert_eq!(res.into_string().await, Some("123".into()));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fmt;
|
||||
use super::{rocket, FormInput, FormOption};
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::blocking::Client;
|
||||
use rocket::http::ContentType;
|
||||
|
||||
impl fmt::Display for FormOption {
|
||||
|
@ -16,12 +16,12 @@ impl fmt::Display for FormOption {
|
|||
|
||||
macro_rules! assert_form_eq {
|
||||
($client:expr, $form_str:expr, $expected:expr) => {{
|
||||
let mut res = $client.post("/")
|
||||
let res = $client.post("/")
|
||||
.header(ContentType::Form)
|
||||
.body($form_str)
|
||||
.dispatch().await;
|
||||
.dispatch();
|
||||
|
||||
assert_eq!(res.body_string().await, Some($expected));
|
||||
assert_eq!(res.into_string(), Some($expected));
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -40,9 +40,9 @@ macro_rules! assert_valid_raw_form {
|
|||
}};
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_good_forms() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
#[test]
|
||||
fn test_good_forms() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut input = FormInput {
|
||||
checkbox: true,
|
||||
number: 310,
|
||||
|
@ -119,9 +119,9 @@ macro_rules! assert_invalid_raw_form {
|
|||
}};
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn check_semantically_invalid_forms() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
#[test]
|
||||
fn check_semantically_invalid_forms() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
|
||||
|
||||
form_vals[0] = "not true";
|
||||
|
@ -175,17 +175,17 @@ async fn check_semantically_invalid_forms() {
|
|||
assert_invalid_raw_form!(&client, "");
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn check_structurally_invalid_forms() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
#[test]
|
||||
fn check_structurally_invalid_forms() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
assert_invalid_raw_form!(&client, "==&&&&&&==");
|
||||
assert_invalid_raw_form!(&client, "a&=b");
|
||||
assert_invalid_raw_form!(&client, "=");
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn check_bad_utf8() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
#[test]
|
||||
fn check_bad_utf8() {
|
||||
let client = Client::new(rocket()).unwrap();
|
||||
unsafe {
|
||||
let bad_str = std::str::from_utf8_unchecked(b"a=\xff");
|
||||
assert_form_eq!(&client, bad_str, "Form input was invalid UTF-8.".into());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
fn test_login<T>(user: &str, pass: &str, age: &str, status: Status, body: T)
|
||||
|
@ -8,14 +8,14 @@ fn test_login<T>(user: &str, pass: &str, age: &str, status: Status, body: T)
|
|||
rocket::async_test(async move {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let query = format!("username={}&password={}&age={}", user, pass, age);
|
||||
let mut response = client.post("/login")
|
||||
let response = client.post("/login")
|
||||
.header(ContentType::Form)
|
||||
.body(&query)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(response.status(), status);
|
||||
if let Some(expected_str) = body.into() {
|
||||
let body_str = response.body_string().await;
|
||||
let body_str = response.into_string().await;
|
||||
assert!(body_str.map_or(false, |s| s.contains(expected_str)));
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{rocket, TemplateContext};
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::http::Status;
|
||||
use rocket_contrib::templates::Template;
|
||||
|
@ -8,7 +8,7 @@ use rocket_contrib::templates::Template;
|
|||
macro_rules! dispatch {
|
||||
($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({
|
||||
let $client = Client::new(rocket()).await.unwrap();
|
||||
let mut $response = $client.req($method, $path).dispatch().await;
|
||||
let $response = $client.req($method, $path).dispatch().await;
|
||||
$body
|
||||
})
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ async fn test_root() {
|
|||
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
|
||||
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ async fn test_name() {
|
|||
|
||||
let expected = Template::show(client.cargo(), "index", &context).unwrap();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,6 @@ async fn test_404() {
|
|||
|
||||
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use rocket::{self, local::Client};
|
||||
use rocket::{self, local::asynchronous::Client};
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn hello_world() {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Hello, Rust 2018!".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Hello, Rust 2018!".into()));
|
||||
}
|
||||
|
||||
// Tests unrelated to the example.
|
||||
|
@ -31,19 +31,19 @@ mod scoped_uri_tests {
|
|||
.mount("/", rocket::routes![inner::hello])
|
||||
}
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_inner_hello() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Hello! Try /Rust%202018.".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Hello! Try /Rust%202018.".into()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_hello_name() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/Rust%202018").dispatch().await;
|
||||
assert_eq!(response.body_string().await.unwrap(), "Hello, Rust 2018! This is /Rust%202018.");
|
||||
let response = client.get("/Rust%202018").dispatch().await;
|
||||
assert_eq!(response.into_string().await.unwrap(), "Hello, Rust 2018! This is /Rust%202018.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn test(uri: String, expected: String) {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
assert_eq!(client.get(&uri).dispatch().await.body_string().await, Some(expected));
|
||||
assert_eq!(client.get(&uri).dispatch().await.into_string().await, Some(expected));
|
||||
}
|
||||
|
||||
async fn test_404(uri: &'static str) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn hello_world() {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -7,18 +7,17 @@ async fn bad_get_put() {
|
|||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
// 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 res = client.get("/message/99").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
|
||||
let body = res.body_string().await.unwrap();
|
||||
let body = res.into_string().await.unwrap();
|
||||
assert!(body.contains("error"));
|
||||
assert!(body.contains("Resource was not found."));
|
||||
|
||||
// Try to get a message with an invalid ID.
|
||||
let mut res = client.get("/message/hi").header(ContentType::JSON).dispatch().await;
|
||||
let body = res.body_string().await.unwrap();
|
||||
let res = client.get("/message/hi").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(res.status(), Status::NotFound);
|
||||
assert!(body.contains("error"));
|
||||
assert!(res.into_string().await.unwrap().contains("error"));
|
||||
|
||||
// Try to put a message without a proper body.
|
||||
let res = client.put("/message/80").header(ContentType::JSON).dispatch().await;
|
||||
|
@ -50,9 +49,9 @@ async fn post_get_put_get() {
|
|||
assert_eq!(res.status(), Status::Ok);
|
||||
|
||||
// Check that the message exists with the correct contents.
|
||||
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
|
||||
let res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
let body = res.body_string().await.unwrap();
|
||||
let body = res.into_string().await.unwrap();
|
||||
assert!(body.contains("Hello, world!"));
|
||||
|
||||
// Change the message contents.
|
||||
|
@ -64,9 +63,9 @@ async fn post_get_put_get() {
|
|||
assert_eq!(res.status(), Status::Ok);
|
||||
|
||||
// Check that the message exists with the updated contents.
|
||||
let mut res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
|
||||
let res = client.get("/message/1").header(ContentType::JSON).dispatch().await;
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
let body = res.body_string().await.unwrap();
|
||||
let body = res.into_string().await.unwrap();
|
||||
assert!(!body.contains("Hello, world!"));
|
||||
assert!(body.contains("Bye bye, world!"));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -8,6 +8,6 @@ async fn test_push_pop() {
|
|||
let response = client.put("/push?event=test1").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
let mut response = client.get("/pop").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("test1".to_string()));
|
||||
let response = client.get("/pop").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("test1".to_string()));
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use super::*;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
fn test(uri: &str, content_type: ContentType, status: Status, body: String) {
|
||||
rocket::async_test(async move {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get(uri).header(content_type).dispatch().await;
|
||||
let response = client.get(uri).header(content_type).dispatch().await;
|
||||
assert_eq!(response.status(), status);
|
||||
assert_eq!(response.body_string().await, Some(body));
|
||||
assert_eq!(response.into_string().await, Some(body));
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -46,9 +46,9 @@ async fn test_upload() {
|
|||
assert_eq!(response.status(), Status::Ok);
|
||||
|
||||
// Ensure we get back the same body.
|
||||
let mut response = client.get("/upload").dispatch().await;
|
||||
let response = client.get("/upload").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(expected_body));
|
||||
assert_eq!(response.into_string().await, Some(expected_body));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -11,12 +11,12 @@ struct Message {
|
|||
#[rocket::async_test]
|
||||
async fn msgpack_get() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut res = client.get("/message/1").header(ContentType::MsgPack).dispatch().await;
|
||||
let res = client.get("/message/1").header(ContentType::MsgPack).dispatch().await;
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
assert_eq!(res.content_type(), Some(ContentType::MsgPack));
|
||||
|
||||
// Check that the message is `[1, "Hello, world!"]`
|
||||
assert_eq!(&res.body_bytes().await.unwrap(),
|
||||
assert_eq!(&res.into_bytes().await.unwrap(),
|
||||
&[146, 1, 173, 72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]);
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,11 @@ async fn msgpack_get() {
|
|||
async fn msgpack_post() {
|
||||
// Dispatch request with a message of `[2, "Goodbye, world!"]`.
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut res = client.post("/message")
|
||||
let res = client.post("/message")
|
||||
.header(ContentType::MsgPack)
|
||||
.body(&[146, 2, 175, 71, 111, 111, 100, 98, 121, 101, 44, 32, 119, 111, 114, 108, 100, 33])
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
assert_eq!(res.body_string().await, Some("Goodbye, world!".into()));
|
||||
assert_eq!(res.into_string().await, Some("Goodbye, world!".into()));
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn test_200(uri: &str, expected_body: &str) {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.get(uri).dispatch().await;
|
||||
let response = client.get(uri).dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(expected_body.to_string()));
|
||||
assert_eq!(response.into_string().await, Some(expected_body.to_string()));
|
||||
}
|
||||
|
||||
async fn test_303(uri: &str, expected_location: &str) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{rocket, index};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
fn extract_id(from: &str) -> Option<String> {
|
||||
|
@ -11,23 +11,23 @@ async fn check_index() {
|
|||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
// Ensure the index returns what we expect.
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
assert_eq!(response.body_string().await, Some(index().into()))
|
||||
assert_eq!(response.into_string().await, Some(index().into()))
|
||||
}
|
||||
|
||||
async fn upload_paste(client: &Client, body: &str) -> String {
|
||||
let mut response = client.post("/").body(body).dispatch().await;
|
||||
let response = client.post("/").body(body).dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
extract_id(&response.body_string().await.unwrap()).unwrap()
|
||||
extract_id(&response.into_string().await.unwrap()).unwrap()
|
||||
}
|
||||
|
||||
async fn download_paste(client: &Client, id: &str) -> String {
|
||||
let mut response = client.get(format!("/{}", id)).dispatch().await;
|
||||
let response = client.get(format!("/{}", id)).dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
response.body_string().await.unwrap()
|
||||
response.into_string().await.unwrap()
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
macro_rules! run_test {
|
||||
|
@ -14,12 +14,12 @@ macro_rules! run_test {
|
|||
#[rocket::async_test]
|
||||
async fn age_and_name_params() {
|
||||
run_test!("?age=10&first-name=john", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("Hello, 10 year old named john!".into()));
|
||||
});
|
||||
|
||||
run_test!("?age=20&first-name=john", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("20 years old? Hi, john!".into()));
|
||||
});
|
||||
}
|
||||
|
@ -27,12 +27,12 @@ async fn age_and_name_params() {
|
|||
#[rocket::async_test]
|
||||
async fn age_param_only() {
|
||||
run_test!("?age=10", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("We're gonna need a name, and only a name.".into()));
|
||||
});
|
||||
|
||||
run_test!("?age=20", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("We're gonna need a name, and only a name.".into()));
|
||||
});
|
||||
}
|
||||
|
@ -40,19 +40,19 @@ async fn age_param_only() {
|
|||
#[rocket::async_test]
|
||||
async fn name_param_only() {
|
||||
run_test!("?first-name=John", |response| {
|
||||
assert_eq!(response.body_string().await, Some("Hello John!".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello John!".into()));
|
||||
});
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn no_params() {
|
||||
run_test!("", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("We're gonna need a name, and only a name.".into()));
|
||||
});
|
||||
|
||||
run_test!("?", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("We're gonna need a name, and only a name.".into()));
|
||||
});
|
||||
}
|
||||
|
@ -60,12 +60,12 @@ async fn no_params() {
|
|||
#[rocket::async_test]
|
||||
async fn extra_params() {
|
||||
run_test!("?age=20&first-name=Bob&extra", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("20 years old? Hi, Bob!".into()));
|
||||
});
|
||||
|
||||
run_test!("?age=30&first-name=Bob&extra", |response| {
|
||||
assert_eq!(response.body_string().await,
|
||||
assert_eq!(response.into_string().await,
|
||||
Some("We're gonna need a name, and only a name.".into()));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
async fn test(uri: String, expected: String) {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.get(&uri).dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
let response = client.get(&uri).dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn hello() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Rocketeer".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Rocketeer".into()));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
use std::env;
|
||||
|
@ -10,8 +10,8 @@ const UPLOAD_CONTENTS: &str = "Hey! I'm going to be uploaded. :D Yay!";
|
|||
#[rocket::async_test]
|
||||
async fn test_index() {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut res = client.get("/").dispatch().await;
|
||||
assert_eq!(res.body_string().await, Some(super::index().to_string()));
|
||||
let res = client.get("/").dispatch().await;
|
||||
assert_eq!(res.into_string().await, Some(super::index().to_string()));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
@ -22,13 +22,13 @@ async fn test_raw_upload() {
|
|||
|
||||
// Do the upload. Make sure we get the expected results.
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut res = client.post("/upload")
|
||||
let res = client.post("/upload")
|
||||
.header(ContentType::Plain)
|
||||
.body(UPLOAD_CONTENTS)
|
||||
.dispatch().await;
|
||||
|
||||
assert_eq!(res.status(), Status::Ok);
|
||||
assert_eq!(res.body_string().await, Some(UPLOAD_CONTENTS.len().to_string()));
|
||||
assert_eq!(res.into_string().await, Some(UPLOAD_CONTENTS.len().to_string()));
|
||||
|
||||
// Ensure we find the body in the /tmp/upload.txt file.
|
||||
let mut file_contents = String::new();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn client() -> Client {
|
||||
|
@ -9,7 +9,7 @@ async fn client() -> Client {
|
|||
#[rocket::async_test]
|
||||
async fn test_root() {
|
||||
let client = client().await;
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
let response = client.get("/").dispatch().await;
|
||||
|
||||
assert!(response.body().is_none());
|
||||
assert_eq!(response.status(), Status::SeeOther);
|
||||
|
@ -25,6 +25,6 @@ async fn test_root() {
|
|||
#[rocket::async_test]
|
||||
async fn test_login() {
|
||||
let client = client().await;
|
||||
let mut r = client.get("/login").dispatch().await;
|
||||
assert_eq!(r.body_string().await, Some("Hi! Please log in before continuing.".into()));
|
||||
let r = client.get("/login").dispatch().await;
|
||||
assert_eq!(r.into_string().await, Some("Hi! Please log in before continuing.".into()));
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ fn rocket() -> rocket::Rocket {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Header;
|
||||
|
||||
async fn test_header_count<'h>(headers: Vec<Header<'static>>) {
|
||||
|
@ -39,9 +39,9 @@ mod test {
|
|||
req.add_header(header);
|
||||
}
|
||||
|
||||
let mut response = req.dispatch().await;
|
||||
let response = req.dispatch().await;
|
||||
let expect = format!("Your request contained {} headers!", headers.len());
|
||||
assert_eq!(response.body_string().await, Some(expect));
|
||||
assert_eq!(response.into_string().await, Some(expect));
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::atomic::Ordering;
|
||||
|
||||
use super::{rocket, Atomics};
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::rocket;
|
||||
use rocket::Response;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, Cookie, ContentType};
|
||||
|
||||
fn user_id_cookie(response: &Response<'_>) -> Option<Cookie<'static>> {
|
||||
|
@ -34,9 +34,9 @@ async fn redirect_on_index() {
|
|||
async fn can_login() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
|
||||
let mut response = client.get("/login").dispatch().await;
|
||||
let body = response.body_string().await.unwrap();
|
||||
let response = client.get("/login").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.into_string().await.unwrap();
|
||||
assert!(body.contains("Please login to continue."));
|
||||
}
|
||||
|
||||
|
@ -53,9 +53,9 @@ async fn login_logout_succeeds() {
|
|||
let login_cookie = login(&client, "Sergio", "password").await.expect("logged in");
|
||||
|
||||
// Ensure we're logged in.
|
||||
let mut response = client.get("/").cookie(login_cookie.clone()).dispatch().await;
|
||||
let body = response.body_string().await.unwrap();
|
||||
let response = client.get("/").cookie(login_cookie.clone()).dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.into_string().await.unwrap();
|
||||
assert!(body.contains("Logged in with user ID 1"));
|
||||
|
||||
// One more.
|
||||
|
@ -73,9 +73,9 @@ async fn login_logout_succeeds() {
|
|||
assert_eq!(response.headers().get_one("Location"), Some("/login"));
|
||||
|
||||
// The page should show the success message, and no errors.
|
||||
let mut response = client.get("/login").dispatch().await;
|
||||
let body = response.body_string().await.unwrap();
|
||||
let response = client.get("/login").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.into_string().await.unwrap();
|
||||
assert!(body.contains("Successfully logged out."));
|
||||
assert!(!body.contains("Error"));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn register_hit(client: &Client) {
|
||||
|
@ -7,8 +7,8 @@ async fn register_hit(client: &Client) {
|
|||
}
|
||||
|
||||
async fn get_count(client: &Client) -> usize {
|
||||
let mut response = client.get("/count").dispatch().await;
|
||||
response.body_string().await.and_then(|s| s.parse().ok()).unwrap()
|
||||
let response = client.get("/count").dispatch().await;
|
||||
response.into_string().await.and_then(|s| s.parse().ok()).unwrap()
|
||||
}
|
||||
|
||||
#[rocket::async_test]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
use super::rocket;
|
||||
|
@ -10,10 +10,10 @@ async fn test_query_file<T> (path: &str, file: T, status: Status)
|
|||
where T: Into<Option<&'static str>>
|
||||
{
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get(path).dispatch().await;
|
||||
let response = client.get(path).dispatch().await;
|
||||
assert_eq!(response.status(), status);
|
||||
|
||||
let body_data = response.body_bytes().await;
|
||||
let body_data = response.into_bytes().await;
|
||||
if let Some(filename) = file.into() {
|
||||
let expected_data = read_file_content(filename);
|
||||
assert!(body_data.map_or(false, |s| s == expected_data));
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_root() {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut res = client.get("/").dispatch().await;
|
||||
let res = client.get("/").dispatch().await;
|
||||
|
||||
// Check that we have exactly 25,000 'a'.
|
||||
let res_str = res.body_string().await.unwrap();
|
||||
let res_str = res.into_string().await.unwrap();
|
||||
assert_eq!(res_str.len(), 25000);
|
||||
for byte in res_str.as_bytes() {
|
||||
assert_eq!(*byte, b'a');
|
||||
|
@ -25,8 +25,8 @@ async fn test_file() {
|
|||
|
||||
// Get the big file contents, hopefully.
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut res = client.get("/big_file").dispatch().await;
|
||||
assert_eq!(res.body_string().await, Some(CONTENTS.into()));
|
||||
let res = client.get("/big_file").dispatch().await;
|
||||
assert_eq!(res.into_string().await, Some(CONTENTS.into()));
|
||||
|
||||
// Delete the 'big_file'.
|
||||
fs::remove_file(super::FILENAME).expect("remove big_file");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Method::*;
|
||||
use rocket::http::Status;
|
||||
use rocket_contrib::templates::Template;
|
||||
|
@ -7,7 +7,7 @@ use rocket_contrib::templates::Template;
|
|||
macro_rules! dispatch {
|
||||
($method:expr, $path:expr, |$client:ident, $response:ident| $body:expr) => ({
|
||||
let $client = Client::new(rocket()).await.unwrap();
|
||||
let mut $response = $client.req($method, $path).dispatch().await;
|
||||
let $response = $client.req($method, $path).dispatch().await;
|
||||
$body
|
||||
})
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ async fn test_root() {
|
|||
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
|
||||
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ async fn test_name() {
|
|||
|
||||
let expected = Template::show(client.cargo(), "index", &context).unwrap();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,6 @@ async fn test_404() {
|
|||
|
||||
let expected = Template::show(client.cargo(), "error/404", &map).unwrap();
|
||||
assert_eq!(response.status(), Status::NotFound);
|
||||
assert_eq!(response.body_string().await, Some(expected));
|
||||
assert_eq!(response.into_string().await, Some(expected));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,14 +15,14 @@ fn rocket() -> rocket::Rocket {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn test_hello() {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn hello_world() {
|
||||
let client = Client::new(super::rocket()).await.unwrap();
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
let response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::task::Task;
|
|||
use parking_lot::Mutex;
|
||||
use rand::{Rng, thread_rng, distributions::Alphanumeric};
|
||||
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::{Status, ContentType};
|
||||
|
||||
// We use a lock to synchronize between tests so DB operations don't collide.
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
async fn test(uri: &str, expected: &str) {
|
||||
let client = Client::new(rocket()).await.unwrap();
|
||||
let mut res = client.get(uri).dispatch().await;
|
||||
assert_eq!(res.body_string().await, Some(expected.into()));
|
||||
let res = client.get(uri).dispatch().await;
|
||||
assert_eq!(res.into_string().await, Some(expected.into()));
|
||||
}
|
||||
|
||||
async fn test_404(uri: &str) {
|
||||
|
|
|
@ -148,7 +148,7 @@ First, we'll create a `test` module with the proper imports:
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
#[test]
|
||||
|
@ -217,7 +217,7 @@ use rocket::http::{ContentType, Status};
|
|||
# let mut response = client.get("/").dispatch();
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
```
|
||||
|
||||
That's it! Altogether, this looks like:
|
||||
|
@ -240,7 +240,7 @@ fn rocket() -> rocket::Rocket {
|
|||
# */
|
||||
mod test {
|
||||
use super::rocket;
|
||||
use rocket::local::Client;
|
||||
use rocket::local::asynchronous::Client;
|
||||
use rocket::http::Status;
|
||||
|
||||
# /*
|
||||
|
@ -250,7 +250,7 @@ mod test {
|
|||
let client = Client::new(rocket()).expect("valid rocket instance");
|
||||
let mut response = client.get("/").dispatch().await;
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.body_string().await, Some("Hello, world!".into()));
|
||||
assert_eq!(response.into_string().await, Some("Hello, world!".into()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue