From bd4124587a1fae9e14a31d5ecaf050f7b454d186 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Mon, 4 Mar 2019 13:25:35 -0800 Subject: [PATCH] provide block_on function for testing purpose --- Cargo.toml | 2 +- src/app.rs | 50 +++++++------ src/extract.rs | 48 ++++--------- src/guard.rs | 74 ++++++++++--------- src/middleware/defaultheaders.rs | 16 ++--- src/responder.rs | 7 +- src/scope.rs | 118 +++++++++++++------------------ src/test.rs | 67 +++++++++++++++--- 8 files changed, 207 insertions(+), 175 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 03b1794ff..3b88c3001 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ flate2-rust = ["flate2/rust_backend"] actix-codec = "0.1.0" actix-service = "0.3.0" actix-utils = "0.3.0" +actix-rt = "0.1.0" actix-http = { git = "https://github.com/actix/actix-http.git" } actix-router = { git = "https://github.com/actix/actix-net.git" } @@ -69,7 +70,6 @@ brotli2 = { version="^0.3.2", optional = true } flate2 = { version="^1.0.2", optional = true, default-features = false } [dev-dependencies] -actix-rt = "0.1.0" actix-server = { version="0.3.0", features=["ssl"] } actix-http = { git = "https://github.com/actix/actix-http.git", features=["ssl"] } actix-http-test = { git = "https://github.com/actix/actix-http.git", features=["ssl"] } diff --git a/src/app.rs b/src/app.rs index 119f1a21e..e1479080a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -924,85 +924,95 @@ where #[cfg(test)] mod tests { - use actix_http::http::StatusCode; + use actix_http::http::{Method, StatusCode}; use super::*; - use crate::test::TestRequest; - use crate::{HttpResponse, State}; + use crate::test::{block_on, TestRequest}; + use crate::{web, HttpResponse, State}; #[test] fn test_default_resource() { - let mut rt = actix_rt::Runtime::new().unwrap(); - let app = App::new() .resource("/test", |r| r.to(|| HttpResponse::Ok())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/test").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/blah").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let app = App::new() .resource("/test", |r| r.to(|| HttpResponse::Ok())) + .resource("/test2", |r| { + r.default_resource(|r| r.to(|| HttpResponse::Created())) + .route(web::get().to(|| HttpResponse::Ok())) + }) .default_resource(|r| r.to(|| HttpResponse::MethodNotAllowed())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/blah").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); + + let req = TestRequest::with_uri("/test2").to_request(); + let resp = block_on(srv.call(req)).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + + let req = TestRequest::with_uri("/test2") + .method(Method::POST) + .to_request(); + let resp = block_on(srv.call(req)).unwrap(); + assert_eq!(resp.status(), StatusCode::CREATED); } #[test] fn test_state() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .state(10usize) .resource("/", |r| r.to(|_: State| HttpResponse::Ok())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::default().to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let app = App::new() .state(10u32) .resource("/", |r| r.to(|_: State| HttpResponse::Ok())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::default().to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } #[test] fn test_state_factory() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .state_factory(|| Ok::<_, ()>(10usize)) .resource("/", |r| r.to(|_: State| HttpResponse::Ok())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::default().to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let app = App::new() .state_factory(|| Ok::<_, ()>(10u32)) .resource("/", |r| r.to(|_: State| HttpResponse::Ok())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::default().to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); } diff --git a/src/extract.rs b/src/extract.rs index 3b5c7e742..7350d7d95 100644 --- a/src/extract.rs +++ b/src/extract.rs @@ -1152,7 +1152,7 @@ mod tests { use serde_derive::Deserialize; use super::*; - use crate::test::TestRequest; + use crate::test::{block_on, TestRequest}; #[derive(Deserialize, Debug, PartialEq)] struct Info { @@ -1161,29 +1161,26 @@ mod tests { #[test] fn test_bytes() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); - let s = rt.block_on(Bytes::from_request(&mut req)).unwrap(); + let s = block_on(Bytes::from_request(&mut req)).unwrap(); assert_eq!(s, Bytes::from_static(b"hello=world")); } #[test] fn test_string() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); - let s = rt.block_on(String::from_request(&mut req)).unwrap(); + let s = block_on(String::from_request(&mut req)).unwrap(); assert_eq!(s, "hello=world"); } #[test] fn test_form() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", @@ -1192,13 +1189,12 @@ mod tests { .set_payload(Bytes::from_static(b"hello=world")) .to_from(); - let s = rt.block_on(Form::::from_request(&mut req)).unwrap(); + let s = block_on(Form::::from_request(&mut req)).unwrap(); assert_eq!(s.hello, "world"); } #[test] fn test_option() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", @@ -1206,9 +1202,7 @@ mod tests { .config(FormConfig::default().limit(4096)) .to_from(); - let r = rt - .block_on(Option::>::from_request(&mut req)) - .unwrap(); + let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!(r, None); let mut req = TestRequest::with_header( @@ -1219,9 +1213,7 @@ mod tests { .set_payload(Bytes::from_static(b"hello=world")) .to_from(); - let r = rt - .block_on(Option::>::from_request(&mut req)) - .unwrap(); + let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!( r, Some(Form(Info { @@ -1237,15 +1229,12 @@ mod tests { .set_payload(Bytes::from_static(b"bye=world")) .to_from(); - let r = rt - .block_on(Option::>::from_request(&mut req)) - .unwrap(); + let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!(r, None); } #[test] fn test_result() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", @@ -1254,8 +1243,7 @@ mod tests { .set_payload(Bytes::from_static(b"hello=world")) .to_from(); - let r = rt - .block_on(Result::, Error>::from_request(&mut req)) + let r = block_on(Result::, Error>::from_request(&mut req)) .unwrap() .unwrap(); assert_eq!( @@ -1273,9 +1261,7 @@ mod tests { .set_payload(Bytes::from_static(b"bye=world")) .to_from(); - let r = rt - .block_on(Result::, Error>::from_request(&mut req)) - .unwrap(); + let r = block_on(Result::, Error>::from_request(&mut req)).unwrap(); assert!(r.is_err()); } @@ -1361,25 +1347,19 @@ mod tests { #[test] fn test_tuple_extract() { - let mut rt = actix_rt::Runtime::new().unwrap(); let resource = ResourceDef::new("/{key}/{value}/"); let mut req = TestRequest::with_uri("/name/user1/?id=test").to_from(); resource.match_path(req.match_info_mut()); - let res = rt - .block_on(<(Path<(String, String)>,)>::from_request(&mut req)) - .unwrap(); + let res = block_on(<(Path<(String, String)>,)>::from_request(&mut req)).unwrap(); assert_eq!((res.0).0, "name"); assert_eq!((res.0).1, "user1"); - let res = rt - .block_on( - <(Path<(String, String)>, Path<(String, String)>)>::from_request( - &mut req, - ), - ) - .unwrap(); + let res = block_on( + <(Path<(String, String)>, Path<(String, String)>)>::from_request(&mut req), + ) + .unwrap(); assert_eq!((res.0).0, "name"); assert_eq!((res.0).1, "user1"); assert_eq!((res.1).0, "name"); diff --git a/src/guard.rs b/src/guard.rs index c8948b3b2..93b6e1325 100644 --- a/src/guard.rs +++ b/src/guard.rs @@ -239,8 +239,7 @@ mod tests { #[test] fn test_header() { let req = TestRequest::with_header(header::TRANSFER_ENCODING, "chunked") - .finish() - .into_request(); + .to_http_request(); let pred = Header("transfer-encoding", "chunked"); assert!(pred.check(&req)); @@ -270,44 +269,55 @@ mod tests { #[test] fn test_methods() { - let req = TestRequest::default().finish().into_request(); + let req = TestRequest::default().to_http_request(); let req2 = TestRequest::default() .method(Method::POST) - .finish() - .into_request(); + .to_http_request(); assert!(Get().check(&req)); assert!(!Get().check(&req2)); assert!(Post().check(&req2)); assert!(!Post().check(&req)); - let r = TestRequest::default().method(Method::PUT).finish(); - assert!(Put().check(&r,)); - assert!(!Put().check(&req,)); + let r = TestRequest::default().method(Method::PUT).to_http_request(); + assert!(Put().check(&r)); + assert!(!Put().check(&req)); - let r = TestRequest::default().method(Method::DELETE).finish(); - assert!(Delete().check(&r,)); - assert!(!Delete().check(&req,)); + let r = TestRequest::default() + .method(Method::DELETE) + .to_http_request(); + assert!(Delete().check(&r)); + assert!(!Delete().check(&req)); - let r = TestRequest::default().method(Method::HEAD).finish(); - assert!(Head().check(&r,)); - assert!(!Head().check(&req,)); + let r = TestRequest::default() + .method(Method::HEAD) + .to_http_request(); + assert!(Head().check(&r)); + assert!(!Head().check(&req)); - let r = TestRequest::default().method(Method::OPTIONS).finish(); - assert!(Options().check(&r,)); - assert!(!Options().check(&req,)); + let r = TestRequest::default() + .method(Method::OPTIONS) + .to_http_request(); + assert!(Options().check(&r)); + assert!(!Options().check(&req)); - let r = TestRequest::default().method(Method::CONNECT).finish(); - assert!(Connect().check(&r,)); - assert!(!Connect().check(&req,)); + let r = TestRequest::default() + .method(Method::CONNECT) + .to_http_request(); + assert!(Connect().check(&r)); + assert!(!Connect().check(&req)); - let r = TestRequest::default().method(Method::PATCH).finish(); - assert!(Patch().check(&r,)); - assert!(!Patch().check(&req,)); + let r = TestRequest::default() + .method(Method::PATCH) + .to_http_request(); + assert!(Patch().check(&r)); + assert!(!Patch().check(&req)); - let r = TestRequest::default().method(Method::TRACE).finish(); - assert!(Trace().check(&r,)); - assert!(!Trace().check(&req,)); + let r = TestRequest::default() + .method(Method::TRACE) + .to_http_request(); + assert!(Trace().check(&r)); + assert!(!Trace().check(&req)); } #[test] @@ -316,13 +326,13 @@ mod tests { .method(Method::TRACE) .to_http_request(); - assert!(Not(Get()).check(&r,)); - assert!(!Not(Trace()).check(&r,)); + assert!(Not(Get()).check(&r)); + assert!(!Not(Trace()).check(&r)); - assert!(All(Trace()).and(Trace()).check(&r,)); - assert!(!All(Get()).and(Trace()).check(&r,)); + assert!(All(Trace()).and(Trace()).check(&r)); + assert!(!All(Get()).and(Trace()).check(&r)); - assert!(Any(Get()).or(Trace()).check(&r,)); - assert!(!Any(Get()).or(Get()).check(&r,)); + assert!(Any(Get()).or(Trace()).check(&r)); + assert!(!Any(Get()).or(Get()).check(&r)); } } diff --git a/src/middleware/defaultheaders.rs b/src/middleware/defaultheaders.rs index fa287b288..40bf9f1cc 100644 --- a/src/middleware/defaultheaders.rs +++ b/src/middleware/defaultheaders.rs @@ -138,39 +138,37 @@ mod tests { use actix_service::FnService; use super::*; - use crate::test::TestRequest; + use crate::test::{block_on, TestRequest}; use crate::{HttpResponse, ServiceRequest}; #[test] fn test_default_headers() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut mw = DefaultHeaders::new().header(CONTENT_TYPE, "0001"); let mut srv = FnService::new(|req: ServiceRequest<_>| { req.into_response(HttpResponse::Ok().finish()) }); - let req = TestRequest::default().finish(); - let resp = rt.block_on(mw.call(req, &mut srv)).unwrap(); + let req = TestRequest::default().to_service(); + let resp = block_on(mw.call(req, &mut srv)).unwrap(); assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001"); - let req = TestRequest::default().finish(); + let req = TestRequest::default().to_service(); let mut srv = FnService::new(|req: ServiceRequest<_>| { req.into_response(HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish()) }); - let resp = rt.block_on(mw.call(req, &mut srv)).unwrap(); + let resp = block_on(mw.call(req, &mut srv)).unwrap(); assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0002"); } #[test] fn test_content_type() { - let mut rt = actix_rt::Runtime::new().unwrap(); let mut mw = DefaultHeaders::new().content_type(); let mut srv = FnService::new(|req: ServiceRequest<_>| { req.into_response(HttpResponse::Ok().finish()) }); - let req = TestRequest::default().finish(); - let resp = rt.block_on(mw.call(req, &mut srv)).unwrap(); + let req = TestRequest::default().to_service(); + let resp = block_on(mw.call(req, &mut srv)).unwrap(); assert_eq!( resp.headers().get(CONTENT_TYPE).unwrap(), "application/octet-stream" diff --git a/src/responder.rs b/src/responder.rs index 8e7f66b43..b2fd848f0 100644 --- a/src/responder.rs +++ b/src/responder.rs @@ -286,19 +286,18 @@ mod tests { #[test] fn test_option_responder() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .resource("/none", |r| r.to(|| -> Option<&'static str> { None })) .resource("/some", |r| r.to(|| Some("some"))) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = TestRequest::block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/none").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = TestRequest::block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/some").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = TestRequest::block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); match resp.body() { ResponseBody::Body(Body::Bytes(ref b)) => { diff --git a/src/scope.rs b/src/scope.rs index 2ed18a423..7aeb50412 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -32,14 +32,14 @@ type BoxedResponse = Box>; /// `Path` extractor also is able to extract scope level variable segments. /// /// ```rust -/// use actix_web::{App, HttpResponse}; +/// use actix_web::{web, App, HttpResponse}; /// /// fn main() { /// let app = App::new().scope("/{project_id}/", |scope| { /// scope /// .resource("/path1", |r| r.to(|| HttpResponse::Ok())) -/// .resource("/path2", |r| r.to(|| HttpResponse::Ok())) -/// .resource("/path3", |r| r.to(|| HttpResponse::MethodNotAllowed())) +/// .resource("/path2", |r| r.route(web::get().to(|| HttpResponse::Ok()))) +/// .resource("/path3", |r| r.route(web::head().to(|| HttpResponse::MethodNotAllowed()))) /// }); /// } /// ``` @@ -512,27 +512,25 @@ mod tests { use actix_service::{IntoNewService, NewService, Service}; use bytes::Bytes; - use crate::test::TestRequest; + use crate::test::{block_on, TestRequest}; use crate::{guard, web, App, HttpRequest, HttpResponse}; #[test] fn test_scope() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.resource("/path1", |r| r.to(|| HttpResponse::Ok())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); } #[test] fn test_scope_root() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope @@ -540,58 +538,55 @@ mod tests { .resource("/", |r| r.to(|| HttpResponse::Created())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); } #[test] fn test_scope_root2() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app/", |scope| { scope.resource("", |r| r.to(|| HttpResponse::Ok())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); } #[test] fn test_scope_root3() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app/", |scope| { scope.resource("/", |r| r.to(|| HttpResponse::Ok())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_scope_route() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("app", |scope| { scope.resource("/path1", |r| { @@ -600,28 +595,27 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/path1") .method(Method::DELETE) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/path1") .method(Method::POST) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_scope_route_without_leading_slash() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("app", |scope| { scope.resource("path1", |r| { @@ -630,28 +624,27 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/path1") .method(Method::DELETE) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/path1") .method(Method::POST) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_scope_guard() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope @@ -659,24 +652,23 @@ mod tests { .resource("/path1", |r| r.to(|| HttpResponse::Ok())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/path1") .method(Method::POST) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/path1") .method(Method::GET) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); } #[test] fn test_scope_variable_segment() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/ab-{project}", |scope| { scope.resource("/path1", |r| { @@ -687,10 +679,10 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/ab-project1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); match resp.body() { @@ -702,13 +694,12 @@ mod tests { } let req = TestRequest::with_uri("/aa-project1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_nested_scope() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("/t1", |scope| { @@ -716,16 +707,15 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/t1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); } #[test] fn test_nested_scope_no_slash() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("t1", |scope| { @@ -733,16 +723,15 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/t1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); } #[test] fn test_nested_scope_root() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("/t1", |scope| { @@ -752,20 +741,19 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/t1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); let req = TestRequest::with_uri("/app/t1/").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); } #[test] fn test_nested_scope_filter() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("/t1", |scope| { @@ -775,24 +763,23 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/t1/path1") .method(Method::POST) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/t1/path1") .method(Method::GET) .to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::OK); } #[test] fn test_nested_scope_with_variable_segment() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("/{project_id}", |scope| { @@ -807,10 +794,10 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/project_1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); match resp.body() { @@ -824,7 +811,6 @@ mod tests { #[test] fn test_nested2_scope_with_variable_segment() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope.nested("/{project}", |scope| { @@ -842,10 +828,10 @@ mod tests { }) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/test/1/path1").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::CREATED); match resp.body() { @@ -857,13 +843,12 @@ mod tests { } let req = TestRequest::with_uri("/app/test/1/path2").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_default_resource() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app", |scope| { scope @@ -871,20 +856,19 @@ mod tests { .default_resource(|r| r.to(|| HttpResponse::BadRequest())) }) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/app/path2").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); let req = TestRequest::with_uri("/path2").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); } #[test] fn test_default_resource_propagation() { - let mut rt = actix_rt::Runtime::new().unwrap(); let app = App::new() .scope("/app1", |scope| { scope.default_resource(|r| r.to(|| HttpResponse::BadRequest())) @@ -892,18 +876,18 @@ mod tests { .scope("/app2", |scope| scope) .default_resource(|r| r.to(|| HttpResponse::MethodNotAllowed())) .into_new_service(); - let mut srv = rt.block_on(app.new_service(&())).unwrap(); + let mut srv = block_on(app.new_service(&())).unwrap(); let req = TestRequest::with_uri("/non-exist").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); let req = TestRequest::with_uri("/app1/non-exist").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::BAD_REQUEST); let req = TestRequest::with_uri("/app2/non-exist").to_request(); - let resp = rt.block_on(srv.call(req)).unwrap(); + let resp = block_on(srv.call(req)).unwrap(); assert_eq!(resp.status(), StatusCode::METHOD_NOT_ALLOWED); } } diff --git a/src/test.rs b/src/test.rs index 684817ec1..7ceedacc4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,4 +1,5 @@ //! Various helpers for Actix applications to use during testing. +use std::cell::RefCell; use std::rc::Rc; use actix_http::http::header::{Header, HeaderName, IntoHeaderValue}; @@ -6,16 +7,47 @@ use actix_http::http::{HttpTryFrom, Method, Version}; use actix_http::test::TestRequest as HttpTestRequest; use actix_http::{Extensions, PayloadStream, Request}; use actix_router::{Path, Url}; +use actix_rt::Runtime; use bytes::Bytes; +use futures::Future; use crate::request::HttpRequest; use crate::service::{ServiceFromRequest, ServiceRequest}; -/// Test `Request` builder +thread_local! { + static RT: RefCell = { + RefCell::new(Runtime::new().unwrap()) + }; +} + +/// Runs the provided future, blocking the current thread until the future +/// completes. +/// +/// This function can be used to synchronously block the current thread +/// until the provided `future` has resolved either successfully or with an +/// error. The result of the future is then returned from this function +/// call. +/// +/// Note that this function is intended to be used only for testing purpose. +/// This function panics on nested call. +pub fn block_on(f: F) -> Result +where + F: Future, +{ + RT.with(move |rt| rt.borrow_mut().block_on(f)) +} + +/// Test `Request` builder. +/// +/// For unit testing, actix provides a request builder type and a simple handler runner. TestRequest implements a builder-like pattern. +/// You can generate various types of request via TestRequest's methods: +/// * `TestRequest::to_request` creates `actix_http::Request` instance. +/// * `TestRequest::to_service` creates `ServiceRequest` instance, which is used for testing middlewares and chain adapters. +/// * `TestRequest::to_from` creates `ServiceFromRequest` instance, which is used for testing extractors. +/// * `TestRequest::to_http_request` creates `HttpRequest` instance, which is used for testing handlers. /// /// ```rust,ignore -/// # use actix_web::*; -/// use actix_web::test::TestRequest; +/// use actix_web::test; /// /// fn index(req: HttpRequest) -> HttpResponse { /// if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) { @@ -26,12 +58,14 @@ use crate::service::{ServiceFromRequest, ServiceRequest}; /// } /// /// fn main() { -/// let resp = TestRequest::with_header("content-type", "text/plain") -/// .run(&index) -/// .unwrap(); +/// let req = test::TestRequest::with_header("content-type", "text/plain") +/// .to_http_request(); +/// +/// let resp = test::block_on(index(req)); /// assert_eq!(resp.status(), StatusCode::OK); /// -/// let resp = TestRequest::default().run(&index).unwrap(); +/// let req = test::TestRequest::default().to_http_request(); +/// let resp = test::block_on(index(req)); /// assert_eq!(resp.status(), StatusCode::BAD_REQUEST); /// } /// ``` @@ -125,7 +159,7 @@ impl TestRequest { } /// Complete request creation and generate `ServiceRequest` instance - pub fn finish(mut self) -> ServiceRequest { + pub fn to_service(mut self) -> ServiceRequest { let req = self.req.finish(); ServiceRequest::new( @@ -163,4 +197,21 @@ impl TestRequest { ); ServiceFromRequest::new(req, None) } + + /// Runs the provided future, blocking the current thread until the future + /// completes. + /// + /// This function can be used to synchronously block the current thread + /// until the provided `future` has resolved either successfully or with an + /// error. The result of the future is then returned from this function + /// call. + /// + /// Note that this function is intended to be used only for testing purpose. + /// This function panics on nested call. + pub fn block_on(f: F) -> Result + where + F: Future, + { + block_on(f) + } }