Module rocket::local

source ·
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 Futures 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.