kode_bridge/
lib.rs

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