From 78cbe36d9845c9dca63f8e25e7d732cab39a37f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=9C=AA=E6=9D=A5?= Date: Sun, 27 Apr 2025 11:06:50 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9C=80=E6=B1=82=E6=B5=8B=E8=AF=95=E8=A1=A5?= =?UTF-8?q?=E5=85=852?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 徐未来 --- ylong_http_client/tests/common/mod.rs | 1 + ylong_http_client/tests/sdv_async_http10.rs | 250 ++++++++++ .../tests/sdv_async_interceptor.rs | 468 ++++++++++++++++++ .../tests/sdv_async_time_group.rs | 323 ++++++++++++ 4 files changed, 1042 insertions(+) create mode 100644 ylong_http_client/tests/sdv_async_http10.rs create mode 100644 ylong_http_client/tests/sdv_async_interceptor.rs create mode 100644 ylong_http_client/tests/sdv_async_time_group.rs diff --git a/ylong_http_client/tests/common/mod.rs b/ylong_http_client/tests/common/mod.rs index bc271b6..edab84c 100644 --- a/ylong_http_client/tests/common/mod.rs +++ b/ylong_http_client/tests/common/mod.rs @@ -19,6 +19,7 @@ mod sync_utils; use tokio::runtime::Runtime; +#[macro_export] macro_rules! define_service_handle { ( HTTP; diff --git a/ylong_http_client/tests/sdv_async_http10.rs b/ylong_http_client/tests/sdv_async_http10.rs new file mode 100644 index 0000000..b5771ea --- /dev/null +++ b/ylong_http_client/tests/sdv_async_http10.rs @@ -0,0 +1,250 @@ +// Copyright (c) 2025 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(all(feature = "async", feature = "http1_1", feature = "tokio_base"))] +mod common; +use std::convert::Infallible; + +// use tokio::sync::mpsc::{Receiver, Sender}; +use ylong_http::response::status::StatusCode; +use ylong_http::version::Version; +use ylong_http_client::async_impl::{Body, Client, Request}; + +use crate::common::init_test_work_runtime; + +#[test] +#[cfg(not(feature = "__tls"))] +fn sdv_async_http10_get() { + define_service_handle!(HTTP;); + + async fn server_fn( + _req: hyper::Request, + ) -> Result, Infallible> { + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) + } + + let rt = init_test_work_runtime(4); + + let (tx, rx) = std::sync::mpsc::channel(); + + rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + tx.send(handle) + .expect("send Handle out the server coroutine failed !"); + }); + + let mut handle = rx.recv().expect("recv Handle failed !"); + + let client = Client::builder().build().expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.0") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await.expect("get response failed"); + assert_eq!(response.status(), StatusCode::OK); + assert_eq!(response.version(), &Version::HTTP1_0); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} + +#[test] +#[cfg(feature = "__tls")] +fn sdv_async_https10_get() { + define_service_handle!(HTTPS;); + + async fn server_fn( + _req: hyper::Request, + ) -> Result, Infallible> { + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) + } + + let rt = init_test_work_runtime(4); + + let mut handles_vec = vec![]; + start_server!( + HTTPS; + ServerNum: 1, + Runtime: rt, + Handles: handles_vec, + ServeFnName: server_fn, + ); + let handle = handles_vec.pop().expect("No more handles !"); + + let client = Client::builder() + .danger_accept_invalid_certs(true) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.0") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await.expect("Request send failed"); + assert_eq!(response.status(), StatusCode::OK); + assert_eq!(response.version(), &Version::HTTP1_0); + }); +} + +#[test] +#[cfg(not(feature = "__tls"))] +fn sdv_async_http10_connect() { + define_service_handle!(HTTP;); + + async fn server_fn( + _req: hyper::Request, + ) -> Result, Infallible> { + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) + } + + let rt = init_test_work_runtime(4); + + let (tx, rx) = std::sync::mpsc::channel(); + + rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + tx.send(handle) + .expect("send Handle out the server coroutine failed !"); + }); + + let mut handle = rx.recv().expect("recv Handle failed !"); + + let client = Client::builder().build().expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.0") + .method("CONNECT") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} + +#[test] +#[cfg(not(feature = "__tls"))] +fn sdv_async_http10_no_support() { + define_service_handle!(HTTP;); + + async fn server_fn( + req: hyper::Request, + ) -> Result, Infallible> { + if req.version() == hyper::Version::HTTP_10 { + return Ok(hyper::Response::builder() + .status(hyper::StatusCode::HTTP_VERSION_NOT_SUPPORTED) + .body(hyper::Body::empty()) + .unwrap()); + } + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) + } + + let rt = init_test_work_runtime(4); + + let (tx, rx) = std::sync::mpsc::channel(); + + rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + tx.send(handle) + .expect("send Handle out the server coroutine failed !"); + }); + + let mut handle = rx.recv().expect("recv Handle failed !"); + + let client = Client::builder().build().expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.0") + .method("CONNECT") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} diff --git a/ylong_http_client/tests/sdv_async_interceptor.rs b/ylong_http_client/tests/sdv_async_interceptor.rs new file mode 100644 index 0000000..40092f7 --- /dev/null +++ b/ylong_http_client/tests/sdv_async_interceptor.rs @@ -0,0 +1,468 @@ +// Copyright (c) 2025 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(all(feature = "async", feature = "tokio_base", not(feature = "__tls")))] + +mod common; + +use std::convert::Infallible; + +use ylong_http::response::status::StatusCode; +use ylong_http_client::async_impl::{Body, Client, HttpBody, Request, Response}; +use ylong_http_client::{ConnDetail, ErrorKind, HttpClientError, Interceptor}; + +use crate::common::init_test_work_runtime; + +async fn server_fn( + _req: hyper::Request, +) -> Result, Infallible> { + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) +} + +async fn server_fn_redirect( + req: hyper::Request, +) -> Result, Infallible> { + use hyper::body::HttpBody; + let mut body = req.into_body(); + + let mut buf = vec![]; + loop { + match body.data().await { + None => { + break; + } + Some(Ok(bytes)) => buf.extend_from_slice(bytes.as_ref()), + Some(Err(_e)) => { + panic!("server read request body data occurs error"); + } + } + } + let redirect_addr = format!("127.0.0.1:{}", std::str::from_utf8(&buf).unwrap()); + let response = hyper::Response::builder() + .header("Location", redirect_addr) + .status(hyper::StatusCode::TEMPORARY_REDIRECT) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) +} + +macro_rules! interceptor_test { + ( + $interceptor: ident, + $service_fn: ident, + $version: literal, + Success; + ) => { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let mut handle = rt.block_on(async move { + let mut handle = start_http_server!(HTTP; $service_fn); + handle.server_start.recv().await.unwrap(); + handle + }); + + let client = Client::builder(); + let client = match $version { + #[cfg(feature = "http1_1")] + "HTTP/1.1" => client.http1_only(), + #[cfg(feature = "http2")] + "HTTP/2.0" => client.http2_prior_knowledge(), + _ => client + }; + let client = client + .interceptor($interceptor) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version($version) + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await.expect("get response failed"); + assert_eq!(response.status(), StatusCode::OK); + + handle.client_shutdown.send(()).await.unwrap(); + handle.server_shutdown.recv().await.unwrap(); + }) + }; + ( + $interceptor: ident, + $service_fn: ident, + $version: literal, + Fail; + ) => { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let handle = rt.block_on(async move { + let mut handle = start_http_server!(HTTP; $service_fn); + handle.server_start.recv().await.unwrap(); + handle + }); + + let client = Client::builder(); + let client = match $version { + #[cfg(feature = "http1_1")] + "HTTP/1.1" => client.http1_only(), + #[cfg(feature = "http2")] + "HTTP/2.0" => client.http2_prior_knowledge(), + _ => client + }; + let client = client + .interceptor($interceptor) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version($version) + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + assert_eq!(response.err().unwrap().error_kind(), ErrorKind::UserAborted); + + handle.client_shutdown.send(()).await.unwrap(); + }) + }; +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_ok() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor {} + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Success;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_connection() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_connection(&self, _info: ConnDetail) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_input() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_input(&self, _bytes: &[u8]) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_output() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_output(&self, _bytes: &[u8]) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_request() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_request(&self, _request: &Request) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_response() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_response(&self, _response: &Response) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_retry() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_connection(&self, _info: ConnDetail) -> Result<(), HttpClientError> { + Err(HttpClientError::other("other")) + } + fn intercept_retry(&self, _error: &HttpClientError) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + define_service_handle!( HTTP ; ); + let rt = init_test_work_runtime(4); + let handle = rt.block_on(async move { + let mut handle = start_http_server!( HTTP ; server_fn ); + handle.server_start.recv().await.unwrap(); + handle + }); + let client = Client::builder() + .retry(ylong_http_client::Retry::new(2).unwrap()) + .interceptor(ExampleInterceptor) + .build() + .expect("Build Client failed."); + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + assert_eq!(response.err().unwrap().error_kind(), ErrorKind::UserAborted); + + handle.client_shutdown.send(()).await.unwrap(); + }) +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_redirect_request() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_redirect_request(&self, _request: &Request) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn_redirect, "HTTP/1.1", Fail;); +} + +#[test] +#[cfg(feature = "http1_1")] +fn sdv_client_request_interceptor_http1_redirect_response() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_redirect_response( + &self, + _response: &ylong_http::response::Response, + ) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + define_service_handle!( HTTP ; ); + let rt = init_test_work_runtime(4); + let (handle1, mut handle2) = rt.block_on(async move { + let mut handle1 = start_http_server!( HTTP ; server_fn_redirect ); + let mut handle2 = start_http_server!( HTTP ; server_fn ); + handle1.server_start.recv().await.unwrap(); + handle2.server_start.recv().await.unwrap(); + (handle1, handle2) + }); + let client = Client::builder() + .interceptor(ExampleInterceptor) + .build() + .expect("Build Client failed."); + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle1.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::slice(handle2.port.to_string().as_str())) + .expect("Client build Request failed."); + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + assert_eq!(response.err().unwrap().error_kind(), ErrorKind::UserAborted); + + handle1.client_shutdown.send(()).await.unwrap(); + handle2.client_shutdown.send(()).await.unwrap(); + handle2.server_shutdown.recv().await.unwrap(); + }) +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_ok() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor {} + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/2.0", Success;); +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_connection() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_connection(&self, _info: ConnDetail) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/2.0", Fail;); +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_request() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_request(&self, _request: &Request) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/2.0", Fail;); +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_response() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_response(&self, _response: &Response) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn, "HTTP/2.0", Fail;); +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_retry() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_connection(&self, _info: ConnDetail) -> Result<(), HttpClientError> { + Err(HttpClientError::other("other")) + } + fn intercept_retry(&self, _error: &HttpClientError) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + define_service_handle!( HTTP ; ); + let rt = init_test_work_runtime(4); + let handle = rt.block_on(async move { + let mut handle = start_http_server!( HTTP ; server_fn ); + handle.server_start.recv().await.unwrap(); + handle + }); + let client = Client::builder() + .http2_prior_knowledge() + .retry(ylong_http_client::Retry::new(2).unwrap()) + .interceptor(ExampleInterceptor) + .build() + .expect("Build Client failed."); + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/2.0") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + assert_eq!(response.err().unwrap().error_kind(), ErrorKind::UserAborted); + + handle.client_shutdown.send(()).await.unwrap(); + }) +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_redirect_request() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_redirect_request(&self, _request: &Request) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + interceptor_test!(ExampleInterceptor, server_fn_redirect, "HTTP/2.0", Fail;); +} + +#[test] +#[cfg(feature = "http2")] +fn sdv_client_request_interceptor_http2_redirect_response() { + struct ExampleInterceptor; + impl Interceptor for ExampleInterceptor { + fn intercept_redirect_response( + &self, + _response: &ylong_http::response::Response, + ) -> Result<(), HttpClientError> { + Err(HttpClientError::user_aborted()) + } + } + + define_service_handle!( HTTP ; ); + let rt = init_test_work_runtime(4); + let (handle1, mut handle2) = rt.block_on(async move { + let mut handle1 = start_http_server!( HTTP ; server_fn_redirect ); + let mut handle2 = start_http_server!( HTTP ; server_fn ); + handle1.server_start.recv().await.unwrap(); + handle2.server_start.recv().await.unwrap(); + (handle1, handle2) + }); + let client = Client::builder() + .http2_prior_knowledge() + .interceptor(ExampleInterceptor) + .build() + .expect("Build Client failed."); + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle1.port).as_str()) + .version("HTTP/2.0") + .method("GET") + .body(Body::slice(handle2.port.to_string().as_str())) + .expect("Client build Request failed."); + rt.block_on(async move { + let response = client.request(request).await; + assert!(response.is_err()); + assert_eq!(response.err().unwrap().error_kind(), ErrorKind::UserAborted); + + handle1.client_shutdown.send(()).await.unwrap(); + handle2.client_shutdown.send(()).await.unwrap(); + handle2.server_shutdown.recv().await.unwrap(); + }) +} diff --git a/ylong_http_client/tests/sdv_async_time_group.rs b/ylong_http_client/tests/sdv_async_time_group.rs new file mode 100644 index 0000000..9f7668d --- /dev/null +++ b/ylong_http_client/tests/sdv_async_time_group.rs @@ -0,0 +1,323 @@ +// Copyright (c) 2025 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![cfg(all(feature = "async", feature = "tokio_base"))] + +mod common; + +use std::convert::Infallible; +use std::time::Instant; + +use ylong_http::response::status::StatusCode; +use ylong_http_client::async_impl::{Body, Client, Request}; + +use crate::common::init_test_work_runtime; + +async fn server_fn( + _req: hyper::Request, +) -> Result, Infallible> { + let response = hyper::Response::builder() + .status(hyper::StatusCode::OK) + .body(hyper::Body::empty()) + .expect("build hyper response failed"); + Ok(response) +} + +#[test] +#[cfg(all(feature = "http1_1", not(feature = "__tls")))] +fn sdv_client_request_time_group_http1() { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let (tx, rx) = std::sync::mpsc::channel(); + + rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + tx.send(handle) + .expect("send Handle out the server coroutine failed !"); + }); + + let mut handle = rx.recv().expect("recv Handle failed !"); + + let client = Client::builder().build().expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let start = Instant::now(); + let response = client.request(request).await.expect("get response failed"); + let cost = Instant::now() - start; + assert_eq!(response.status(), StatusCode::OK); + + let time_group = response.time_group(); + assert!(time_group.dns_duration().unwrap() < cost); + assert!(time_group.connect_duration().unwrap() < cost); + assert!(time_group.tcp_duration().unwrap() < cost); + assert!(time_group.transfer_duration().unwrap() < cost); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} + +#[test] +#[cfg(all(feature = "http1_1", feature = "__tls"))] +fn sdv_client_request_time_group_https1() { + define_service_handle!(HTTPS;); + + let rt = init_test_work_runtime(4); + + let mut handles_vec = vec![]; + start_server!( + HTTPS; + ServerNum: 1, + Runtime: rt, + Handles: handles_vec, + ServeFnName: server_fn, + ); + let handle = handles_vec.pop().expect("No more handles !"); + + let client = Client::builder() + .danger_accept_invalid_certs(true) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let start = Instant::now(); + let response = client.request(request).await.expect("get response failed"); + let cost = Instant::now() - start; + assert_eq!(response.status(), StatusCode::OK); + + let time_group = response.time_group(); + assert!(time_group.dns_duration().unwrap() < cost); + assert!(time_group.connect_duration().unwrap() < cost); + assert!(time_group.tls_duration().unwrap() < cost); + assert!(time_group.tcp_duration().unwrap() < cost); + assert!(time_group.transfer_duration().unwrap() < cost); + }); +} + +#[test] +#[cfg(all(feature = "http2", not(feature = "__tls")))] +fn sdv_client_request_time_group_http2() { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let (tx, rx) = std::sync::mpsc::channel(); + + rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + tx.send(handle) + .expect("send Handle out the server coroutine failed !"); + }); + + let mut handle = rx.recv().expect("recv Handle failed !"); + + let client = Client::builder() + .http2_prior_knowledge() + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/2.0") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let start = Instant::now(); + let response = client.request(request).await.expect("get response failed"); + let cost = Instant::now() - start; + assert_eq!(response.status(), StatusCode::OK); + + let time_group = response.time_group(); + assert!(time_group.dns_duration().unwrap() < cost); + assert!(time_group.connect_duration().unwrap() < cost); + assert!(time_group.tcp_duration().unwrap() < cost); + assert!(time_group.transfer_duration().unwrap() < cost); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} + +#[test] +#[cfg(all(feature = "http1_1", not(feature = "__tls")))] +fn sdv_client_request_time_group_proxy() { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let (mut handle1, mut handle2) = rt.block_on(async move { + let mut handle1 = start_http_server!(HTTP; server_fn); + let mut handle2 = start_http_server!(HTTP; server_fn); + handle1 + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + handle2 + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + (handle1, handle2) + }); + + let client = Client::builder() + .proxy( + ylong_http_client::Proxy::http( + format!("http://{}:{}", "127.0.0.1", handle2.port).as_str(), + ) + .build() + .unwrap(), + ) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle1.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let start = Instant::now(); + let response = client.request(request).await.expect("get response failed"); + let cost = Instant::now() - start; + assert_eq!(response.status(), StatusCode::OK); + + let time_group = response.time_group(); + assert!(time_group.dns_duration().unwrap() < cost); + assert!(time_group.connect_duration().unwrap() < cost); + assert!(time_group.tcp_duration().unwrap() < cost); + assert!(time_group.transfer_duration().unwrap() < cost); + + handle1 + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle1 + .server_shutdown + .recv() + .await + .expect("server shutdown"); + handle2 + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle2 + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} + +#[test] +#[cfg(all(feature = "http1_1", not(feature = "__tls")))] +fn sdv_client_request_time_group_redirect() { + define_service_handle!(HTTP;); + + let rt = init_test_work_runtime(4); + + let mut handle = rt.block_on(async move { + let mut handle = start_http_server!(HTTP; server_fn); + handle + .server_start + .recv() + .await + .expect("recv server start msg failed !"); + handle + }); + + let client = Client::builder() + .redirect(ylong_http_client::Redirect::default()) + .build() + .expect("Build Client failed."); + + let request = Request::builder() + .url(format!("{}:{}", "127.0.0.1", handle.port).as_str()) + .version("HTTP/1.1") + .method("GET") + .body(Body::empty()) + .expect("Client build Request failed."); + + rt.block_on(async move { + let start = Instant::now(); + let response = client.request(request).await.expect("get response failed"); + let cost = Instant::now() - start; + assert_eq!(response.status(), StatusCode::OK); + + let time_group = response.time_group(); + assert!(time_group.dns_duration().unwrap() < cost); + assert!(time_group.connect_duration().unwrap() < cost); + assert!(time_group.tcp_duration().unwrap() < cost); + assert!(time_group.transfer_duration().unwrap() < cost); + + handle + .client_shutdown + .send(()) + .await + .expect("send client shutdown"); + handle + .server_shutdown + .recv() + .await + .expect("server shutdown"); + }) +} -- Gitee