rocket/local/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
//! 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.
//!
//! # Async. vs. Blocking
//!
//! This module contains two variants, in its two submodules, of the same local
//! API: [`asynchronous`], and [`blocking`]. As their names imply, the
//! `asynchronous` API is `async`, returning a `Future` for operations that
//! would otherwise block, while `blocking` blocks for the same operations.
//!
//! Unless your request handling requires concurrency to make progress, or
//! you're making use of a `Client` in an environment that necessitates or would
//! benefit from concurrency, you should use the `blocking` set of APIs due
//! their ease-of-use. If your request handling _does_ require concurrency to
//! make progress, for instance by having one handler `await` a response
//! generated from a request to another handler, use the `asynchronous` set of
//! APIs.
//!
//! Both APIs include a `Client` structure that is used to create `LocalRequest`
//! structures that can be dispatched against a given [`Rocket`](crate::Rocket)
//! instance to yield a `LocalResponse` structure. The APIs are identical except
//! in that the `asynchronous` APIs return `Future`s for otherwise blocking
//! operations.
//!
//! # Unit/Integration Testing
//!
//! This module is primarily intended to be used to test a Rocket application by
//! constructing requests via `Client`, dispatching them, and validating the
//! resulting response. As a complete example, consider the following "Hello,
//! world!" application, with testing.
//!
//! ```rust
//! #[macro_use] extern crate rocket;
//!
//! #[get("/")]
//! fn hello() -> &'static str {
//! "Hello, world!"
//! }
//!
//! #[launch]
//! fn rocket() -> _ {
//! rocket::build().mount("/", routes![hello])
//! }
//!
//! #[cfg(test)]
//! mod test {
//! // Using the preferred `blocking` API.
//! #[test]
//! fn test_hello_world_blocking() {
//! use rocket::local::blocking::Client;
//!
//! // Construct a client to use for dispatching requests.
//! let client = Client::tracked(super::rocket())
//! .expect("valid `Rocket`");
//!
//! // Dispatch a request to 'GET /' and validate the response.
//! let response = client.get("/").dispatch();
//! assert_eq!(response.into_string().unwrap(), "Hello, world!");
//! }
//!
//! // Using the `asynchronous` API.
//! #[rocket::async_test]
//! async fn test_hello_world_async() {
//! use rocket::local::asynchronous::Client;
//!
//! // Construct a client to use for dispatching requests.
//! let client = Client::tracked(super::rocket()).await
//! .expect("valid `Rocket`");
//!
//! // Dispatch a request to 'GET /' and validate the response.
//! let response = client.get("/").dispatch().await;
//! assert_eq!(response.into_string().await.unwrap(), "Hello, world!");
//! }
//! }
//! ```
//!
//! For more details on testing, see the [testing guide].
//!
//! [testing guide]: https://rocket.rs/v0.5/guide/testing/
//! [`Client`]: crate::local::asynchronous::Client
//!
//! # `Client`
//!
//! A `Client`, either [`blocking::Client`] or [`asynchronous::Client`],
//! referred to as simply [`Client`] and [`async` `Client`], respectively,
//! constructs requests for local dispatching.
//!
//! **Usage**
//!
//! A `Client` is constructed via the [`tracked()`] ([`async` `tracked()`]) or
//! [`untracked()`] ([`async` `untracked()`]) methods from an already
//! constructed `Rocket` instance. Once a value of `Client` has been
//! constructed, [`get()`], [`put()`], [`post()`], and so on ([`async` `get()`],
//! [`async` `put()`], [`async` `post()`]) can be called to create a
//! [`LocalRequest`] ([`async` `LocalRequest`]) for dispatching.
//!
//! **Cookie Tracking**
//!
//! A `Client` constructed using `tracked()` 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()` constructor to create a `Client` that _will not_ track
//! cookies.
//!
//! [`Client`]: blocking::Client
//! [`async` `Client`]: asynchronous::Client
//! [`LocalRequest`]: blocking::LocalRequest
//! [`async` `LocalRequest`]: asynchronous::LocalRequest
//!
//! [`tracked()`]: blocking::Client::tracked()
//! [`untracked()`]: blocking::Client::untracked()
//! [`async` `tracked()`]: asynchronous::Client::tracked()
//! [`async` `untracked()`]: asynchronous::Client::untracked()
//!
//! [`get()`]: blocking::Client::get()
//! [`put()`]: blocking::Client::put()
//! [`post()`]: blocking::Client::post()
//! [`async` `get()`]: asynchronous::Client::get()
//! [`async` `put()`]: asynchronous::Client::put()
//! [`async` `post()`]: asynchronous::Client::post()
//!
//! **Example**
//!
//! For a usage example, see [`Client`] or [`async` `Client`].
//!
//! # `LocalRequest`
//!
//! A [`LocalRequest`] ([`async` `LocalRequest`]) is constructed via a `Client`.
//! Once obtained, headers, cookies, including private cookies, the remote IP
//! address, and the request body can all be set via methods on the
//! `LocalRequest` structure.
//!
//! **Dispatching**
//!
//! A `LocalRequest` is dispatched by calling [`dispatch()`] ([`async`
//! `dispatch()`]). The `LocalRequest` is consumed and a [`LocalResponse`]
//! ([`async` `LocalResponse`]) is returned.
//!
//! 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()`.
//!
//! **Example**
//!
//! For a usage example, see [`LocalRequest`] or [`async` `LocalRequest`].
//!
//! [`LocalResponse`]: blocking::LocalResponse
//! [`async` `LocalResponse`]: asynchronous::LocalResponse
//! [`dispatch()`]: blocking::LocalRequest::dispatch()
//! [`async` `dispatch()`]: asynchronous::LocalRequest::dispatch()
//!
//! # `LocalResponse`
//!
//! The result of `dispatch()`ing a `LocalRequest` is a [`LocalResponse`]
//! ([`async` `LocalResponse`]). A `LocalResponse` can be queried for response
//! metadata, including the HTTP status, headers, and cookies, via its getter
//! methods. Additionally, the body of the response can be read into a string
//! ([`into_string()`] or [`async` `into_string()`]) or a vector
//! ([`into_bytes()`] or [`async` `into_bytes()`]).
//!
//! The response body must also be read directly using standard I/O mechanisms:
//! the `blocking` `LocalResponse` implements `Read` while the `async`
//! `LocalResponse` implements `AsyncRead`.
//!
//! For a usage example, see [`LocalResponse`] or [`async` `LocalResponse`].
//!
//! [`into_string()`]: blocking::LocalResponse::into_string()
//! [`async` `into_string()`]: asynchronous::LocalResponse::into_string()
//! [`into_bytes()`]: blocking::LocalResponse::into_bytes()
//! [`async` `into_bytes()`]: asynchronous::LocalResponse::into_bytes()
#[macro_use] mod client;
#[macro_use] mod request;
#[macro_use] mod response;
pub mod asynchronous;
pub mod blocking;