2017-04-17 02:48:59 +00:00
|
|
|
# Testing
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
Every application should be well tested and understandable. Rocket provides the
|
|
|
|
tools to perform unit and integration tests. It also provides a means to inspect
|
|
|
|
code generated by Rocket.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
## Local Dispatching
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
Rocket applications are tested by dispatching requests to a local instance of
|
|
|
|
`Rocket`. The [`local`] module contains all of the structures necessary to do
|
|
|
|
so. In particular, it contains a [`Client`] structure that is used to create
|
|
|
|
[`LocalRequest`] structures that can be dispatched against a given [`Rocket`]
|
|
|
|
instance. Usage is straightforward:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
1. Construct a `Rocket` instance that represents the application.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
```rust,no_run
|
2020-02-15 11:43:47 +00:00
|
|
|
let rocket = rocket::ignite();
|
|
|
|
# let _ = rocket;
|
|
|
|
```
|
2017-07-05 02:21:46 +00:00
|
|
|
|
|
|
|
2. Construct a `Client` using the `Rocket` instance.
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
```rust,no_run
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
# let rocket = rocket::ignite();
|
2020-10-15 04:37:16 +00:00
|
|
|
let client = Client::tracked(rocket).unwrap();
|
2020-02-15 11:43:47 +00:00
|
|
|
# let _ = client;
|
|
|
|
```
|
2017-07-05 02:21:46 +00:00
|
|
|
|
|
|
|
3. Construct requests using the `Client` instance.
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
```rust,no_run
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
# let rocket = rocket::ignite();
|
2020-10-15 04:37:16 +00:00
|
|
|
# let client = Client::tracked(rocket).unwrap();
|
2020-02-15 11:43:47 +00:00
|
|
|
let req = client.get("/");
|
|
|
|
# let _ = req;
|
|
|
|
```
|
2017-07-05 02:21:46 +00:00
|
|
|
|
2017-07-10 11:59:55 +00:00
|
|
|
4. Dispatch the request to retrieve the response.
|
2017-07-05 02:21:46 +00:00
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
```rust,no_run
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
# let rocket = rocket::ignite();
|
2020-10-15 04:37:16 +00:00
|
|
|
# let client = Client::tracked(rocket).unwrap();
|
2020-02-15 11:43:47 +00:00
|
|
|
# let req = client.get("/");
|
|
|
|
let response = req.dispatch();
|
|
|
|
# let _ = response;
|
|
|
|
```
|
2017-07-05 02:21:46 +00:00
|
|
|
|
2018-10-16 06:24:23 +00:00
|
|
|
[`local`]: @api/rocket/local/
|
2021-03-20 01:09:13 +00:00
|
|
|
[`Client`]: @api/rocket/local/#client
|
|
|
|
[`LocalRequest`]: @api/rocket/local/#localrequest
|
2018-10-16 05:50:35 +00:00
|
|
|
[`Rocket`]: @api/rocket/struct.Rocket.html
|
2017-07-05 02:21:46 +00:00
|
|
|
|
|
|
|
## Validating Responses
|
|
|
|
|
2021-03-20 01:09:13 +00:00
|
|
|
A `dispatch` of a `LocalRequest` returns a [`LocalResponse`] which can be
|
|
|
|
inspected for validaty. During testing, the response is usually validated
|
|
|
|
against expected properties. These includes things like the response HTTP
|
|
|
|
status, the inclusion of headers, and expected body data.
|
2017-07-05 02:21:46 +00:00
|
|
|
|
2021-03-20 01:09:13 +00:00
|
|
|
[`LocalResponse`] type provides methods to ease this sort of validation. We list
|
2017-07-05 02:21:46 +00:00
|
|
|
a few below:
|
|
|
|
|
|
|
|
* [`status`]: returns the HTTP status in the response.
|
|
|
|
* [`content_type`]: returns the Content-Type header in the response.
|
|
|
|
* [`headers`]: returns a map of all of the headers in the response.
|
2021-03-20 01:09:13 +00:00
|
|
|
* [`into_string`]: reads the body data into a `String`.
|
|
|
|
* [`into_bytes`]: reads the body data into a `Vec<u8>`.
|
2017-07-05 02:21:46 +00:00
|
|
|
|
2021-03-20 01:09:13 +00:00
|
|
|
[`LocalResponse`]: @api/rocket/local/blocking/struct.LocalResponse.html
|
|
|
|
[`status`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.status
|
|
|
|
[`content_type`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.content_type
|
|
|
|
[`headers`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.headers
|
|
|
|
[`into_string`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_string
|
|
|
|
[`into_bytes`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_bytes
|
2017-07-05 02:21:46 +00:00
|
|
|
|
|
|
|
These methods are typically used in combination with the `assert_eq!` or
|
|
|
|
`assert!` macros as follows:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
|
|
|
# use std::io::Cursor;
|
|
|
|
# use rocket::Response;
|
|
|
|
# use rocket::http::Header;
|
|
|
|
|
|
|
|
# #[get("/")]
|
|
|
|
# fn hello() -> Response<'static> {
|
|
|
|
# Response::build()
|
|
|
|
# .header(ContentType::Plain)
|
|
|
|
# .header(Header::new("X-Special", ""))
|
2020-07-11 16:41:53 +00:00
|
|
|
# .sized_body("Expected Body".len(), Cursor::new("Expected Body"))
|
2020-02-15 11:43:47 +00:00
|
|
|
# .finalize()
|
|
|
|
# }
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
use rocket::http::{ContentType, Status};
|
|
|
|
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# let rocket = rocket::ignite().mount("/", routes![hello]);
|
|
|
|
# let client = Client::debug(rocket).expect("valid rocket instance");
|
2020-07-05 18:35:36 +00:00
|
|
|
let mut response = client.get("/").dispatch();
|
2017-07-05 02:21:46 +00:00
|
|
|
|
|
|
|
assert_eq!(response.status(), Status::Ok);
|
|
|
|
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
|
|
|
assert!(response.headers().get_one("X-Special").is_some());
|
2020-07-11 16:41:53 +00:00
|
|
|
assert_eq!(response.into_string(), Some("Expected Body".into()));
|
2017-07-05 02:21:46 +00:00
|
|
|
```
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
## Testing "Hello, world!"
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
To solidify an intuition for how Rocket applications are tested, we walk through
|
|
|
|
how to test the "Hello, world!" application below:
|
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
#[get("/")]
|
|
|
|
fn hello() -> &'static str {
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
|
2020-07-22 23:10:02 +00:00
|
|
|
#[launch]
|
2020-02-15 11:43:47 +00:00
|
|
|
fn rocket() -> rocket::Rocket {
|
2017-07-05 02:21:46 +00:00
|
|
|
rocket::ignite().mount("/", routes![hello])
|
|
|
|
}
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
Notice that we've separated the _creation_ of the `Rocket` instance from the
|
|
|
|
_launch_ of the instance. As you'll soon see, this makes testing our application
|
|
|
|
easier, less verbose, and less error-prone.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
### Setting Up
|
|
|
|
|
|
|
|
First, we'll create a `test` module with the proper imports:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use super::rocket;
|
2020-07-05 18:35:36 +00:00
|
|
|
use rocket::local::blocking::Client;
|
2017-07-05 02:21:46 +00:00
|
|
|
use rocket::http::Status;
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn hello_world() {
|
2020-02-15 11:43:47 +00:00
|
|
|
/* .. */
|
2017-04-17 02:48:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
You can also move the body of the `test` module into its own file, say
|
|
|
|
`tests.rs`, and then import the module into the main file using:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
2017-07-05 02:21:46 +00:00
|
|
|
#[cfg(test)] mod tests;
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
### Testing
|
|
|
|
|
2020-01-08 16:03:05 +00:00
|
|
|
To test our "Hello, world!" application, we create a `Client` for our
|
2017-07-05 02:21:46 +00:00
|
|
|
`Rocket` instance. It's okay to use methods like `expect` and `unwrap` during
|
|
|
|
testing: we _want_ our tests to panic when something goes wrong.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# fn rocket() -> rocket::Rocket {
|
|
|
|
# rocket::ignite().reconfigure(rocket::Config::debug_default())
|
|
|
|
# }
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
|
2020-10-15 04:37:16 +00:00
|
|
|
let client = Client::tracked(rocket()).expect("valid rocket instance");
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
Then, we create a new `GET /` request and dispatch it, getting back our
|
|
|
|
application's response:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# fn rocket() -> rocket::Rocket {
|
|
|
|
# rocket::ignite().reconfigure(rocket::Config::debug_default())
|
|
|
|
# }
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-10-15 04:37:16 +00:00
|
|
|
# let client = Client::tracked(rocket()).expect("valid rocket instance");
|
2017-07-05 02:21:46 +00:00
|
|
|
let mut response = client.get("/").dispatch();
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
Finally, we ensure that the response contains the information we expect it to.
|
|
|
|
Here, we want to ensure two things:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
1. The status is `200 OK`.
|
|
|
|
2. The body is the string "Hello, world!".
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
We do this by checking the `Response` object directly:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
|
|
|
# #[get("/")]
|
|
|
|
# fn hello() -> &'static str { "Hello, world!" }
|
|
|
|
|
2020-07-11 16:41:53 +00:00
|
|
|
# use rocket::local::blocking::Client;
|
2020-02-15 11:43:47 +00:00
|
|
|
use rocket::http::{ContentType, Status};
|
2020-02-16 03:47:50 +00:00
|
|
|
#
|
2020-02-15 11:43:47 +00:00
|
|
|
# let rocket = rocket::ignite().mount("/", routes![hello]);
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# let client = Client::debug(rocket).expect("valid rocket instance");
|
2020-02-15 11:43:47 +00:00
|
|
|
# let mut response = client.get("/").dispatch();
|
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
assert_eq!(response.status(), Status::Ok);
|
2020-07-05 18:35:36 +00:00
|
|
|
assert_eq!(response.into_string(), Some("Hello, world!".into()));
|
2017-07-05 02:21:46 +00:00
|
|
|
```
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
That's it! Altogether, this looks like:
|
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
|
|
|
#[get("/")]
|
|
|
|
fn hello() -> &'static str {
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn rocket() -> rocket::Rocket {
|
|
|
|
rocket::ignite().mount("/", routes![hello])
|
|
|
|
}
|
|
|
|
|
|
|
|
# /*
|
2017-07-05 02:21:46 +00:00
|
|
|
#[cfg(test)]
|
2020-02-15 11:43:47 +00:00
|
|
|
# */
|
2017-07-05 02:21:46 +00:00
|
|
|
mod test {
|
|
|
|
use super::rocket;
|
2020-07-05 18:35:36 +00:00
|
|
|
use rocket::local::blocking::Client;
|
2017-07-05 02:21:46 +00:00
|
|
|
use rocket::http::Status;
|
|
|
|
|
2020-02-15 11:43:47 +00:00
|
|
|
# /*
|
2017-07-05 02:21:46 +00:00
|
|
|
#[test]
|
2020-02-15 11:43:47 +00:00
|
|
|
# */ pub
|
2017-07-05 02:21:46 +00:00
|
|
|
fn hello_world() {
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# /*
|
2020-10-15 04:37:16 +00:00
|
|
|
let client = Client::tracked(rocket()).expect("valid rocket instance");
|
Test 'secret_key' validation, now on pre-launch.
Prior to this commit, it was not possible to test Rocket crates in
production mode without setting a global secret key or bypassing secret
key checking - the testing script did the latter. The consequence is
that it became impossible to test secret key related failures because
the tests passed regardless.
This commit undoes this. As a consequence, all tests are now aware of
the difference between debug and release configurations, the latter of
which validates 'secret_key' by default. New 'Client::debug()' and
'Client::debug_with()' simplify creating an instance of 'Client' with
configuration in debug mode to avoid undesired test failures.
The summary of changes in this commit are:
* Config 'secret_key' success and failure are now tested.
* 'secret_key' validation was moved to pre-launch from 'Config:from()'.
* 'Config::from()' only extracts the config.
* Added 'Config::try_from()' for non-panicking extraction.
* 'Config' now knows the profile it was extracted from.
* The 'Config' provider sets a profile of 'Config.profile'.
* 'Rocket', 'Client', 'Fairings', implement 'Debug'.
* 'fairing::Info' implements 'Copy', 'Clone'.
* 'Fairings' keeps track of, logs attach fairings.
* 'Rocket::reconfigure()' was added to allow modifying a config.
Internally, the testing script was refactored to properly test the
codebase with the new changes. In particular, it no longer sets a rustc
'cfg' to avoid secret-key checking.
Resolves #1543.
Fixes #1564.
2021-03-09 08:07:43 +00:00
|
|
|
# */
|
|
|
|
# let client = Client::debug(rocket()).expect("valid rocket instance");
|
2020-07-05 18:35:36 +00:00
|
|
|
let mut response = client.get("/").dispatch();
|
2017-07-05 02:21:46 +00:00
|
|
|
assert_eq!(response.status(), Status::Ok);
|
2020-07-05 18:35:36 +00:00
|
|
|
assert_eq!(response.into_string(), Some("Hello, world!".into()));
|
2017-07-05 02:21:46 +00:00
|
|
|
}
|
|
|
|
}
|
2020-02-15 11:43:47 +00:00
|
|
|
|
|
|
|
# fn main() { test::hello_world(); }
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
The tests can be run with `cargo test`. You can find the full source code to
|
2018-10-16 05:50:35 +00:00
|
|
|
[this example on GitHub](@example/testing).
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-07-08 16:20:12 +00:00
|
|
|
## Asynchronous Testing
|
|
|
|
|
|
|
|
You may have noticed the use of a "`blocking`" API in these examples, even
|
|
|
|
though `Rocket` is an `async` web framework. In most situations, the `blocking`
|
2020-07-09 01:36:28 +00:00
|
|
|
testing API is easier to use and should be preferred. However, when concurrent
|
|
|
|
execution of two or more requests is required for the server to make progress,
|
|
|
|
you will need the more flexible `asynchronous` API; the `blocking` API is not
|
|
|
|
capable of dispatching multiple requests simultaneously. While synthetic, the
|
|
|
|
[`async_required` `testing` example] uses an `async` barrier to demonstrate such
|
|
|
|
a case. For more information, see the [`rocket::local`] and
|
|
|
|
[`rocket::local::asynchronous`] documentation.
|
2020-07-08 16:20:12 +00:00
|
|
|
|
|
|
|
[`rocket::local`]: @api/rocket/local/index.html
|
|
|
|
[`rocket::local::asynchronous`]: @api/rocket/local/asynchronous/index.html
|
2020-07-09 01:36:28 +00:00
|
|
|
[`async_required` `testing` example]: @example/testing/src/async_required.rs
|
2020-07-08 16:20:12 +00:00
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
## Codegen Debug
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
It can be useful to inspect the code that Rocket's code generation is emitting,
|
|
|
|
especially when you get a strange type error. To have Rocket log the code that
|
|
|
|
it is emitting to the console, set the `ROCKET_CODEGEN_DEBUG` environment
|
|
|
|
variable when compiling:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-02-15 11:43:47 +00:00
|
|
|
```sh
|
2017-04-17 02:48:59 +00:00
|
|
|
ROCKET_CODEGEN_DEBUG=1 cargo build
|
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
During compilation, you should see output like:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-02-15 11:43:47 +00:00
|
|
|
```rust,ignore
|
2018-10-22 21:47:35 +00:00
|
|
|
note: emitting Rocket code generation debug output
|
2021-03-20 01:09:13 +00:00
|
|
|
--> examples/hello_world/src/main.rs:14:1
|
|
|
|
|
|
|
|
|
14 | #[get("/world")]
|
|
|
|
| ^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
|
= note:
|
|
|
|
impl From<world> for rocket::StaticRouteInfo {
|
|
|
|
fn from(_: world) -> rocket::StaticRouteInfo {
|
|
|
|
fn monomorphized_function<'_b>(
|
|
|
|
__req: &'_b rocket::request::Request<'_>,
|
|
|
|
__data: rocket::data::Data,
|
|
|
|
) -> rocket::handler::HandlerFuture<'_b> {
|
|
|
|
::std::boxed::Box::pin(async move {
|
|
|
|
let ___responder = world();
|
|
|
|
rocket::handler::Outcome::from(__req, ___responder)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
rocket::StaticRouteInfo {
|
|
|
|
name: "world",
|
|
|
|
method: ::rocket::http::Method::Get,
|
|
|
|
path: "/world",
|
|
|
|
handler: monomorphized_function,
|
|
|
|
format: ::std::option::Option::None,
|
|
|
|
rank: ::std::option::Option::None,
|
|
|
|
}
|
|
|
|
}
|
2018-10-22 21:47:35 +00:00
|
|
|
}
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2017-07-05 02:21:46 +00:00
|
|
|
This corresponds to the facade request handler Rocket has generated for the
|
|
|
|
`hello` route.
|