Skip to main content

ntex/client/
test.rs

1//! Test helpers for the ntex HTTP client.
2#[cfg(feature = "cookie")]
3use coo_kie::{Cookie, CookieJar};
4
5use crate::http::error::HttpError;
6use crate::http::header::{HeaderName, HeaderValue};
7use crate::http::{Payload, ResponseHead, StatusCode, Version};
8use crate::{Cfg, channel::bstream, util::Bytes};
9
10use super::ClientResponse;
11
12#[derive(Debug)]
13/// Builder for creating a [`ClientResponse`] in tests.
14pub struct TestResponse {
15    head: ResponseHead,
16    payload: Option<Payload>,
17    #[cfg(feature = "cookie")]
18    cookies: CookieJar,
19}
20
21impl TestResponse {
22    /// Creates a test response builder.
23    pub fn builder() -> TestResponse {
24        TestResponse {
25            head: ResponseHead::new(StatusCode::OK, Version::default()),
26            payload: None,
27            #[cfg(feature = "cookie")]
28            cookies: CookieJar::new(),
29        }
30    }
31
32    #[must_use]
33    /// Creates a test response with one header.
34    pub fn with_header<K, V>(key: K, value: V) -> Self
35    where
36        HeaderName: TryFrom<K>,
37        HeaderValue: TryFrom<V>,
38        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
39    {
40        Self::builder().header(key, value)
41    }
42
43    #[must_use]
44    /// Sets the response HTTP version.
45    pub fn version(mut self, ver: Version) -> Self {
46        self.head.version = ver;
47        self
48    }
49
50    #[must_use]
51    /// Appends a response header.
52    pub fn header<K, V>(mut self, key: K, value: V) -> Self
53    where
54        HeaderName: TryFrom<K>,
55        HeaderValue: TryFrom<V>,
56        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
57    {
58        if let Ok(key) = HeaderName::try_from(key)
59            && let Ok(value) = HeaderValue::try_from(value)
60        {
61            self.head.headers.append(key, value);
62            return self;
63        }
64        panic!("Cannot create header");
65    }
66
67    #[must_use]
68    #[cfg(feature = "cookie")]
69    /// Adds a response cookie.
70    pub fn cookie<C>(mut self, cookie: C) -> Self
71    where
72        C: Into<Cookie<'static>>,
73    {
74        self.cookies.add(cookie.into());
75        self
76    }
77
78    #[must_use]
79    /// Sets the response payload.
80    pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
81        self.payload = Some(bstream::empty(Some(data.into())).into());
82        self
83    }
84
85    #[must_use]
86    /// Builds the [`ClientResponse`].
87    pub fn build(self) -> ClientResponse {
88        #[allow(unused_mut)]
89        let mut head = self.head;
90
91        // one `Set-Cookie` header per cookie
92        #[cfg(feature = "cookie")]
93        for c in self.cookies.delta() {
94            let value = HeaderValue::from_str(&c.encoded().to_string()).unwrap();
95            head.headers.append(crate::http::header::SET_COOKIE, value);
96        }
97
98        if let Some(pl) = self.payload {
99            ClientResponse::new(head, pl, Cfg::default())
100        } else {
101            ClientResponse::new(head, bstream::empty(None).into(), Cfg::default())
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::http::header;
110
111    #[crate::rt_test]
112    async fn test_basics() {
113        let res = {
114            #[cfg(feature = "cookie")]
115            {
116                TestResponse::builder()
117                    .version(Version::HTTP_2)
118                    .header(header::DATE, "data")
119                    .cookie(coo_kie::Cookie::build(("name", "value")))
120                    .build()
121            }
122            #[cfg(not(feature = "cookie"))]
123            {
124                TestResponse::builder()
125                    .version(Version::HTTP_2)
126                    .header(header::DATE, "data")
127                    .build()
128            }
129        };
130        #[cfg(feature = "cookie")]
131        assert!(res.headers().contains_key(header::SET_COOKIE));
132        assert!(res.headers().contains_key(header::DATE));
133        assert_eq!(res.version(), Version::HTTP_2);
134    }
135
136    #[cfg(feature = "cookie")]
137    #[crate::rt_test]
138    async fn test_cookies() {
139        use crate::http::HttpMessage;
140        use coo_kie::Cookie;
141
142        let res = TestResponse::builder()
143            .cookie(Cookie::build(("c1", "v 1")).path("/p"))
144            .cookie(Cookie::build(("c2", "v2")))
145            .build();
146        assert_eq!(res.headers().get_all(header::SET_COOKIE).count(), 2);
147
148        let mut cookies: Vec<_> = res
149            .cookies()
150            .unwrap()
151            .iter()
152            .map(|c| (c.name().to_string(), c.value().to_string()))
153            .collect();
154        cookies.sort_unstable();
155        assert_eq!(
156            cookies,
157            [
158                ("c1".to_string(), "v 1".to_string()),
159                ("c2".to_string(), "v2".to_string())
160            ]
161        );
162        assert_eq!(res.cookie("c1").unwrap().path(), Some("/p"));
163    }
164}