diff --git a/src/responder.rs b/src/responder.rs index 6dce300a..ace360c6 100644 --- a/src/responder.rs +++ b/src/responder.rs @@ -261,7 +261,8 @@ where type Future = Result; fn respond_to(self, _: &HttpRequest) -> Self::Future { - Err(self.into()) + let err: Error = self.into(); + Ok(err.into()) } } @@ -289,12 +290,13 @@ where #[cfg(test)] mod tests { use actix_service::Service; - use bytes::Bytes; + use bytes::{Bytes, BytesMut}; + use super::*; use crate::dev::{Body, ResponseBody}; - use crate::http::StatusCode; - use crate::test::{init_service, TestRequest}; - use crate::{web, App}; + use crate::http::{header::CONTENT_TYPE, HeaderValue, StatusCode}; + use crate::test::{block_on, init_service, TestRequest}; + use crate::{error, web, App, HttpResponse}; #[test] fn test_option_responder() { @@ -319,4 +321,87 @@ mod tests { _ => panic!(), } } + + trait BodyTest { + fn bin_ref(&self) -> &[u8]; + fn body(&self) -> &Body; + } + + impl BodyTest for ResponseBody { + fn bin_ref(&self) -> &[u8] { + match self { + ResponseBody::Body(ref b) => match b { + Body::Bytes(ref bin) => &bin, + _ => panic!(), + }, + ResponseBody::Other(ref b) => match b { + Body::Bytes(ref bin) => &bin, + _ => panic!(), + }, + } + } + fn body(&self) -> &Body { + match self { + ResponseBody::Body(ref b) => b, + ResponseBody::Other(ref b) => b, + } + } + } + + #[test] + fn test_responder() { + let req = TestRequest::default().to_http_request(); + + let resp: HttpResponse = block_on(().respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(*resp.body().body(), Body::Empty); + + let resp: HttpResponse = block_on("test".respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(resp.body().bin_ref(), b"test"); + assert_eq!( + resp.headers().get(CONTENT_TYPE).unwrap(), + HeaderValue::from_static("text/plain; charset=utf-8") + ); + + let resp: HttpResponse = block_on(b"test".respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(resp.body().bin_ref(), b"test"); + assert_eq!( + resp.headers().get(CONTENT_TYPE).unwrap(), + HeaderValue::from_static("application/octet-stream") + ); + + let resp: HttpResponse = block_on("test".to_string().respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(resp.body().bin_ref(), b"test"); + assert_eq!( + resp.headers().get(CONTENT_TYPE).unwrap(), + HeaderValue::from_static("text/plain; charset=utf-8") + ); + + let resp: HttpResponse = + block_on(Bytes::from_static(b"test").respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(resp.body().bin_ref(), b"test"); + assert_eq!( + resp.headers().get(CONTENT_TYPE).unwrap(), + HeaderValue::from_static("application/octet-stream") + ); + + let resp: HttpResponse = + block_on(BytesMut::from(b"test".as_ref()).respond_to(&req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + assert_eq!(resp.body().bin_ref(), b"test"); + assert_eq!( + resp.headers().get(CONTENT_TYPE).unwrap(), + HeaderValue::from_static("application/octet-stream") + ); + + let resp: HttpResponse = + error::InternalError::new("err", StatusCode::BAD_REQUEST) + .respond_to(&req) + .unwrap(); + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + } } diff --git a/src/server.rs b/src/server.rs index f80e5a0e..9055be30 100644 --- a/src/server.rs +++ b/src/server.rs @@ -182,8 +182,8 @@ where /// Host name is used by application router aa a hostname for url /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. /// html#method.host) documentation for more information. - pub fn server_hostname(mut self, val: String) -> Self { - self.host = Some(val); + pub fn server_hostname>(mut self, val: T) -> Self { + self.host = Some(val.as_ref().to_owned()); self } diff --git a/src/test.rs b/src/test.rs index 03700b67..57a6d396 100644 --- a/src/test.rs +++ b/src/test.rs @@ -12,7 +12,7 @@ use actix_server_config::ServerConfig; use actix_service::{IntoNewService, NewService, Service}; use bytes::Bytes; use cookie::Cookie; -use futures::Future; +use futures::future::{lazy, Future}; use crate::config::{AppConfig, AppConfigInner}; use crate::rmap::ResourceMap; @@ -42,6 +42,17 @@ where RT.with(move |rt| rt.borrow_mut().block_on(f)) } +/// Runs the provided function, with runtime enabled. +/// +/// Note that this function is intended to be used only for testing purpose. +/// This function panics on nested call. +pub fn run_on(f: F) -> Result +where + F: Fn() -> Result, +{ + RT.with(move |rt| rt.borrow_mut().block_on(lazy(|| f()))) +} + /// This method accepts application builder instance, and constructs /// service. /// diff --git a/tests/test_httpserver.rs b/tests/test_httpserver.rs new file mode 100644 index 00000000..d2bc07ac --- /dev/null +++ b/tests/test_httpserver.rs @@ -0,0 +1,75 @@ +use net2::TcpBuilder; +use std::sync::mpsc; +use std::{net, thread, time::Duration}; + +use actix_http::{client, Response}; + +use actix_web::{test, web, App, HttpServer}; + +fn unused_addr() -> net::SocketAddr { + let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap(); + let socket = TcpBuilder::new_v4().unwrap(); + socket.bind(&addr).unwrap(); + socket.reuse_address(true).unwrap(); + let tcp = socket.to_tcp_listener().unwrap(); + tcp.local_addr().unwrap() +} + +#[test] +#[cfg(unix)] +fn test_start() { + let addr = unused_addr(); + let (tx, rx) = mpsc::channel(); + + thread::spawn(move || { + let sys = actix_rt::System::new("test"); + + let srv = HttpServer::new(|| { + App::new().service( + web::resource("/").route(web::to(|| Response::Ok().body("test"))), + ) + }) + .workers(1) + .backlog(1) + .maxconn(10) + .maxconnrate(10) + .keep_alive(10) + .client_timeout(5000) + .client_shutdown(0) + .server_hostname("localhost") + .system_exit() + .disable_signals() + .bind(format!("{}", addr)) + .unwrap() + .start(); + + let _ = tx.send((srv, actix_rt::System::current())); + let _ = sys.run(); + }); + let (srv, sys) = rx.recv().unwrap(); + + let mut connector = test::run_on(|| { + Ok::<_, ()>( + client::Connector::default() + .timeout(Duration::from_millis(100)) + .service(), + ) + }) + .unwrap(); + let host = format!("http://{}", addr); + + let response = test::block_on( + client::ClientRequest::get(host.clone()) + .finish() + .unwrap() + .send(&mut connector), + ) + .unwrap(); + assert!(response.status().is_success()); + + // stop + let _ = srv.stop(false); + + thread::sleep(Duration::from_millis(100)); + let _ = sys.stop(); +}