Expand description
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
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.
#[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.
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.
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
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
.
Modules
- Asynchronous local dispatching of requests.
- Blocking local dispatching of requests.