mirror of
https://github.com/actix/actix-web.git
synced 2025-01-03 13:58:44 +00:00
add test runtime macro (#2409)
This commit is contained in:
parent
ad22cc4e7f
commit
591abc37c3
19 changed files with 94 additions and 43 deletions
|
@ -67,7 +67,7 @@ __compress = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0"
|
actix-codec = "0.4.0"
|
||||||
actix-macros = "0.2.1"
|
actix-macros = "0.2.3"
|
||||||
actix-router = "0.5.0-beta.2"
|
actix-router = "0.5.0-beta.2"
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-server = "2.0.0-beta.3"
|
actix-server = "2.0.0-beta.3"
|
||||||
|
|
|
@ -83,7 +83,7 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_web::test]
|
||||||
async fn test_file_extension_to_mime() {
|
async fn test_file_extension_to_mime() {
|
||||||
let m = file_extension_to_mime("");
|
let m = file_extension_to_mime("");
|
||||||
assert_eq!(m, mime::APPLICATION_OCTET_STREAM);
|
assert_eq!(m, mime::APPLICATION_OCTET_STREAM);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use actix_web::{
|
||||||
App,
|
App,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_web::test]
|
||||||
async fn test_utf8_file_contents() {
|
async fn test_utf8_file_contents() {
|
||||||
// use default ISO-8859-1 encoding
|
// use default ISO-8859-1 encoding
|
||||||
let srv = test::init_service(App::new().service(Files::new("/", "./tests"))).await;
|
let srv = test::init_service(App::new().service(Files::new("/", "./tests"))).await;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use actix_web::{
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_web::test]
|
||||||
async fn test_guard_filter() {
|
async fn test_guard_filter() {
|
||||||
let srv = test::init_service(
|
let srv = test::init_service(
|
||||||
App::new()
|
App::new()
|
||||||
|
|
|
@ -36,7 +36,7 @@ use socket2::{Domain, Protocol, Socket, Type};
|
||||||
/// Ok(HttpResponse::Ok().into())
|
/// Ok(HttpResponse::Ok().into())
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_example() {
|
/// async fn test_example() {
|
||||||
/// let mut srv = TestServer::start(
|
/// let mut srv = TestServer::start(
|
||||||
/// || HttpService::new(
|
/// || HttpService::new(
|
||||||
|
|
|
@ -186,6 +186,7 @@ where
|
||||||
let mut conn = None;
|
let mut conn = None;
|
||||||
|
|
||||||
// check if there is idle connection for given key.
|
// check if there is idle connection for given key.
|
||||||
|
#[allow(clippy::must_not_suspend)]
|
||||||
let mut map = inner.available.borrow_mut();
|
let mut map = inner.available.borrow_mut();
|
||||||
|
|
||||||
if let Some(conns) = map.get_mut(&key) {
|
if let Some(conns) = map.get_mut(&key) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ const AVERAGE_HEADER_SIZE: usize = 30;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct MessageEncoder<T: MessageType> {
|
pub(crate) struct MessageEncoder<T: MessageType> {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub length: BodySize,
|
pub length: BodySize,
|
||||||
pub te: TransferEncoding,
|
pub te: TransferEncoding,
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
|
|
|
@ -6,8 +6,9 @@ use crate::{IntoPatterns, Resource, ResourceDef, ResourcePath};
|
||||||
pub struct ResourceId(pub u16);
|
pub struct ResourceId(pub u16);
|
||||||
|
|
||||||
/// Information about current resource
|
/// Information about current resource
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ResourceInfo {
|
pub struct ResourceInfo {
|
||||||
|
#[allow(dead_code)]
|
||||||
resource: ResourceId,
|
resource: ResourceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ pub use actix_web::test::{
|
||||||
/// Ok(HttpResponse::Ok())
|
/// Ok(HttpResponse::Ok())
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_example() {
|
/// async fn test_example() {
|
||||||
/// let srv = actix_test::start(||
|
/// let srv = actix_test::start(||
|
||||||
/// App::new().service(my_handler)
|
/// App::new().service(my_handler)
|
||||||
|
@ -104,7 +104,7 @@ where
|
||||||
/// Ok(HttpResponse::Ok())
|
/// Ok(HttpResponse::Ok())
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_example() {
|
/// async fn test_example() {
|
||||||
/// let srv = actix_test::start_with(actix_test::config().h1(), ||
|
/// let srv = actix_test::start_with(actix_test::config().h1(), ||
|
||||||
/// App::new().service(my_handler)
|
/// App::new().service(my_handler)
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
* Improve error recovery potential when macro input is invalid. [#2410]
|
* Improve error recovery potential when macro input is invalid. [#2410]
|
||||||
|
* Add `#[actix_web::test]` macro for setting up tests with a runtime. [#2409]
|
||||||
* Minimum supported Rust version (MSRV) is now 1.52.
|
* Minimum supported Rust version (MSRV) is now 1.52.
|
||||||
|
|
||||||
[#2410]: https://github.com/actix/actix-web/pull/2410
|
[#2410]: https://github.com/actix/actix-web/pull/2410
|
||||||
|
[#2409]: https://github.com/actix/actix-web/pull/2409
|
||||||
|
|
||||||
|
|
||||||
## 0.5.0-beta.4 - 2021-09-09
|
## 0.5.0-beta.4 - 2021-09-09
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
name = "actix-web-codegen"
|
name = "actix-web-codegen"
|
||||||
version = "0.5.0-beta.4"
|
version = "0.5.0-beta.4"
|
||||||
description = "Routing and runtime macros for Actix Web"
|
description = "Routing and runtime macros for Actix Web"
|
||||||
readme = "README.md"
|
|
||||||
homepage = "https://actix.rs"
|
homepage = "https://actix.rs"
|
||||||
repository = "https://github.com/actix/actix-web"
|
repository = "https://github.com/actix/actix-web.git"
|
||||||
documentation = "https://docs.rs/actix-web-codegen"
|
authors = [
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||||
|
"Rob Ede <robjtede@icloud.com>",
|
||||||
|
]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ actix-router = "0.5.0-beta.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
actix-rt = "2.2"
|
actix-rt = "2.2"
|
||||||
actix-macros = "0.2.2"
|
actix-macros = "0.2.3"
|
||||||
actix-test = "0.1.0-beta.3"
|
actix-test = "0.1.0-beta.3"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-web = "4.0.0-beta.9"
|
actix-web = "4.0.0-beta.9"
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#![recursion_limit = "512"]
|
#![recursion_limit = "512"]
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
mod route;
|
mod route;
|
||||||
|
|
||||||
|
@ -157,24 +158,41 @@ method_macro! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks async main function as the actix system entry-point.
|
/// Marks async main function as the actix system entry-point.
|
||||||
///
|
|
||||||
/// # Actix Web Re-export
|
|
||||||
/// This macro can be applied with `#[actix_web::main]` when used in Actix Web applications.
|
|
||||||
///
|
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// #[actix_web_codegen::main]
|
/// #[actix_web::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// async { println!("Hello world"); }.await
|
/// async { println!("Hello world"); }.await
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
use quote::quote;
|
let mut output: TokenStream = (quote! {
|
||||||
let input = syn::parse_macro_input!(item as syn::ItemFn);
|
#[::actix_web::rt::main(system = "::actix_web::rt::System")]
|
||||||
(quote! {
|
|
||||||
#[actix_web::rt::main(system = "::actix_web::rt::System")]
|
|
||||||
#input
|
|
||||||
})
|
})
|
||||||
.into()
|
.into();
|
||||||
|
|
||||||
|
output.extend(item);
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marks async test functions to use the actix system entry-point.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// #[actix_web::test]
|
||||||
|
/// async fn test() {
|
||||||
|
/// assert_eq!(async { "Hello world" }.await, "Hello world");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn test(_: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
|
let mut output: TokenStream = (quote! {
|
||||||
|
#[::actix_web::rt::test(system = "::actix_web::rt::System")]
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
output.extend(item);
|
||||||
|
output
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,7 +220,7 @@ fn guess_resource_type(typ: &syn::Type) -> ResourceType {
|
||||||
impl Route {
|
impl Route {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
args: AttributeArgs,
|
args: AttributeArgs,
|
||||||
input: TokenStream,
|
ast: syn::ItemFn,
|
||||||
method: Option<MethodType>,
|
method: Option<MethodType>,
|
||||||
) -> syn::Result<Self> {
|
) -> syn::Result<Self> {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
|
@ -234,14 +234,11 @@ impl Route {
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let ast: syn::ItemFn = syn::parse(input)?;
|
|
||||||
let name = ast.sig.ident.clone();
|
let name = ast.sig.ident.clone();
|
||||||
|
|
||||||
// Try and pull out the doc comments so that we can reapply them to the
|
// Try and pull out the doc comments so that we can reapply them to the generated struct.
|
||||||
// generated struct.
|
// Note that multi line doc comments are converted to multiple doc attributes.
|
||||||
//
|
|
||||||
// Note that multi line doc comments are converted to multiple doc
|
|
||||||
// attributes.
|
|
||||||
let doc_attributes = ast
|
let doc_attributes = ast
|
||||||
.attrs
|
.attrs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -349,9 +346,16 @@ pub(crate) fn with_method(
|
||||||
input: TokenStream,
|
input: TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let args = parse_macro_input!(args as syn::AttributeArgs);
|
let args = parse_macro_input!(args as syn::AttributeArgs);
|
||||||
match Route::new(args, input.clone(), method) {
|
|
||||||
|
let ast = match syn::parse::<syn::ItemFn>(input.clone()) {
|
||||||
|
Ok(ast) => ast,
|
||||||
|
// on parse error, make IDEs happy; see fn docs
|
||||||
|
Err(err) => return input_and_compile_error(input, err),
|
||||||
|
};
|
||||||
|
|
||||||
|
match Route::new(args, ast, method) {
|
||||||
Ok(route) => route.into_token_stream().into(),
|
Ok(route) => route.into_token_stream().into(),
|
||||||
// on parse err, make IDEs happy; see fn docs
|
// on macro related error, make IDEs happy; see fn docs
|
||||||
Err(err) => input_and_compile_error(input, err),
|
Err(err) => input_and_compile_error(input, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,7 +256,7 @@ async fn test_auto_async() {
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_web::test]
|
||||||
async fn test_wrap() {
|
async fn test_wrap() {
|
||||||
let srv = actix_test::start(|| App::new().service(get_wrap));
|
let srv = actix_test::start(|| App::new().service(get_wrap));
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,6 @@ fn compile_macros() {
|
||||||
t.compile_fail("tests/trybuild/route-malformed-path-fail.rs");
|
t.compile_fail("tests/trybuild/route-malformed-path-fail.rs");
|
||||||
|
|
||||||
t.pass("tests/trybuild/docstring-ok.rs");
|
t.pass("tests/trybuild/docstring-ok.rs");
|
||||||
|
|
||||||
|
t.pass("tests/trybuild/test-runtime.rs");
|
||||||
}
|
}
|
||||||
|
|
6
actix-web-codegen/tests/trybuild/test-runtime.rs
Normal file
6
actix-web-codegen/tests/trybuild/test-runtime.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn my_test() {
|
||||||
|
assert!(async { 1 }.await, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -35,7 +35,7 @@ async fn main() -> std::io::Result<()> {
|
||||||
)
|
)
|
||||||
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
||||||
})
|
})
|
||||||
.bind("127.0.0.1:8080")?
|
.bind(("127.0.0.1", 8080))?
|
||||||
.workers(1)
|
.workers(1)
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await
|
||||||
|
|
16
src/test.rs
16
src/test.rs
|
@ -52,7 +52,7 @@ pub fn default_service(
|
||||||
/// use actix_service::Service;
|
/// use actix_service::Service;
|
||||||
/// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
|
/// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_init_service() {
|
/// async fn test_init_service() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new()
|
/// App::new()
|
||||||
|
@ -98,7 +98,7 @@ where
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
|
/// use actix_web::{test, web, App, HttpResponse, http::StatusCode};
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_response() {
|
/// async fn test_response() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new()
|
/// App::new()
|
||||||
|
@ -129,7 +129,7 @@ where
|
||||||
/// use actix_web::{test, web, App, HttpResponse, http::header};
|
/// use actix_web::{test, web, App, HttpResponse, http::header};
|
||||||
/// use bytes::Bytes;
|
/// use bytes::Bytes;
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_index() {
|
/// async fn test_index() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new().service(
|
/// App::new().service(
|
||||||
|
@ -176,7 +176,7 @@ where
|
||||||
/// use actix_web::{test, web, App, HttpResponse, http::header};
|
/// use actix_web::{test, web, App, HttpResponse, http::header};
|
||||||
/// use bytes::Bytes;
|
/// use bytes::Bytes;
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_index() {
|
/// async fn test_index() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new().service(
|
/// App::new().service(
|
||||||
|
@ -224,7 +224,7 @@ where
|
||||||
/// name: String,
|
/// name: String,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_post_person() {
|
/// async fn test_post_person() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new().service(
|
/// App::new().service(
|
||||||
|
@ -296,7 +296,7 @@ where
|
||||||
/// name: String
|
/// name: String
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[actix_rt::test]
|
/// #[actix_web::test]
|
||||||
/// async fn test_add_person() {
|
/// async fn test_add_person() {
|
||||||
/// let app = test::init_service(
|
/// let app = test::init_service(
|
||||||
/// App::new().service(
|
/// App::new().service(
|
||||||
|
@ -356,8 +356,8 @@ where
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[test]
|
/// #[actix_web::test]
|
||||||
/// fn test_index() {
|
/// async fn test_index() {
|
||||||
/// let req = test::TestRequest::default().insert_header("content-type", "text/plain")
|
/// let req = test::TestRequest::default().insert_header("content-type", "text/plain")
|
||||||
/// .to_http_request();
|
/// .to_http_request();
|
||||||
///
|
///
|
||||||
|
|
15
tests/test-macro-import-conflict.rs
Normal file
15
tests/test-macro-import-conflict.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//! Checks that test macro does not cause problems in the presence of imports named "test" that
|
||||||
|
//! could be either a module with test items or the "test with runtime" macro itself.
|
||||||
|
//!
|
||||||
|
//! Before actix/actix-net#399 was implemented, this macro was running twice. The first run output
|
||||||
|
//! `#[test]` and it got run again and since it was in scope.
|
||||||
|
//!
|
||||||
|
//! Prevented by using the fully-qualified test marker (`#[::core::prelude::v1::test]`).
|
||||||
|
|
||||||
|
use actix_web::test;
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn test_macro_naming_conflict() {
|
||||||
|
let _req = test::TestRequest::default();
|
||||||
|
assert_eq!(async { 1 }.await, 1);
|
||||||
|
}
|
Loading…
Reference in a new issue