actix_server/
test_server.rs1use std::{io, net, sync::mpsc, thread};
2
3use actix_rt::{net::TcpStream, System};
4
5use crate::{Server, ServerBuilder, ServerHandle, ServerServiceFactory};
6
7pub struct TestServer;
30
31pub struct TestServerHandle {
33 addr: net::SocketAddr,
34 host: String,
35 port: u16,
36 server_handle: ServerHandle,
37 thread_handle: Option<thread::JoinHandle<io::Result<()>>>,
38}
39
40impl TestServer {
41 pub fn start(factory: impl ServerServiceFactory<TcpStream>) -> TestServerHandle {
43 Self::start_with_builder(Server::build(), factory)
44 }
45
46 pub fn start_with_builder(
48 server_builder: ServerBuilder,
49 factory: impl ServerServiceFactory<TcpStream>,
50 ) -> TestServerHandle {
51 let (tx, rx) = mpsc::channel();
52
53 let thread_handle = thread::spawn(move || {
55 let lst = net::TcpListener::bind("127.0.0.1:0").unwrap();
56 let local_addr = lst.local_addr().unwrap();
57
58 System::new().block_on(async {
59 let server = server_builder
60 .listen("test", lst, factory)
61 .unwrap()
62 .workers(1)
63 .disable_signals()
64 .run();
65
66 tx.send((server.handle(), local_addr)).unwrap();
67 server.await
68 })
69 });
70
71 let (server_handle, addr) = rx.recv().unwrap();
72
73 let host = format!("{}", addr.ip());
74 let port = addr.port();
75
76 TestServerHandle {
77 addr,
78 host,
79 port,
80 server_handle,
81 thread_handle: Some(thread_handle),
82 }
83 }
84
85 pub fn unused_addr() -> net::SocketAddr {
87 use socket2::{Domain, Protocol, Socket, Type};
88
89 let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
90 let domain = Domain::for_address(addr);
91 let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).unwrap();
92
93 socket.set_reuse_address(true).unwrap();
94 socket.set_nonblocking(true).unwrap();
95 socket.bind(&addr.into()).unwrap();
96 socket.listen(1024).unwrap();
97
98 net::TcpListener::from(socket).local_addr().unwrap()
99 }
100}
101
102impl TestServerHandle {
103 pub fn host(&self) -> &str {
105 &self.host
106 }
107
108 pub fn port(&self) -> u16 {
110 self.port
111 }
112
113 pub fn addr(&self) -> net::SocketAddr {
115 self.addr
116 }
117
118 fn stop(&mut self) {
120 drop(self.server_handle.stop(false));
121 self.thread_handle.take().unwrap().join().unwrap().unwrap();
122 }
123
124 pub fn connect(&self) -> io::Result<TcpStream> {
126 TcpStream::from_std(net::TcpStream::connect(self.addr)?)
127 }
128}
129
130impl Drop for TestServerHandle {
131 fn drop(&mut self) {
132 self.stop()
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use actix_service::fn_service;
139
140 use super::*;
141
142 #[tokio::test]
143 async fn connect_in_tokio_runtime() {
144 let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
145 assert!(srv.connect().is_ok());
146 }
147
148 #[actix_rt::test]
149 async fn connect_in_actix_runtime() {
150 let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
151 assert!(srv.connect().is_ok());
152 }
153}