rocket/local/client.rs
1macro_rules! req_method {
2 ($import:literal, $NAME:literal, $f:ident, $method:expr) => (
3 req_method!(@
4 $import,
5 $NAME,
6 concat!("let req = client.", stringify!($f), r#"("/hello");"#),
7 $f,
8 $method
9 );
10 );
11
12 (@$import:literal, $NAME:literal, $use_it:expr, $f:ident, $method:expr) => (
13 /// Create a local `
14 #[doc = $NAME]
15 /// ` request to the URI `uri`.
16 ///
17 /// When dispatched, the request will be served by the instance of Rocket
18 /// within `self`. The request is not dispatched automatically. To actually
19 /// dispatch the request, call [`LocalRequest::dispatch()`] on the returned
20 /// request.
21 ///
22 /// # Example
23 ///
24 /// ```rust,no_run
25 #[doc = $import]
26 ///
27 /// # Client::_test(|client, _, _| {
28 /// let client: &Client = client;
29 #[doc = $use_it]
30 /// # });
31 /// ```
32 #[inline(always)]
33 pub fn $f<'c, 'u: 'c, U>(&'c self, uri: U) -> LocalRequest<'c>
34 where U: TryInto<Origin<'u>> + fmt::Display
35 {
36 self.req($method, uri)
37 }
38 )
39}
40
41macro_rules! pub_client_impl {
42 ($import:literal $(@$prefix:tt $suffix:tt)?) =>
43{
44 /// Construct a new `Client` from an instance of `Rocket` _with_ cookie
45 /// tracking. This is typically the desired mode of operation for testing.
46 ///
47 /// # Cookie Tracking
48 ///
49 /// With cookie tracking enabled, a `Client` propagates cookie changes made
50 /// by responses to previously dispatched requests. In other words,
51 /// succeeding requests reflect changes (additions and removals) made by any
52 /// prior responses.
53 ///
54 /// Cookie tracking requires synchronization between dispatches. **As such,
55 /// cookie tracking _should not_ be enabled if a local client is being used
56 /// to serve requests on multiple threads.**
57 ///
58 /// # Errors
59 ///
60 /// If launching the `Rocket` instance would fail, excepting network errors,
61 /// the `Error` is returned.
62 ///
63 /// ```rust,no_run
64 #[doc = $import]
65 ///
66 /// let rocket = rocket::build();
67 /// let client = Client::tracked(rocket);
68 /// ```
69 #[inline(always)]
70 pub $($prefix)? fn tracked<P: Phase>(rocket: Rocket<P>) -> Result<Self, Error> {
71 Self::_new(rocket, true, false) $(.$suffix)?
72 }
73
74 #[inline(always)]
75 pub $($prefix)? fn tracked_secure<P: Phase>(rocket: Rocket<P>) -> Result<Self, Error> {
76 Self::_new(rocket, true, true) $(.$suffix)?
77 }
78
79 /// Construct a new `Client` from an instance of `Rocket` _without_
80 /// cookie tracking.
81 ///
82 /// # Cookie Tracking
83 ///
84 /// Unlike the [`tracked()`](Client::tracked()) constructor, a `Client`
85 /// returned from this method _does not_ automatically propagate cookie
86 /// changes and thus requires no synchronization between dispatches.
87 ///
88 /// # Errors
89 ///
90 /// If launching the `Rocket` instance would fail, excepting network
91 /// errors, the `Error` is returned.
92 ///
93 /// ```rust,no_run
94 #[doc = $import]
95 ///
96 /// let rocket = rocket::build();
97 /// let client = Client::untracked(rocket);
98 /// ```
99 pub $($prefix)? fn untracked<P: Phase>(rocket: Rocket<P>) -> Result<Self, Error> {
100 Self::_new(rocket, false, false) $(.$suffix)?
101 }
102
103 pub $($prefix)? fn untracked_secure<P: Phase>(rocket: Rocket<P>) -> Result<Self, Error> {
104 Self::_new(rocket, false, true) $(.$suffix)?
105 }
106
107 /// Terminates `Client` by initiating a graceful shutdown via
108 /// [`Shutdown::notify()`] and running shutdown fairings.
109 ///
110 /// This method _must_ be called on a `Client` if graceful shutdown is
111 /// required for testing as `Drop` _does not_ signal `Shutdown` nor run
112 /// shutdown fairings. Returns the instance of `Rocket` being managed by
113 /// this client after all shutdown fairings run to completion.
114 ///
115 /// [`Shutdown::notify()`]: crate::Shutdown::notify()
116 ///
117 /// ```rust,no_run
118 #[doc = $import]
119 ///
120 /// # fn f(client: Client) {
121 /// let client: Client = client;
122 /// let rocket = client.terminate();
123 /// # }
124 /// ```
125 #[inline(always)]
126 pub $($prefix)? fn terminate(self) -> Rocket<Ignite> {
127 Self::_terminate(self) $(.$suffix)?
128 }
129
130 #[doc(hidden)]
131 pub $($prefix)? fn debug_with(routes: Vec<crate::Route>) -> Result<Self, Error> {
132 let rocket = crate::custom(crate::Config::debug_default());
133 Self::debug(rocket.mount("/", routes)) $(.$suffix)?
134 }
135
136 #[doc(hidden)]
137 pub $($prefix)? fn debug(rocket: Rocket<crate::Build>) -> Result<Self, Error> {
138 use crate::config;
139
140 let figment = rocket.figment().clone()
141 .merge((config::Config::LOG_LEVEL, "debug"))
142 .select(config::Config::DEBUG_PROFILE);
143
144 Self::tracked(rocket.reconfigure(figment)) $(.$suffix)?
145 }
146
147 /// Returns a reference to the `Rocket` this client is creating requests
148 /// for.
149 ///
150 /// # Example
151 ///
152 /// ```rust
153 #[doc = $import]
154 ///
155 /// # Client::_test(|client, _, _| {
156 /// let client: &Client = client;
157 /// let rocket = client.rocket();
158 /// # });
159 /// ```
160 #[inline(always)]
161 pub fn rocket(&self) -> &Rocket<Orbit> {
162 &*self._rocket()
163 }
164
165 /// Returns a cookie jar containing all of the cookies this client is
166 /// currently tracking.
167 ///
168 /// If cookie tracking is disabled, the returned jar will always be empty.
169 /// Otherwise, it will contains all of the cookies collected from responses
170 /// to requests dispatched by this client that have not expired.
171 ///
172 /// # Example
173 ///
174 /// ```rust
175 #[doc = $import]
176 ///
177 /// # Client::_test(|client, _, _| {
178 /// let client: &Client = client;
179 /// let cookie = client.cookies();
180 /// # });
181 /// ```
182 #[inline(always)]
183 pub fn cookies(&self) -> crate::http::CookieJar<'_> {
184 let jar = self._with_raw_cookies(|jar| jar.clone());
185 crate::http::CookieJar::new(Some(jar), self.rocket())
186 }
187
188 req_method!($import, "GET", get, Method::Get);
189 req_method!($import, "PUT", put, Method::Put);
190 req_method!($import, "POST", post, Method::Post);
191 req_method!($import, "DELETE", delete, Method::Delete);
192 req_method!($import, "OPTIONS", options, Method::Options);
193 req_method!($import, "HEAD", head, Method::Head);
194 req_method!($import, "PATCH", patch, Method::Patch);
195
196 /// Create a local `GET` request to the URI `uri`.
197 ///
198 /// When dispatched, the request will be served by the instance of
199 /// Rocket within `self`. The request is not dispatched automatically.
200 /// To actually dispatch the request, call [`LocalRequest::dispatch()`]
201 /// on the returned request.
202 ///
203 /// # Example
204 ///
205 /// ```rust,no_run
206 #[doc = $import]
207 /// use rocket::http::Method;
208 ///
209 /// # Client::_test(|client, _, _| {
210 /// let client: &Client = client;
211 /// client.req(Method::Get, "/hello");
212 /// # });
213 /// ```
214 #[inline(always)]
215 pub fn req<'c, 'u: 'c, U>(
216 &'c self,
217 method: Method,
218 uri: U
219 ) -> LocalRequest<'c>
220 where U: TryInto<Origin<'u>> + fmt::Display
221 {
222 self._req(method, uri)
223 }
224
225 #[cfg(test)]
226 #[allow(dead_code)]
227 fn _ensure_impls_exist() {
228 fn is_send<T: Send>() {}
229 is_send::<Self>();
230
231 fn is_debug<T: std::fmt::Debug>() {}
232 is_debug::<Self>();
233 }
234}}