Skip to content

Commit 53760c3

Browse files
authored
test(layer): 添加layer组件的单元测试 (#25)
1 parent 9b35e55 commit 53760c3

File tree

9 files changed

+427
-1
lines changed

9 files changed

+427
-1
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/layer/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,8 @@ http-body = { workspace = true }
1818
serde = { workspace = true, features = ["derive"] }
1919
tower = { workspace = true, features = ["limit"] }
2020
tower-http = { workspace = true, features = ["trace", "set-header", "timeout", "cors"] }
21-
tracing = { workspace = true }
21+
tracing = { workspace = true }
22+
23+
[dev-dependencies]
24+
serde_yaml = { workspace = true }
25+
tokio = { workspace = true, features = ["rt", "macros"] }

crates/layer/tests/identify.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use http::Response;
2+
use satex_core::body::Body;
3+
use std::fmt::{Debug, Display, Formatter};
4+
use std::future::{ready, Ready};
5+
use std::task::{Context, Poll};
6+
use tower::Service;
7+
8+
pub struct Identify<F> {
9+
f: F,
10+
}
11+
12+
impl<F> Identify<F> {
13+
pub fn new(f: F) -> Self {
14+
Self { f }
15+
}
16+
}
17+
18+
impl<F, Request> Service<Request> for Identify<F>
19+
where
20+
F: FnMut(Request) -> bool,
21+
{
22+
type Response = Response<Body>;
23+
type Error = Error;
24+
type Future = Ready<Result<Self::Response, Self::Error>>;
25+
26+
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
27+
Poll::Ready(Ok(()))
28+
}
29+
30+
fn call(&mut self, request: Request) -> Self::Future {
31+
if (self.f)(request) {
32+
ready(Ok(Response::new(Body::empty())))
33+
} else {
34+
ready(Err(Error))
35+
}
36+
}
37+
}
38+
39+
pub struct Error;
40+
41+
impl Debug for Error {
42+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
43+
f.write_str("Mistake")
44+
}
45+
}
46+
47+
impl Display for Error {
48+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
49+
f.write_str("Mistake")
50+
}
51+
}
52+
53+
impl std::error::Error for Error {}

crates/layer/tests/set_method.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
mod identify;
2+
3+
use crate::identify::Identify;
4+
use http::{Method, Request};
5+
use satex_core::body::Body;
6+
use satex_core::component::Args;
7+
use satex_layer::make::MakeRouteLayer;
8+
use satex_layer::set_method::MakeSetMethodRouteLayer;
9+
use serde_yaml::Value;
10+
use std::str::FromStr;
11+
use tower::{Layer, Service};
12+
13+
async fn layer_shortcut(method: &str) {
14+
let args = Args::shortcut(method);
15+
let layer = MakeSetMethodRouteLayer.make(args).unwrap();
16+
17+
let method = Method::from_str(method).unwrap();
18+
let mut service = layer.layer(Identify::new(|request: Request<Body>| {
19+
request.method() == method
20+
}));
21+
let request = Request::new(Body::empty());
22+
let result = service.call(request).await;
23+
assert!(result.is_ok());
24+
}
25+
26+
async fn layer_full(method: &str) {
27+
let yaml = format!("method: {}", method);
28+
let value = serde_yaml::from_str::<Value>(yaml.as_str()).unwrap();
29+
let args = Args::full(&value);
30+
let layer = MakeSetMethodRouteLayer.make(args).unwrap();
31+
32+
let method = Method::from_str(method).unwrap();
33+
let mut service = layer.layer(Identify::new(|request: Request<Body>| {
34+
request.method() == method
35+
}));
36+
let request = Request::new(Body::empty());
37+
let result = service.call(request).await;
38+
assert!(result.is_ok());
39+
}
40+
41+
#[tokio::test]
42+
async fn make_with_shortcut() {
43+
layer_shortcut("GET").await;
44+
layer_shortcut("POST").await;
45+
layer_shortcut("PUT").await;
46+
layer_shortcut("DELETE").await;
47+
layer_shortcut("OPTIONS").await;
48+
layer_shortcut("TRACE").await;
49+
}
50+
51+
#[tokio::test]
52+
async fn make_with_full() {
53+
layer_full("GET").await;
54+
layer_full("POST").await;
55+
layer_full("PUT").await;
56+
layer_full("DELETE").await;
57+
layer_full("OPTIONS").await;
58+
layer_full("TRACE").await;
59+
}

crates/layer/tests/set_prefix.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
mod identify;
2+
3+
use crate::identify::Identify;
4+
use http::Request;
5+
use satex_core::body::Body;
6+
use satex_core::component::Args;
7+
use satex_layer::make::MakeRouteLayer;
8+
use satex_layer::set_prefix::{MakeSetPrefixRouteLayer, SetPrefixLayer};
9+
use tower::{Layer, Service};
10+
11+
async fn _layer(layer: SetPrefixLayer, path: &str) {
12+
let mut service = layer.layer(Identify::new(|request: Request<Body>| {
13+
request.uri().path() == path
14+
}));
15+
let request = Request::builder()
16+
.uri("/resource")
17+
.body(Body::empty())
18+
.unwrap();
19+
let result = service.call(request).await;
20+
assert!(result.is_ok());
21+
}
22+
23+
#[tokio::test]
24+
async fn make_with_shortcut() {
25+
let args = Args::shortcut("/api");
26+
let layer = MakeSetPrefixRouteLayer.make(args).unwrap();
27+
_layer(layer, "/api/resource").await;
28+
29+
let args = Args::shortcut("/api/v1");
30+
let layer = MakeSetPrefixRouteLayer.make(args).unwrap();
31+
_layer(layer, "/api/v1/resource").await;
32+
}
33+
34+
#[tokio::test]
35+
async fn make_with_full() {
36+
let yaml = "prefix: /api";
37+
let value = serde_yaml::from_str(yaml).unwrap();
38+
let args = Args::full(&value);
39+
let layer = MakeSetPrefixRouteLayer.make(args).unwrap();
40+
_layer(layer, "/api/resource").await;
41+
42+
let yaml = "prefix: /api/v1";
43+
let value = serde_yaml::from_str(yaml).unwrap();
44+
let args = Args::full(&value);
45+
let layer = MakeSetPrefixRouteLayer.make(args).unwrap();
46+
_layer(layer, "/api/v1/resource").await;
47+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
mod identify;
2+
3+
use crate::identify::Identify;
4+
use http::{HeaderValue, Request};
5+
use satex_core::body::Body;
6+
use satex_core::component::Args;
7+
use satex_layer::make::MakeRouteLayer;
8+
use satex_layer::set_header::MakeSetRequestHeaderRouteLayer;
9+
use tower::{Layer, Service};
10+
use tower_http::set_header::SetRequestHeaderLayer;
11+
12+
async fn _layer(layer: SetRequestHeaderLayer<HeaderValue>, value: &[&str]) {
13+
let mut request = Request::new(Body::empty());
14+
request
15+
.headers_mut()
16+
.insert("x-app", HeaderValue::from_static("v1"));
17+
let service = Identify::new(|request: Request<Body>| {
18+
let app = request
19+
.headers()
20+
.get_all("x-app")
21+
.into_iter()
22+
.flat_map(|x| x.to_str())
23+
.collect::<Vec<_>>();
24+
app.as_slice() == value
25+
});
26+
let mut service = layer.layer(service);
27+
let result = service.call(request).await;
28+
assert!(result.is_ok());
29+
}
30+
31+
#[tokio::test]
32+
async fn make_with_shortcut() {
33+
let args = Args::shortcut("x-app, v2");
34+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
35+
_layer(layer, &["v2"]).await;
36+
37+
let args = Args::shortcut("x-app, v2, Appending");
38+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
39+
_layer(layer, &["v1", "v2"]).await;
40+
41+
let args = Args::shortcut("x-app, v2, IfNotPresent");
42+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
43+
_layer(layer, &["v1"]).await;
44+
}
45+
46+
#[tokio::test]
47+
async fn make_with_full() {
48+
let yaml = r#"
49+
name: x-app
50+
value: v2
51+
"#;
52+
let value = serde_yaml::from_str(yaml).unwrap();
53+
let args = Args::full(&value);
54+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
55+
_layer(layer, &["v2"]).await;
56+
57+
let yaml = r#"
58+
name: x-app
59+
value: v2
60+
policy: Appending
61+
"#;
62+
let value = serde_yaml::from_str(yaml).unwrap();
63+
let args = Args::full(&value);
64+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
65+
_layer(layer, &["v1", "v2"]).await;
66+
67+
let yaml = r#"
68+
name: x-app
69+
value: v2
70+
policy: IfNotPresent
71+
"#;
72+
let value = serde_yaml::from_str(yaml).unwrap();
73+
let args = Args::full(&value);
74+
let layer = MakeSetRequestHeaderRouteLayer.make(args).unwrap();
75+
_layer(layer, &["v1"]).await;
76+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use http::{HeaderValue, Request, Response};
2+
use satex_core::body::Body;
3+
use satex_core::component::Args;
4+
use satex_layer::make::MakeRouteLayer;
5+
use satex_layer::set_header::MakeSetResponseHeaderRouteLayer;
6+
use std::convert::Infallible;
7+
use tower::{service_fn, Layer, Service};
8+
use tower_http::set_header::SetResponseHeaderLayer;
9+
10+
async fn _layer(layer: SetResponseHeaderLayer<HeaderValue>, value: &[&str]) {
11+
let request = Request::new(Body::empty());
12+
let service = service_fn(|_| async move {
13+
let mut response = Response::new(Body::empty());
14+
response
15+
.headers_mut()
16+
.insert("x-app", HeaderValue::from_static("v1"));
17+
Ok::<_, Infallible>(response)
18+
});
19+
let mut service = layer.layer(service);
20+
let response = service.call(request).await.unwrap();
21+
let app = response
22+
.headers()
23+
.get_all("x-app")
24+
.into_iter()
25+
.flat_map(|v| v.to_str())
26+
.collect::<Vec<_>>();
27+
assert_eq!(app.as_slice(), value);
28+
}
29+
30+
#[tokio::test]
31+
async fn make_with_shortcut() {
32+
let args = Args::shortcut("x-app, v2");
33+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
34+
_layer(layer, &["v2"]).await;
35+
36+
let args = Args::shortcut("x-app, v2, Appending");
37+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
38+
_layer(layer, &["v1", "v2"]).await;
39+
40+
let args = Args::shortcut("x-app, v2, IfNotPresent");
41+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
42+
_layer(layer, &["v1"]).await;
43+
}
44+
45+
#[tokio::test]
46+
async fn make_with_full() {
47+
let yaml = r#"
48+
name: x-app
49+
value: v2
50+
"#;
51+
let value = serde_yaml::from_str(yaml).unwrap();
52+
let args = Args::full(&value);
53+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
54+
_layer(layer, &["v2"]).await;
55+
56+
let yaml = r#"
57+
name: x-app
58+
value: v2
59+
policy: Appending
60+
"#;
61+
let value = serde_yaml::from_str(yaml).unwrap();
62+
let args = Args::full(&value);
63+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
64+
_layer(layer, &["v1", "v2"]).await;
65+
66+
let yaml = r#"
67+
name: x-app
68+
value: v2
69+
policy: IfNotPresent
70+
"#;
71+
let value = serde_yaml::from_str(yaml).unwrap();
72+
let args = Args::full(&value);
73+
let layer = MakeSetResponseHeaderRouteLayer.make(args).unwrap();
74+
_layer(layer, &["v1"]).await;
75+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
mod identify;
2+
3+
use http::{Request, StatusCode};
4+
use identify::Identify;
5+
use satex_core::body::Body;
6+
use satex_core::component::Args;
7+
use satex_layer::make::MakeRouteLayer;
8+
use satex_layer::set_status_code::MakeSetStatusCodeRouteLayer;
9+
use serde_yaml::Value;
10+
use tower::{Layer, Service};
11+
use tower_http::set_status::SetStatusLayer;
12+
13+
async fn _layer(layer: SetStatusLayer) {
14+
let mut service = layer.layer(Identify::new(|_| true));
15+
let request = Request::new(Body::empty());
16+
let response = service.call(request).await.unwrap();
17+
assert_eq!(response.status(), StatusCode::OK);
18+
}
19+
20+
#[tokio::test]
21+
async fn make_with_shortcut() {
22+
let args = Args::shortcut("200");
23+
let layer = MakeSetStatusCodeRouteLayer.make(args).unwrap();
24+
_layer(layer).await;
25+
}
26+
27+
#[tokio::test]
28+
async fn make_with_full() {
29+
let yaml = "status: 200";
30+
let value = serde_yaml::from_str::<Value>(yaml).unwrap();
31+
let args = Args::full(&value);
32+
let layer = MakeSetStatusCodeRouteLayer.make(args).unwrap();
33+
_layer(layer).await;
34+
}

0 commit comments

Comments
 (0)