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
153
//! Test server
use std::{io, net, thread};

use ntex_net::{tcp_connect, Io};
use ntex_rt::System;
use ntex_service::ServiceFactory;
use socket2::{Domain, SockAddr, Socket, Type};

use super::{Server, ServerBuilder};

/// Start test server
///
/// `TestServer` is very simple test server that simplify process of writing
/// integration tests cases for ntex web applications.
///
/// # Examples
///
/// ```rust
/// use ntex::http;
/// use ntex::http::client::Client;
/// use ntex::server;
/// use ntex::web::{self, App, HttpResponse};
///
/// async fn my_handler() -> Result<HttpResponse, std::io::Error> {
///     Ok(HttpResponse::Ok().into())
/// }
///
/// #[ntex::test]
/// async fn test_example() {
///     let mut srv = server::test_server(
///         || http::HttpService::new(
///             App::new().service(
///                 web::resource("/").to(my_handler))
///         )
///     );
///
///     let req = Client::new().get("http://127.0.0.1:{}", srv.addr().port());
///     let response = req.send().await.unwrap();
///     assert!(response.status().is_success());
/// }
/// ```
pub fn test_server<F, R>(factory: F) -> TestServer
where
    F: Fn() -> R + Send + Clone + 'static,
    R: ServiceFactory<Io> + 'static,
{
    let (tx, rx) = oneshot::channel();
    // run server in separate thread
    thread::spawn(move || {
        let sys = System::new("ntex-test-server");
        let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap();
        let local_addr = tcp.local_addr().unwrap();
        let system = sys.system();

        sys.run(move || {
            let server = ServerBuilder::new()
                .listen("test", tcp, move |_| factory())?
                .set_tag("test", "TEST-SERVER")
                .workers(1)
                .disable_signals()
                .run();
            tx.send((system, local_addr, server))
                .expect("Failed to send Server to TestServer");
            Ok(())
        })
    });

    let (system, addr, server) = rx.recv().unwrap();

    TestServer {
        addr,
        server,
        system,
    }
}

/// Start new server with server builder
pub fn build_test_server<F>(factory: F) -> TestServer
where
    F: FnOnce(ServerBuilder) -> ServerBuilder + Send + 'static,
{
    let (tx, rx) = oneshot::channel();
    // run server in separate thread
    thread::spawn(move || {
        let sys = System::new("ntex-test-server");
        let system = sys.system();

        sys.run(|| {
            let server = factory(super::build()).workers(1).disable_signals().run();
            tx.send((system, server))
                .expect("Failed to send Server to TestServer");
            Ok(())
        })
    });
    let (system, server) = rx.recv().unwrap();

    TestServer {
        system,
        server,
        addr: "127.0.0.1:0".parse().unwrap(),
    }
}

#[derive(Debug)]
/// Test server controller
pub struct TestServer {
    addr: net::SocketAddr,
    system: System,
    server: Server,
}

impl TestServer {
    /// Test server socket addr
    pub fn addr(&self) -> net::SocketAddr {
        self.addr
    }

    pub fn set_addr(mut self, addr: net::SocketAddr) -> Self {
        self.addr = addr;
        self
    }

    /// Connect to server, return Io
    pub async fn connect(&self) -> io::Result<Io> {
        tcp_connect(self.addr).await
    }

    /// Stop http server by stopping the runtime.
    pub fn stop(&self) {
        self.system.stop();
    }

    /// Get first available unused address
    pub fn unused_addr() -> net::SocketAddr {
        let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
        let socket = Socket::new(Domain::IPV4, Type::STREAM, None).unwrap();
        socket.set_reuse_address(true).unwrap();
        socket.bind(&SockAddr::from(addr)).unwrap();
        let tcp = net::TcpListener::from(socket);
        tcp.local_addr().unwrap()
    }

    /// Get access to the running Server
    pub fn server(&self) -> Server {
        self.server.clone()
    }
}

impl Drop for TestServer {
    fn drop(&mut self) {
        self.stop()
    }
}