trillium_testing/
server_connector.rs

1use crate::TestTransport;
2use std::sync::Arc;
3use url::Url;
4
5/// a bridge between trillium servers and clients
6#[derive(Debug)]
7pub struct ServerConnector<H> {
8    handler: Arc<H>,
9}
10
11impl<H> ServerConnector<H>
12where
13    H: trillium::Handler,
14{
15    /// builds a new ServerConnector
16    pub fn new(handler: H) -> Self {
17        Self {
18            handler: Arc::new(handler),
19        }
20    }
21
22    /// opens a new connection to this virtual server, returning the client transport
23    pub async fn connect(&self, secure: bool) -> TestTransport {
24        let (client_transport, server_transport) = TestTransport::new();
25
26        let handler = Arc::clone(&self.handler);
27
28        crate::spawn(async move {
29            trillium_http::Conn::map(server_transport, Default::default(), |mut conn| {
30                let handler = Arc::clone(&handler);
31                async move {
32                    conn.set_secure(secure);
33                    let conn = handler.run(conn.into()).await;
34                    let conn = handler.before_send(conn).await;
35                    conn.into_inner()
36                }
37            })
38            .await
39            .unwrap();
40        });
41
42        client_transport
43    }
44}
45
46#[trillium_server_common::async_trait]
47impl<H: trillium::Handler> trillium_server_common::Connector for ServerConnector<H> {
48    type Transport = TestTransport;
49    async fn connect(&self, url: &Url) -> std::io::Result<Self::Transport> {
50        Ok(self.connect(url.scheme() == "https").await)
51    }
52
53    fn spawn<Fut: std::future::Future<Output = ()> + Send + 'static>(&self, fut: Fut) {
54        crate::spawn(fut);
55    }
56}
57
58/// build a connector from this handler
59pub fn connector(handler: impl trillium::Handler) -> impl trillium_server_common::Connector {
60    ServerConnector::new(handler)
61}
62
63#[cfg(test)]
64mod test {
65    use crate::server_connector::ServerConnector;
66    use trillium_client::Client;
67
68    #[test]
69    fn test() {
70        crate::block_on(async {
71            let client = Client::new(ServerConnector::new("test"));
72            let mut conn = client.get("https://example.com/test").await.unwrap();
73            assert_eq!(conn.response_body().read_string().await.unwrap(), "test");
74        });
75    }
76
77    #[test]
78    fn test_no_dns() {
79        crate::block_on(async {
80            let client = Client::new(ServerConnector::new("test"));
81            let mut conn = client
82                .get("https://not.a.real.tld.example/test")
83                .await
84                .unwrap();
85            assert_eq!(conn.response_body().read_string().await.unwrap(), "test");
86        });
87    }
88
89    #[test]
90    fn test_post() {
91        crate::block_on(async {
92            let client = Client::new(ServerConnector::new(
93                |mut conn: trillium::Conn| async move {
94                    let body = conn.request_body_string().await.unwrap();
95                    let response = format!(
96                        "{} {}://{}{} with body \"{}\"",
97                        conn.method(),
98                        if conn.is_secure() { "https" } else { "http" },
99                        conn.inner().host().unwrap_or_default(),
100                        conn.path(),
101                        body
102                    );
103
104                    conn.ok(response)
105                },
106            ));
107
108            let body = client
109                .post("https://example.com/test")
110                .with_body("some body")
111                .await
112                .unwrap()
113                .response_body()
114                .read_string()
115                .await
116                .unwrap();
117
118            assert_eq!(
119                body,
120                "POST https://example.com/test with body \"some body\""
121            );
122        });
123    }
124}