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}