rocket/local/
mod.rs

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