Skip to main content

kode_bridge/
lib.rs

1#[cfg(feature = "server")]
2pub mod codec;
3pub mod config;
4pub mod errors;
5pub mod http_client;
6pub mod metrics;
7pub mod parser_cache;
8pub mod pool;
9pub mod response;
10pub mod retry;
11mod transport;
12
13pub use transport::{Endpoint, IpcStream, ListenerOptions};
14
15#[cfg(feature = "client")]
16pub mod ipc_http_client;
17
18#[cfg(feature = "client")]
19pub mod ipc_stream_client;
20
21#[cfg(feature = "client")]
22pub mod stream_client;
23
24#[cfg(feature = "server")]
25pub mod ipc_http_server;
26
27#[cfg(feature = "server")]
28pub mod ipc_stream_server;
29
30pub use config::*;
31pub use errors::*;
32pub use metrics::{
33    global_metrics, init_metrics, BufferPoolStats, HealthChecker, HealthReport, HealthStatus, MetricsCollector,
34    MetricsSnapshot, ParserCacheStats,
35};
36pub use response::*;
37
38#[cfg(feature = "client")]
39pub use ipc_http_client::*;
40
41#[cfg(feature = "client")]
42pub use ipc_stream_client::*;
43
44#[cfg(feature = "client")]
45pub use stream_client::*;
46
47#[cfg(feature = "server")]
48pub use ipc_http_server::{ClientInfo, IpcHttpServer, PeerCredentials, RequestContext, Router, ServerConfig};
49
50#[cfg(feature = "server")]
51pub use ipc_stream_server::*;
52
53#[cfg(test)]
54mod test_utils {
55    use crate::config::GlobalConfig;
56    use tokio::sync::oneshot;
57
58    pub fn test_config() -> GlobalConfig {
59        let mut config = GlobalConfig::default();
60        config.client.default_timeout_ms = 5000;
61        config.client.max_retries = 2;
62        config.client.retry_delay_ms = 100;
63        config.client.connection_timeout_ms = 1000;
64        config.client.pool.max_size = 5;
65        config.client.pool.min_idle = 2; // 确保 min_idle <= max_size
66        config
67    }
68
69    pub fn _setup_test_server(_socket_path: &str) -> (tokio::task::JoinHandle<()>, oneshot::Sender<()>) {
70        // TODO: Fix server API integration
71        let (shutdown_tx, _shutdown_rx) = oneshot::channel();
72        let handle = tokio::spawn(async move {
73            // Placeholder for server implementation
74        });
75        (handle, shutdown_tx)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use test_utils::*;
83
84    #[test]
85    fn test_config_validation() {
86        let mut invalid_config = test_config();
87        invalid_config.client.default_timeout_ms = 0;
88
89        assert!(invalid_config.validate().is_err());
90
91        let valid_config = test_config();
92        assert!(valid_config.validate().is_ok());
93    }
94
95    #[test]
96    fn test_config_builder() {
97        use crate::config::ConfigBuilder;
98        use std::time::Duration;
99
100        let config = ConfigBuilder::new()
101            .client_timeout(Duration::from_millis(3000))
102            .max_retries(3)
103            .enable_logging("debug")
104            .enable_feature("caching")
105            .build()
106            .unwrap();
107
108        assert_eq!(config.client.default_timeout_ms, 3000);
109        assert_eq!(config.client.max_retries, 3);
110        assert_eq!(config.logging.level, "debug");
111        assert!(config.features.caching);
112    }
113
114    #[test]
115    fn test_error_categorization() {
116        use crate::errors::KodeBridgeError;
117
118        let connection_error = KodeBridgeError::Connection {
119            message: "Connection failed".to_string(),
120        };
121        assert!(connection_error.is_retriable());
122        assert!(!connection_error.is_client_error());
123        assert!(!connection_error.is_server_error());
124
125        let config_error = KodeBridgeError::Configuration {
126            message: "Invalid configuration".to_string(),
127        };
128        assert!(!config_error.is_retriable());
129
130        let client_error = KodeBridgeError::ClientError { status: 400 };
131        assert!(client_error.is_client_error());
132        assert!(!client_error.is_server_error());
133
134        let server_error = KodeBridgeError::ServerError { status: 500 };
135        assert!(server_error.is_server_error());
136        assert!(!server_error.is_client_error());
137    }
138
139    #[test]
140    fn test_timeout_error() {
141        use crate::errors::KodeBridgeError;
142
143        let timeout_error = KodeBridgeError::timeout(5000);
144        assert!(timeout_error.is_retriable());
145
146        assert!(matches!(timeout_error, KodeBridgeError::Timeout { duration_ms } if duration_ms == 5000));
147    }
148
149    #[test]
150    fn test_error_construction_helpers() {
151        use crate::errors::KodeBridgeError;
152
153        let conn_err = KodeBridgeError::connection("Test connection error");
154        assert!(matches!(conn_err, KodeBridgeError::Connection { message } if message == "Test connection error"));
155
156        let proto_err = KodeBridgeError::protocol("Protocol violation");
157        assert!(matches!(proto_err, KodeBridgeError::Protocol { message } if message == "Protocol violation"));
158
159        let config_err = KodeBridgeError::configuration("Bad config");
160        assert!(matches!(config_err, KodeBridgeError::Configuration { message } if message == "Bad config"));
161
162        let custom_err = KodeBridgeError::custom("Custom error message");
163        assert!(matches!(custom_err, KodeBridgeError::Custom { message } if message == "Custom error message"));
164    }
165
166    #[test]
167    fn test_pool_config() {
168        use crate::pool::PoolConfig;
169
170        let pool_config = PoolConfig {
171            max_size: 10,
172            min_idle: 2,
173            max_idle_time_ms: 300_000,
174            connection_timeout_ms: 30_000,
175            retry_delay_ms: 100,
176            max_retries: 3,
177            max_concurrent_requests: 8,
178            max_requests_per_second: Some(10.0),
179        };
180
181        assert_eq!(pool_config.max_size, 10);
182        assert_eq!(pool_config.min_idle, 2);
183        assert_eq!(pool_config.max_idle_time_ms, 300_000);
184
185        let default_config = PoolConfig::default();
186        assert_eq!(default_config.max_size, 64); // 更新为新的默认值
187        assert_eq!(default_config.min_idle, 8); // 更新为新的默认值
188    }
189
190    #[cfg(feature = "server")]
191    #[test]
192    fn test_path_security() {
193        use crate::ipc_http_server::Router;
194
195        let router = Router::new();
196
197        // Test safe paths
198        assert!(router.is_safe_path("/api/users"));
199        assert!(router.is_safe_path("/"));
200        assert!(router.is_safe_path("/data/file.json"));
201
202        // Test unsafe paths - directory traversal
203        assert!(!router.is_safe_path("/../etc/passwd"));
204        assert!(!router.is_safe_path("/api/../../../etc/passwd"));
205        assert!(!router.is_safe_path("/data\\..\\windows"));
206
207        // Test paths with invalid characters
208        assert!(!router.is_safe_path("/api/users\0"));
209        assert!(!router.is_safe_path("/api/\x01users"));
210
211        // Test paths not starting with /
212        assert!(!router.is_safe_path("api/users"));
213        assert!(!router.is_safe_path("../etc/passwd"));
214
215        // Test excessively long paths
216        let long_path = "/".to_string() + &"a".repeat(3000);
217        assert!(!router.is_safe_path(&long_path));
218    }
219
220    #[test]
221    fn test_metrics_integration() {
222        use crate::metrics::global_metrics;
223
224        let metrics = global_metrics();
225
226        // Test request tracking
227        {
228            let tracker = metrics.request_start("GET");
229            std::thread::sleep(std::time::Duration::from_millis(1));
230            tracker.success(200);
231        }
232
233        let snapshot = metrics.snapshot();
234        assert_eq!(snapshot.total_requests, 1);
235        assert_eq!(snapshot.successful_requests, 1);
236        assert_eq!(snapshot.active_requests, 0);
237
238        // Test connection tracking
239        metrics.connection_created(true);
240        metrics.connection_created(false);
241
242        let snapshot = metrics.snapshot();
243        assert_eq!(snapshot.total_connections, 2);
244        assert_eq!(snapshot.pool_hits, 1);
245        assert_eq!(snapshot.pool_misses, 1);
246    }
247
248    #[test]
249    fn test_health_checker() {
250        use crate::metrics::{HealthChecker, HealthStatus, MetricsCollector};
251        use std::sync::Arc;
252
253        let metrics = Arc::new(MetricsCollector::new());
254        let health_checker = HealthChecker::new(metrics);
255
256        let report = health_checker.check_health();
257        assert_eq!(report.status, HealthStatus::Healthy);
258        assert!(report.issues.is_empty());
259    }
260}