diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 55e175cc..e08804fd 100644 --- a/actix-server/CHANGES.md +++ b/actix-server/CHANGES.md @@ -1,6 +1,9 @@ # Changes ## Unreleased - 2021-xx-xx +- Simplify `TestServer`. [#431] + +[#431]: https://github.com/actix/actix-net/pull/431 ## 2.0.0-rc.1 - 2021-12-05 diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index 7a6123ef..805c6e75 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -140,10 +140,11 @@ impl ServerBuilder { } /// Add new service to the server. - pub fn bind>(mut self, name: N, addr: U, factory: F) -> io::Result + pub fn bind(mut self, name: N, addr: U, factory: F) -> io::Result where F: ServerServiceFactory, U: ToSocketAddrs, + N: AsRef, { let sockets = bind_addr(addr, self.backlog)?; diff --git a/actix-server/src/test_server.rs b/actix-server/src/test_server.rs index 16820f3e..78b415d3 100644 --- a/actix-server/src/test_server.rs +++ b/actix-server/src/test_server.rs @@ -28,8 +28,8 @@ use crate::{Server, ServerBuilder, ServerHandle, ServerServiceFactory}; /// ``` pub struct TestServer; -/// Test server runtime -pub struct TestServerRuntime { +/// Test server handle. +pub struct TestServerHandle { addr: net::SocketAddr, host: String, port: u16, @@ -38,46 +38,26 @@ pub struct TestServerRuntime { } impl TestServer { - /// Start new server with server builder. - pub fn start(mut factory: F) -> TestServerRuntime - where - F: FnMut(ServerBuilder) -> ServerBuilder + Send + 'static, - { - let (tx, rx) = mpsc::channel(); - - // run server in separate thread - let thread_handle = thread::spawn(move || { - System::new().block_on(async { - let server = factory(Server::build()).workers(1).disable_signals().run(); - tx.send(server.handle()).unwrap(); - server.await - }) - }); - - let server_handle = rx.recv().unwrap(); - - TestServerRuntime { - addr: "127.0.0.1:0".parse().unwrap(), - host: "127.0.0.1".to_string(), - port: 0, - server_handle, - thread_handle: Some(thread_handle), - } + /// Start new `TestServer` using application factory and default server config. + pub fn start(factory: impl ServerServiceFactory) -> TestServerHandle { + Self::start_with_builder(Server::build(), factory) } - /// Start new test server with application factory. - pub fn with>(factory: F) -> TestServerRuntime { + /// Start new `TestServer` using application factory and server builder. + pub fn start_with_builder( + server_builder: ServerBuilder, + factory: impl ServerServiceFactory, + ) -> TestServerHandle { let (tx, rx) = mpsc::channel(); // run server in separate thread let thread_handle = thread::spawn(move || { - let sys = System::new(); - let tcp = net::TcpListener::bind("127.0.0.1:0").unwrap(); - let local_addr = tcp.local_addr().unwrap(); + let lst = net::TcpListener::bind("127.0.0.1:0").unwrap(); + let local_addr = lst.local_addr().unwrap(); - sys.block_on(async { - let server = Server::build() - .listen("test", tcp, factory) + System::new().block_on(async { + let server = server_builder + .listen("test", lst, factory) .unwrap() .workers(1) .disable_signals() @@ -93,7 +73,7 @@ impl TestServer { let host = format!("{}", addr.ip()); let port = addr.port(); - TestServerRuntime { + TestServerHandle { addr, host, port, @@ -107,17 +87,19 @@ impl TestServer { use socket2::{Domain, Protocol, Socket, Type}; let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); - let socket = - Socket::new(Domain::for_address(addr), Type::STREAM, Some(Protocol::TCP)).unwrap(); + let domain = Domain::for_address(addr); + let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).unwrap(); + socket.set_reuse_address(true).unwrap(); socket.set_nonblocking(true).unwrap(); socket.bind(&addr.into()).unwrap(); socket.listen(1024).unwrap(); + net::TcpListener::from(socket).local_addr().unwrap() } } -impl TestServerRuntime { +impl TestServerHandle { /// Test server host. pub fn host(&self) -> &str { &self.host @@ -140,12 +122,12 @@ impl TestServerRuntime { } /// Connect to server, returning a Tokio `TcpStream`. - pub fn connect(&self) -> std::io::Result { + pub fn connect(&self) -> io::Result { TcpStream::from_std(net::TcpStream::connect(self.addr)?) } } -impl Drop for TestServerRuntime { +impl Drop for TestServerHandle { fn drop(&mut self) { self.stop() } @@ -158,8 +140,14 @@ mod tests { use super::*; #[tokio::test] - async fn plain_tokio_runtime() { - let srv = TestServer::with(|| fn_service(|_sock| async move { Ok::<_, ()>(()) })); + async fn connect_in_tokio_runtime() { + let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) })); + assert!(srv.connect().is_ok()); + } + + #[actix_rt::test] + async fn connect_in_actix_runtime() { + let srv = TestServer::start(|| fn_service(|_sock| async move { Ok::<_, ()>(()) })); assert!(srv.connect().is_ok()); } } diff --git a/actix-server/tests/test_server.rs b/actix-server/tests/server.rs similarity index 90% rename from actix-server/tests/test_server.rs rename to actix-server/tests/server.rs index 5b988847..0a70402b 100644 --- a/actix-server/tests/test_server.rs +++ b/actix-server/tests/server.rs @@ -79,35 +79,6 @@ fn test_listen() { h.join().unwrap().unwrap(); } -// #[test] -// fn test_bind() { -// let addr = unused_addr(); -// let (tx, rx) = mpsc::channel(); - -// let h = thread::spawn(move || { -// actix_rt::System::new().block_on(async { -// let srv = Server::build() -// .workers(1) -// .disable_signals() -// .bind("test", addr, move || { -// fn_service(|_| async { Ok::<_, ()>(()) }) -// })? -// .run(); - -// let _ = tx.send(srv.handle()); - -// srv.await -// }) -// }); -// let srv = rx.recv().unwrap(); - -// thread::sleep(Duration::from_millis(500)); -// assert!(net::TcpStream::connect(addr).is_ok()); - -// let _ = srv.stop(true); -// h.join().unwrap().unwrap(); -// } - #[test] fn plain_tokio_runtime() { let addr = unused_addr(); @@ -143,38 +114,6 @@ fn plain_tokio_runtime() { h.join().unwrap().unwrap(); } -// #[test] -// fn test_listen() { -// let addr = unused_addr(); -// let lst = net::TcpListener::bind(addr).unwrap(); - -// let (tx, rx) = mpsc::channel(); - -// let h = thread::spawn(move || { -// actix_rt::System::new().block_on(async { -// let srv = Server::build() -// .disable_signals() -// .workers(1) -// .listen("test", lst, move || { -// fn_service(|_| async { Ok::<_, ()>(()) }) -// })? -// .run(); - -// let _ = tx.send(srv.handle()); - -// srv.await -// }) -// }); - -// let srv = rx.recv().unwrap(); - -// thread::sleep(Duration::from_millis(500)); -// assert!(net::TcpStream::connect(addr).is_ok()); - -// let _ = srv.stop(true); -// h.join().unwrap().unwrap(); -// } - #[test] #[cfg(unix)] fn test_start() { diff --git a/actix-server/tests/testing_server.rs b/actix-server/tests/testing_server.rs new file mode 100644 index 00000000..fed7ebf7 --- /dev/null +++ b/actix-server/tests/testing_server.rs @@ -0,0 +1,73 @@ +use std::net; + +use actix_rt::net::TcpStream; +use actix_server::{Server, TestServer}; +use actix_service::fn_service; +use bytes::BytesMut; +use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _}; + +macro_rules! await_timeout_ms { + ($fut:expr, $limit:expr) => { + ::actix_rt::time::timeout(::std::time::Duration::from_millis($limit), $fut) + .await + .unwrap() + .unwrap(); + }; +} + +#[tokio::test] +async fn testing_server_echo() { + let srv = TestServer::start(|| { + fn_service(move |mut stream: TcpStream| async move { + let mut size = 0; + let mut buf = BytesMut::new(); + + match stream.read_buf(&mut buf).await { + Ok(0) => return Err(()), + + Ok(bytes_read) => { + stream.write_all(&buf[size..]).await.unwrap(); + size += bytes_read; + } + + Err(_) => return Err(()), + } + + Ok((buf.freeze(), size)) + }) + }); + + let mut conn = srv.connect().unwrap(); + + await_timeout_ms!(conn.write_all(b"test"), 200); + + let mut buf = Vec::new(); + await_timeout_ms!(conn.read_to_end(&mut buf), 200); + + assert_eq!(&buf, b"test".as_ref()); +} + +#[tokio::test] +async fn new_with_builder() { + let alt_addr = TestServer::unused_addr(); + + let srv = TestServer::with_builder( + Server::build() + .bind("alt", alt_addr, || { + fn_service(|_| async { Ok::<_, ()>(()) }) + }) + .unwrap(), + || { + fn_service(|mut sock: TcpStream| async move { + let mut buf = [0u8; 16]; + sock.read_exact(&mut buf).await + }) + }, + ); + + // connect to test server + srv.connect().unwrap(); + + // connect to alt service defined in custom ServerBuilder + TcpStream::from_std(net::TcpStream::connect(alt_addr).unwrap()).unwrap(); +}