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