summaryrefslogtreecommitdiff
path: root/crates/utils/tcp_connection/tcp_connection_test/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2025-09-26 17:38:54 +0800
committer魏曹先生 <1992414357@qq.com>2025-09-26 17:39:36 +0800
commit4951e2e98bab7a2996893939ee77f0279145b556 (patch)
tree78138b8564d132edba20226a7522532746bfb79e /crates/utils/tcp_connection/tcp_connection_test/src
parente8160eda1b68a42b8d861bbec5e9c1dc555ea783 (diff)
refactor: downgrade tcp_connection functionality to test utilities
- Remove handle, target, target_configure, target_connection modules from main library - Create test_utils module in test project to contain temporary connection functionality - Update import paths in test files - Keep instance and error modules as core functionality - Adjust vcs_test configurations to adapt to new test structure
Diffstat (limited to 'crates/utils/tcp_connection/tcp_connection_test/src')
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/lib.rs3
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs13
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs7
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs13
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs7
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs7
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs4
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs11
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs201
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs53
-rw-r--r--crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs89
11 files changed, 387 insertions, 21 deletions
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs b/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs
index beba25b..c9372d4 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/lib.rs
@@ -12,3 +12,6 @@ pub mod test_file_transfer;
#[cfg(test)]
pub mod test_msgpack;
+
+pub mod test_utils;
+pub use test_utils::*;
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs
index 95b0e3c..2fc1a87 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_challenge.rs
@@ -1,16 +1,17 @@
use std::{env::current_dir, time::Duration};
-use tcp_connection::{
- handle::{ClientHandle, ServerHandle},
- instance::ConnectionInstance,
- target::TcpServerTarget,
- target_configure::ServerTargetConfig,
-};
+use tcp_connection::instance::ConnectionInstance;
use tokio::{
join,
time::{sleep, timeout},
};
+use crate::test_utils::{
+ handle::{ClientHandle, ServerHandle},
+ target::TcpServerTarget,
+ target_configure::ServerTargetConfig,
+};
+
pub(crate) struct ExampleChallengeClientHandle;
impl ClientHandle<ExampleChallengeServerHandle> for ExampleChallengeClientHandle {
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs
index 79aac65..8c3ab01 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_connection.rs
@@ -1,12 +1,13 @@
use std::time::Duration;
-use tcp_connection::{
+use tcp_connection::instance::ConnectionInstance;
+use tokio::{join, time::sleep};
+
+use crate::test_utils::{
handle::{ClientHandle, ServerHandle},
- instance::ConnectionInstance,
target::TcpServerTarget,
target_configure::ServerTargetConfig,
};
-use tokio::{join, time::sleep};
pub(crate) struct ExampleClientHandle;
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs
index 9425d30..4237ea7 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_file_transfer.rs
@@ -1,16 +1,17 @@
use std::{env::current_dir, time::Duration};
-use tcp_connection::{
- handle::{ClientHandle, ServerHandle},
- instance::ConnectionInstance,
- target::TcpServerTarget,
- target_configure::ServerTargetConfig,
-};
+use tcp_connection::instance::ConnectionInstance;
use tokio::{
join,
time::{sleep, timeout},
};
+use crate::test_utils::{
+ handle::{ClientHandle, ServerHandle},
+ target::TcpServerTarget,
+ target_configure::ServerTargetConfig,
+};
+
pub(crate) struct ExampleFileTransferClientHandle;
impl ClientHandle<ExampleFileTransferServerHandle> for ExampleFileTransferClientHandle {
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs
index 7344d64..7a7dc1f 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_msgpack.rs
@@ -1,12 +1,13 @@
use serde::{Deserialize, Serialize};
use std::time::Duration;
-use tcp_connection::{
+use tcp_connection::instance::ConnectionInstance;
+use tokio::{join, time::sleep};
+
+use crate::test_utils::{
handle::{ClientHandle, ServerHandle},
- instance::ConnectionInstance,
target::TcpServerTarget,
target_configure::ServerTargetConfig,
};
-use tokio::{join, time::sleep};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct TestData {
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs
index bcaada3..aa1ec74 100644
--- a/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_tcp_target_build.rs
@@ -1,6 +1,7 @@
-use tcp_connection::target::TcpServerTarget;
-
-use crate::test_connection::{ExampleClientHandle, ExampleServerHandle};
+use crate::{
+ test_connection::{ExampleClientHandle, ExampleServerHandle},
+ test_utils::target::TcpServerTarget,
+};
#[test]
fn test_tcp_test_target_build() {
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs
new file mode 100644
index 0000000..badf27d
--- /dev/null
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils.rs
@@ -0,0 +1,4 @@
+pub mod handle;
+pub mod target;
+pub mod target_configure;
+pub mod target_connection;
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs
new file mode 100644
index 0000000..4f9bdbb
--- /dev/null
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/handle.rs
@@ -0,0 +1,11 @@
+use std::future::Future;
+
+use tcp_connection::instance::ConnectionInstance;
+
+pub trait ClientHandle<RequestServer> {
+ fn process(instance: ConnectionInstance) -> impl Future<Output = ()> + Send;
+}
+
+pub trait ServerHandle<RequestClient> {
+ fn process(instance: ConnectionInstance) -> impl Future<Output = ()> + Send;
+}
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs
new file mode 100644
index 0000000..8972b2a
--- /dev/null
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target.rs
@@ -0,0 +1,201 @@
+use serde::{Deserialize, Serialize};
+use std::{
+ fmt::{Display, Formatter},
+ marker::PhantomData,
+ net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr},
+ str::FromStr,
+};
+use tokio::net::lookup_host;
+
+use crate::test_utils::{
+ handle::{ClientHandle, ServerHandle},
+ target_configure::{ClientTargetConfig, ServerTargetConfig},
+};
+
+const DEFAULT_PORT: u16 = 8080;
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ /// Client Config
+ client_cfg: Option<ClientTargetConfig>,
+
+ /// Server Config
+ server_cfg: Option<ServerTargetConfig>,
+
+ /// Server port
+ port: u16,
+
+ /// Bind addr
+ bind_addr: IpAddr,
+
+ /// Client Phantom Data
+ _client: PhantomData<Client>,
+
+ /// Server Phantom Data
+ _server: PhantomData<Server>,
+}
+
+impl<Client, Server> Default for TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ fn default() -> Self {
+ Self {
+ client_cfg: None,
+ server_cfg: None,
+ port: DEFAULT_PORT,
+ bind_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
+ _client: PhantomData,
+ _server: PhantomData,
+ }
+ }
+}
+
+impl<Client, Server> From<SocketAddr> for TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ /// Convert SocketAddr to TcpServerTarget
+ fn from(value: SocketAddr) -> Self {
+ Self {
+ port: value.port(),
+ bind_addr: value.ip(),
+ ..Self::default()
+ }
+ }
+}
+
+impl<Client, Server> From<TcpServerTarget<Client, Server>> for SocketAddr
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ /// Convert TcpServerTarget to SocketAddr
+ fn from(val: TcpServerTarget<Client, Server>) -> Self {
+ SocketAddr::new(val.bind_addr, val.port)
+ }
+}
+
+impl<Client, Server> Display for TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}:{}", self.bind_addr, self.port)
+ }
+}
+
+impl<Client, Server> TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ /// Create target by address
+ pub fn from_addr(addr: impl Into<IpAddr>, port: impl Into<u16>) -> Self {
+ Self {
+ port: port.into(),
+ bind_addr: addr.into(),
+ ..Self::default()
+ }
+ }
+
+ /// Try to create target by string
+ pub fn from_address_str<'a>(addr_str: impl Into<&'a str>) -> Result<Self, AddrParseError> {
+ let socket_addr = SocketAddr::from_str(addr_str.into());
+ match socket_addr {
+ Ok(socket_addr) => Ok(Self::from_addr(socket_addr.ip(), socket_addr.port())),
+ Err(err) => Err(err),
+ }
+ }
+
+ /// Try to create target by domain name
+ pub async fn from_domain<'a>(domain: impl Into<&'a str>) -> Result<Self, std::io::Error> {
+ match domain_to_addr(domain).await {
+ Ok(domain_addr) => Ok(Self::from(domain_addr)),
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Set client config
+ pub fn client_cfg(mut self, config: ClientTargetConfig) -> Self {
+ self.client_cfg = Some(config);
+ self
+ }
+
+ /// Set server config
+ pub fn server_cfg(mut self, config: ServerTargetConfig) -> Self {
+ self.server_cfg = Some(config);
+ self
+ }
+
+ /// Add client config
+ pub fn add_client_cfg(&mut self, config: ClientTargetConfig) {
+ self.client_cfg = Some(config);
+ }
+
+ /// Add server config
+ pub fn add_server_cfg(&mut self, config: ServerTargetConfig) {
+ self.server_cfg = Some(config);
+ }
+
+ /// Get client config ref
+ pub fn get_client_cfg(&self) -> Option<&ClientTargetConfig> {
+ self.client_cfg.as_ref()
+ }
+
+ /// Get server config ref
+ pub fn get_server_cfg(&self) -> Option<&ServerTargetConfig> {
+ self.server_cfg.as_ref()
+ }
+
+ /// Get SocketAddr of TcpServerTarget
+ pub fn get_addr(&self) -> SocketAddr {
+ SocketAddr::new(self.bind_addr, self.port)
+ }
+}
+
+/// Parse Domain Name to IpAddr via DNS
+async fn domain_to_addr<'a>(domain: impl Into<&'a str>) -> Result<SocketAddr, std::io::Error> {
+ let domain = domain.into();
+ let default_port: u16 = DEFAULT_PORT;
+
+ if let Ok(socket_addr) = domain.parse::<SocketAddr>() {
+ return Ok(match socket_addr.ip() {
+ IpAddr::V4(_) => socket_addr,
+ IpAddr::V6(_) => SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), socket_addr.port()),
+ });
+ }
+
+ if let Ok(_v6_addr) = domain.parse::<std::net::Ipv6Addr>() {
+ return Ok(SocketAddr::new(
+ IpAddr::V4(Ipv4Addr::LOCALHOST),
+ default_port,
+ ));
+ }
+
+ let (host, port_str) = if let Some((host, port)) = domain.rsplit_once(':') {
+ (host.trim_matches(|c| c == '[' || c == ']'), Some(port))
+ } else {
+ (domain, None)
+ };
+
+ let port = port_str
+ .and_then(|p| p.parse::<u16>().ok())
+ .map(|p| p.clamp(0, u16::MAX))
+ .unwrap_or(default_port);
+
+ let mut socket_iter = lookup_host((host, 0)).await?;
+
+ if let Some(addr) = socket_iter.find(|addr| addr.is_ipv4()) {
+ return Ok(SocketAddr::new(addr.ip(), port));
+ }
+
+ Ok(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), port))
+}
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs
new file mode 100644
index 0000000..d739ac9
--- /dev/null
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_configure.rs
@@ -0,0 +1,53 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
+pub struct ServerTargetConfig {
+ /// Only process a single connection, then shut down the server.
+ once: bool,
+
+ /// Timeout duration in milliseconds. (0 is Closed)
+ timeout: u64,
+}
+
+impl ServerTargetConfig {
+ /// Set `once` to True
+ /// This method configures the `once` field of `ServerTargetConfig`.
+ pub fn once(mut self) -> Self {
+ self.once = true;
+ self
+ }
+
+ /// Set `timeout` to the given value
+ /// This method configures the `timeout` field of `ServerTargetConfig`.
+ pub fn timeout(mut self, timeout: u64) -> Self {
+ self.timeout = timeout;
+ self
+ }
+
+ /// Set `once` to the given value
+ /// This method configures the `once` field of `ServerTargetConfig`.
+ pub fn set_once(&mut self, enable: bool) {
+ self.once = enable;
+ }
+
+ /// Set `timeout` to the given value
+ /// This method configures the `timeout` field of `ServerTargetConfig`.
+ pub fn set_timeout(&mut self, timeout: u64) {
+ self.timeout = timeout;
+ }
+
+ /// Check if the server is configured to process only a single connection.
+ /// Returns `true` if the server will shut down after processing one connection.
+ pub fn is_once(&self) -> bool {
+ self.once
+ }
+
+ /// Get the current timeout value in milliseconds.
+ /// Returns the timeout duration. A value of 0 indicates the connection is closed.
+ pub fn get_timeout(&self) -> u64 {
+ self.timeout
+ }
+}
+
+#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize)]
+pub struct ClientTargetConfig {}
diff --git a/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs
new file mode 100644
index 0000000..d5bf2c3
--- /dev/null
+++ b/crates/utils/tcp_connection/tcp_connection_test/src/test_utils/target_connection.rs
@@ -0,0 +1,89 @@
+use tcp_connection::{error::TcpTargetError, instance::ConnectionInstance};
+use tokio::{
+ net::{TcpListener, TcpSocket},
+ spawn,
+};
+
+use crate::test_utils::{
+ handle::{ClientHandle, ServerHandle},
+ target::TcpServerTarget,
+ target_configure::ServerTargetConfig,
+};
+
+impl<Client, Server> TcpServerTarget<Client, Server>
+where
+ Client: ClientHandle<Server>,
+ Server: ServerHandle<Client>,
+{
+ /// Attempts to establish a connection to the TCP server.
+ ///
+ /// This function initiates a connection to the server address
+ /// specified in the target configuration.
+ ///
+ /// This is a Block operation.
+ pub async fn connect(&self) -> Result<(), TcpTargetError> {
+ let addr = self.get_addr();
+ let Ok(socket) = TcpSocket::new_v4() else {
+ return Err(TcpTargetError::from("Create tcp socket failed!"));
+ };
+ let stream = match socket.connect(addr).await {
+ Ok(stream) => stream,
+ Err(e) => {
+ let err = format!("Connect to `{}` failed: {}", addr, e);
+ return Err(TcpTargetError::from(err));
+ }
+ };
+ let instance = ConnectionInstance::from(stream);
+ Client::process(instance).await;
+ Ok(())
+ }
+
+ /// Attempts to establish a connection to the TCP server.
+ ///
+ /// This function initiates a connection to the server address
+ /// specified in the target configuration.
+ pub async fn listen(&self) -> Result<(), TcpTargetError> {
+ let addr = self.get_addr();
+ let listener = match TcpListener::bind(addr).await {
+ Ok(listener) => listener,
+ Err(_) => {
+ let err = format!("Bind to `{}` failed", addr);
+ return Err(TcpTargetError::from(err));
+ }
+ };
+
+ let cfg: ServerTargetConfig = match self.get_server_cfg() {
+ Some(cfg) => *cfg,
+ None => ServerTargetConfig::default(),
+ };
+
+ if cfg.is_once() {
+ // Process once (Blocked)
+ let (stream, _) = match listener.accept().await {
+ Ok(result) => result,
+ Err(e) => {
+ let err = format!("Accept connection failed: {}", e);
+ return Err(TcpTargetError::from(err));
+ }
+ };
+ let instance = ConnectionInstance::from(stream);
+ Server::process(instance).await;
+ } else {
+ loop {
+ // Process multiple times (Concurrent)
+ let (stream, _) = match listener.accept().await {
+ Ok(result) => result,
+ Err(e) => {
+ let err = format!("Accept connection failed: {}", e);
+ return Err(TcpTargetError::from(err));
+ }
+ };
+ let instance = ConnectionInstance::from(stream);
+ spawn(async move {
+ Server::process(instance).await;
+ });
+ }
+ }
+ Ok(())
+ }
+}