axum_test/
test_server_config.rs

1use anyhow::Result;
2
3use crate::transport_layer::IntoTransportLayer;
4use crate::TestServer;
5use crate::TestServerBuilder;
6use crate::Transport;
7
8/// This is for customising the [`TestServer`](crate::TestServer) on construction.
9/// It implements [`Default`] to ease building.
10///
11/// ```rust
12/// use axum_test::TestServerConfig;
13///
14/// let config = TestServerConfig {
15///     save_cookies: true,
16///     ..TestServerConfig::default()
17/// };
18/// ```
19///
20/// These can be passed to `TestServer::new_with_config`:
21///
22/// ```rust
23/// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
24/// #
25/// use axum::Router;
26/// use axum_test::TestServer;
27/// use axum_test::TestServerConfig;
28///
29/// let my_app = Router::new();
30///
31/// let config = TestServerConfig {
32///     save_cookies: true,
33///     ..TestServerConfig::default()
34/// };
35///
36/// // Build the Test Server
37/// let server = TestServer::new_with_config(my_app, config)?;
38/// #
39/// # Ok(())
40/// # }
41/// ```
42///
43#[derive(Debug, Clone, Eq, PartialEq)]
44pub struct TestServerConfig {
45    /// Which transport mode to use to process requests.
46    /// For setting if the server should use mocked http (which uses [`tower::util::Oneshot`](tower::util::Oneshot)),
47    /// or if it should run on a named or random IP address.
48    ///
49    /// The default is to use mocking, apart from services built using [`axum::extract::connect_info::IntoMakeServiceWithConnectInfo`](axum::extract::connect_info::IntoMakeServiceWithConnectInfo)
50    /// (this is because it needs a real TCP stream).
51    pub transport: Option<Transport>,
52
53    /// Set for the server to save cookies that are returned,
54    /// for use in future requests.
55    ///
56    /// This is useful for automatically saving session cookies (and similar)
57    /// like a browser would do.
58    ///
59    /// **Defaults** to false (being turned off).
60    pub save_cookies: bool,
61
62    /// Asserts that requests made to the test server,
63    /// will by default,
64    /// return a status code in the 2xx range.
65    ///
66    /// This can be overridden on a per request basis using
67    /// [`TestRequest::expect_failure()`](crate::TestRequest::expect_failure()).
68    ///
69    /// This is useful when making multiple requests at a start of test
70    /// which you presume should always work.
71    ///
72    /// **Defaults** to false (being turned off).
73    pub expect_success_by_default: bool,
74
75    /// If you make a request with a 'http://' schema,
76    /// then it will ignore the Test Server's address.
77    ///
78    /// For example if the test server is running at `http://localhost:1234`,
79    /// and you make a request to `http://google.com`.
80    /// Then the request will go to `http://google.com`.
81    /// Ignoring the `localhost:1234` part.
82    ///
83    /// Turning this setting on will change this behaviour.
84    ///
85    /// After turning this on, the same request will go to
86    /// `http://localhost:1234/http://google.com`.
87    ///
88    /// **Defaults** to false (being turned off).
89    pub restrict_requests_with_http_schema: bool,
90
91    /// Set the default content type for all requests created by the `TestServer`.
92    ///
93    /// This overrides the default 'best efforts' approach of requests.
94    pub default_content_type: Option<String>,
95
96    /// Set the default scheme to use for all requests created by the `TestServer`.
97    ///
98    /// This overrides the default 'http'.
99    pub default_scheme: Option<String>,
100}
101
102impl TestServerConfig {
103    /// Creates a default `TestServerConfig`.
104    pub fn new() -> Self {
105        Default::default()
106    }
107
108    /// This is shorthand for calling [`crate::TestServer::new_with_config`],
109    /// and passing this config.
110    ///
111    /// ```rust
112    /// # async fn test() -> Result<(), Box<dyn ::std::error::Error>> {
113    /// #
114    /// use axum::Router;
115    /// use axum_test::TestServer;
116    /// use axum_test::TestServerConfig;
117    ///
118    /// let app = Router::new();
119    /// let config = TestServerConfig {
120    ///     save_cookies: true,
121    ///     default_content_type: Some("application/json".to_string()),
122    ///     ..Default::default()
123    /// };
124    /// let server = TestServer::new_with_config(app, config)?;
125    /// #
126    /// # Ok(())
127    /// # }
128    /// ```
129    pub fn build<A>(self, app: A) -> Result<TestServer>
130    where
131        A: IntoTransportLayer,
132    {
133        TestServer::new_with_config(app, self)
134    }
135}
136
137impl Default for TestServerConfig {
138    fn default() -> Self {
139        Self {
140            transport: None,
141            save_cookies: false,
142            expect_success_by_default: false,
143            restrict_requests_with_http_schema: false,
144            default_content_type: None,
145            default_scheme: None,
146        }
147    }
148}
149
150impl From<TestServerBuilder> for TestServerConfig {
151    fn from(builder: TestServerBuilder) -> Self {
152        builder.into_config()
153    }
154}
155
156#[cfg(test)]
157mod test_scheme {
158    use axum::extract::Request;
159    use axum::routing::get;
160    use axum::Router;
161
162    use crate::TestServer;
163    use crate::TestServerConfig;
164
165    async fn route_get_scheme(request: Request) -> String {
166        request.uri().scheme_str().unwrap().to_string()
167    }
168
169    #[tokio::test]
170    async fn it_should_set_scheme_when_present_in_config() {
171        let router = Router::new().route("/scheme", get(route_get_scheme));
172
173        let config = TestServerConfig {
174            default_scheme: Some("https".to_string()),
175            ..Default::default()
176        };
177        let server = TestServer::new_with_config(router, config).unwrap();
178
179        server.get("/scheme").await.assert_text("https");
180    }
181}