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 let stream = net::TcpStream::connect(self.addr)?;
127 stream.set_nonblocking(true)?;
128 TcpStream::from_std(stream)
129 }
130}
131
132impl Drop for TestServerHandle {
133 fn drop(&mut self) {
134 self.stop()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use actix_service::fn_service;
141
142 use super::*;
143
144 #[tokio::test]
145 async fn connect_in_tokio_runtime() {
146 let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
147 assert!(srv.connect().is_ok());
148 }
149
150 #[actix_rt::test]
151 async fn connect_in_actix_runtime() {
152 let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) }));
153 assert!(srv.connect().is_ok());
154 }
155}