axum_test/transport_layer/into_transport_layer/
serve.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use anyhow::anyhow;
use anyhow::Context;
use anyhow::Result;
use axum::extract::Request;
use axum::response::Response;
use axum::serve::IncomingStream;
use axum::serve::Serve;
use std::convert::Infallible;
use tokio::spawn;
use tower::Service;
use url::Url;

use crate::internals::HttpTransportLayer;
use crate::transport_layer::IntoTransportLayer;
use crate::transport_layer::TransportLayer;
use crate::transport_layer::TransportLayerBuilder;
use crate::util::ServeHandle;

impl<M, S> IntoTransportLayer for Serve<M, S>
where
    M: for<'a> Service<IncomingStream<'a>, Error = Infallible, Response = S> + Send + 'static,
    for<'a> <M as Service<IncomingStream<'a>>>::Future: Send,
    S: Service<Request, Response = Response, Error = Infallible> + Clone + Send + 'static,
    S::Future: Send,
{
    fn into_http_transport_layer(
        self,
        _builder: TransportLayerBuilder,
    ) -> Result<Box<dyn TransportLayer>> {
        Err(anyhow!("`Serve` must be started with http or mock transport. Do not set any transport on `TestServerConfig`."))
    }

    fn into_mock_transport_layer(self) -> Result<Box<dyn TransportLayer>> {
        Err(anyhow!("`Serve` cannot be mocked, as it's underlying implementation requires a real connection. Do not set any transport on `TestServerConfig`."))
    }

    fn into_default_transport(
        self,
        _builder: TransportLayerBuilder,
    ) -> Result<Box<dyn TransportLayer>> {
        let socket_addr = self.local_addr()?;

        let join_handle = spawn(async move {
            self.await
                .context("Failed to create ::axum::Server for TestServer")
                .expect("Expect server to start serving");
        });

        let server_address = format!("http://{socket_addr}");
        let server_url: Url = server_address.parse()?;

        Ok(Box::new(HttpTransportLayer::new(
            ServeHandle::new(join_handle),
            None,
            server_url,
        )))
    }
}

#[cfg(test)]
mod test_into_http_transport_layer {
    use crate::util::new_random_tokio_tcp_listener;
    use crate::TestServer;
    use axum::routing::get;
    use axum::routing::IntoMakeService;
    use axum::serve;
    use axum::Router;

    async fn get_ping() -> &'static str {
        "pong!"
    }

    #[tokio::test]
    #[should_panic]
    async fn it_should_panic_when_run_with_http() {
        // Build an application with a route.
        let app: IntoMakeService<Router> = Router::new()
            .route("/ping", get(get_ping))
            .into_make_service();
        let port = new_random_tokio_tcp_listener().unwrap();
        let application = serve(port, app);

        // Run the server.
        TestServer::builder()
            .http_transport()
            .build(application)
            .expect("Should create test server");
    }
}

#[cfg(test)]
mod test_into_mock_transport_layer {
    use crate::util::new_random_tokio_tcp_listener;
    use crate::TestServer;
    use axum::routing::get;
    use axum::routing::IntoMakeService;
    use axum::serve;
    use axum::Router;

    async fn get_ping() -> &'static str {
        "pong!"
    }

    #[tokio::test]
    #[should_panic]
    async fn it_should_panic_when_run_with_mock_http() {
        // Build an application with a route.
        let app: IntoMakeService<Router> = Router::new()
            .route("/ping", get(get_ping))
            .into_make_service();
        let port = new_random_tokio_tcp_listener().unwrap();
        let application = serve(port, app);

        // Run the server.
        TestServer::builder()
            .mock_transport()
            .build(application)
            .expect("Should create test server");
    }
}

#[cfg(test)]
mod test_into_default_transport {
    use crate::util::new_random_tokio_tcp_listener;
    use crate::TestServer;
    use axum::routing::get;
    use axum::routing::IntoMakeService;
    use axum::serve;
    use axum::Router;

    async fn get_ping() -> &'static str {
        "pong!"
    }

    #[tokio::test]
    async fn it_should_run_service() {
        // Build an application with a route.
        let app: IntoMakeService<Router> = Router::new()
            .route("/ping", get(get_ping))
            .into_make_service();
        let port = new_random_tokio_tcp_listener().unwrap();
        let application = serve(port, app);

        // Run the server.
        let server = TestServer::builder()
            .build(application)
            .expect("Should create test server");

        // Get the request.
        server.get(&"/ping").await.assert_text(&"pong!");
    }
}