From 01d2f18f681194f6127790d10576ce00fa39c6f8 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 27 Dec 2021 18:27:54 +0000 Subject: [PATCH] simplify test server (#431) --- actix-server/CHANGES.md | 3 + actix-server/src/builder.rs | 3 +- actix-server/src/test_server.rs | 76 ++++++++----------- .../tests/{test_server.rs => server.rs} | 61 --------------- actix-server/tests/testing_server.rs | 73 ++++++++++++++++++ actix-tls/tests/accept-openssl.rs | 2 +- actix-tls/tests/accept-rustls.rs | 2 +- actix-tls/tests/test_connect.rs | 14 ++-- actix-tls/tests/test_resolvers.rs | 2 +- 9 files changed, 120 insertions(+), 116 deletions(-) rename actix-server/tests/{test_server.rs => server.rs} (90%) create mode 100644 actix-server/tests/testing_server.rs diff --git a/actix-server/CHANGES.md b/actix-server/CHANGES.md index 55e175cc9f..e08804fdb8 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 7a6123ef6d..805c6e75c3 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 16820f3ec3..67659948cc 100644 --- a/actix-server/src/test_server.rs +++ b/actix-server/src/test_server.rs @@ -16,7 +16,7 @@ use crate::{Server, ServerBuilder, ServerHandle, ServerServiceFactory}; /// /// #[actix_rt::main] /// async fn main() { -/// let srv = TestServer::with(|| fn_service( +/// let srv = TestServer::start(|| fn_service( /// |sock| async move { /// println!("New connection: {:?}", sock); /// Ok::<_, ()>(()) @@ -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 5b988847bc..0a70402b6d 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 0000000000..921caa0578 --- /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::start_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(); +} diff --git a/actix-tls/tests/accept-openssl.rs b/actix-tls/tests/accept-openssl.rs index 3d195b040b..4b6fadf0a9 100644 --- a/actix-tls/tests/accept-openssl.rs +++ b/actix-tls/tests/accept-openssl.rs @@ -94,7 +94,7 @@ fn rustls_connector(_cert: String, _key: String) -> ClientConfig { async fn accepts_connections() { let (cert, key) = new_cert_and_key(); - let srv = TestServer::with({ + let srv = TestServer::start({ let cert = cert.clone(); let key = key.clone(); diff --git a/actix-tls/tests/accept-rustls.rs b/actix-tls/tests/accept-rustls.rs index 2c922a68c2..521af7f962 100644 --- a/actix-tls/tests/accept-rustls.rs +++ b/actix-tls/tests/accept-rustls.rs @@ -74,7 +74,7 @@ fn openssl_connector(cert: String, key: String) -> SslConnector { async fn accepts_connections() { let (cert, key) = new_cert_and_key(); - let srv = TestServer::with({ + let srv = TestServer::start({ let cert = cert.clone(); let key = key.clone(); diff --git a/actix-tls/tests/test_connect.rs b/actix-tls/tests/test_connect.rs index d3373c9001..bdd6b49cff 100644 --- a/actix-tls/tests/test_connect.rs +++ b/actix-tls/tests/test_connect.rs @@ -17,7 +17,7 @@ use actix_tls::connect::{ConnectError, ConnectInfo, Connection, Connector, Host} #[cfg(feature = "openssl")] #[actix_rt::test] async fn test_string() { - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -34,7 +34,7 @@ async fn test_string() { #[cfg(feature = "rustls")] #[actix_rt::test] async fn test_rustls_string() { - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -50,7 +50,7 @@ async fn test_rustls_string() { #[actix_rt::test] async fn test_static_str() { - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -81,7 +81,7 @@ async fn service_factory() { Connector::default() } - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -101,7 +101,7 @@ async fn service_factory() { async fn test_openssl_uri() { use std::convert::TryFrom; - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -120,7 +120,7 @@ async fn test_openssl_uri() { async fn test_rustls_uri() { use std::convert::TryFrom; - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; @@ -136,7 +136,7 @@ async fn test_rustls_uri() { #[actix_rt::test] async fn test_local_addr() { - let srv = TestServer::with(|| { + let srv = TestServer::start(|| { fn_service(|io: TcpStream| async { let mut framed = Framed::new(io, BytesCodec); framed.send(Bytes::from_static(b"test")).await?; diff --git a/actix-tls/tests/test_resolvers.rs b/actix-tls/tests/test_resolvers.rs index 987b229c67..81bbec545a 100644 --- a/actix-tls/tests/test_resolvers.rs +++ b/actix-tls/tests/test_resolvers.rs @@ -53,7 +53,7 @@ async fn custom_resolver_connect() { use trust_dns_resolver::TokioAsyncResolver; let srv = - TestServer::with(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) })); + TestServer::start(|| fn_service(|_io: TcpStream| async { Ok::<_, io::Error>(()) })); struct MyResolver { trust_dns: TokioAsyncResolver,