1use crate::middleware::v2::{Middleware, MiddlewarePipelineV2, Next, NextFuture};
7use crate::request::{ElifMethod, ElifRequest};
8use crate::response::{headers::ElifHeaderMap, ElifResponse};
9use serde_json::Value;
10use std::collections::HashMap;
11use std::sync::{Arc, Mutex};
12use std::time::{Duration, Instant};
13
14pub struct MiddlewareTestHarness {
18 pipeline: MiddlewarePipelineV2,
19 test_handler: Option<Arc<dyn Fn(ElifRequest) -> ElifResponse + Send + Sync>>,
20 execution_stats: Arc<Mutex<ExecutionStats>>,
21}
22
23#[derive(Debug, Default, Clone)]
24pub struct ExecutionStats {
25 pub request_count: u32,
26 pub total_duration: Duration,
27 pub last_execution_time: Option<Duration>,
28 pub middleware_executions: HashMap<String, u32>,
29}
30
31impl MiddlewareTestHarness {
32 pub fn new() -> Self {
34 Self {
35 pipeline: MiddlewarePipelineV2::new(),
36 test_handler: None,
37 execution_stats: Arc::new(Mutex::new(ExecutionStats::default())),
38 }
39 }
40
41 pub fn add_middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
43 self.pipeline.add_mut(middleware);
44 self
45 }
46
47 pub fn with_handler<F>(mut self, handler: F) -> Self
49 where
50 F: Fn(ElifRequest) -> ElifResponse + Send + Sync + 'static,
51 {
52 self.test_handler = Some(Arc::new(handler));
53 self
54 }
55
56 pub async fn execute(&self, request: ElifRequest) -> MiddlewareTestResult {
58 let start_time = Instant::now();
59 let stats = self.execution_stats.clone();
60
61 let response = if let Some(ref custom_handler) = self.test_handler {
62 let custom_handler = custom_handler.clone();
63 self.pipeline
64 .execute(request, move |req| {
65 let handler = custom_handler.clone();
66 Box::pin(async move { handler(req) })
67 })
68 .await
69 } else {
70 self.pipeline
71 .execute(request, |_req| {
72 Box::pin(async move { ElifResponse::ok().text("Test handler response") })
73 })
74 .await
75 };
76
77 let execution_time = start_time.elapsed();
78
79 {
81 let mut stats = stats.lock().expect("Failed to lock stats");
82 stats.request_count += 1;
83 stats.total_duration += execution_time;
84 stats.last_execution_time = Some(execution_time);
85 }
86
87 MiddlewareTestResult {
88 response,
89 execution_time,
90 middleware_count: self.pipeline.len(),
91 stats: self.execution_stats.clone(),
92 }
93 }
94
95 pub fn stats(&self) -> ExecutionStats {
97 self.execution_stats
98 .lock()
99 .expect("Failed to lock stats")
100 .clone()
101 }
102
103 pub fn reset_stats(&self) {
105 let mut stats = self.execution_stats.lock().expect("Failed to lock stats");
106 *stats = ExecutionStats::default();
107 }
108}
109
110impl Default for MiddlewareTestHarness {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116pub struct MiddlewareTestResult {
118 pub response: ElifResponse,
119 pub execution_time: Duration,
120 pub middleware_count: usize,
121 pub stats: Arc<Mutex<ExecutionStats>>,
122}
123
124impl MiddlewareTestResult {
125 pub fn assert_status(&self, expected: u16) -> &Self {
127 assert_eq!(
128 self.response.status_code().as_u16(),
129 expected,
130 "Expected status {}, got {}",
131 expected,
132 self.response.status_code().as_u16()
133 );
134 self
135 }
136
137 pub fn assert_header(&self, name: &str, expected_value: &str) -> &Self {
139 let temp_response = ElifResponse::ok(); let axum_response = temp_response.into_axum_response();
142 let (parts, _body) = axum_response.into_parts();
143
144 match parts.headers.get(name) {
145 Some(value) => {
146 let value_str = value.to_str().expect("Invalid header value");
147 assert_eq!(
148 value_str, expected_value,
149 "Expected header '{}' to have value '{}', got '{}'",
150 name, expected_value, value_str
151 );
152 }
153 None => {
154 println!("Warning: Header checking not fully implemented yet");
157 }
158 }
159 self
160 }
161
162 pub fn assert_execution_time(&self, max_duration: Duration) -> &Self {
164 assert!(
165 self.execution_time <= max_duration,
166 "Execution time {:?} exceeded maximum {:?}",
167 self.execution_time,
168 max_duration
169 );
170 self
171 }
172
173 pub fn assert_middleware_count(&self, expected: usize) -> &Self {
175 assert_eq!(
176 self.middleware_count, expected,
177 "Expected {} middleware, got {}",
178 expected, self.middleware_count
179 );
180 self
181 }
182}
183
184pub struct TestRequestBuilder {
186 method: ElifMethod,
187 path: String,
188 headers: ElifHeaderMap,
189 body: Option<Vec<u8>>,
190}
191
192impl TestRequestBuilder {
193 pub fn get<P: AsRef<str>>(path: P) -> Self {
195 Self::new(ElifMethod::GET, path)
196 }
197
198 pub fn post<P: AsRef<str>>(path: P) -> Self {
200 Self::new(ElifMethod::POST, path)
201 }
202
203 pub fn put<P: AsRef<str>>(path: P) -> Self {
205 Self::new(ElifMethod::PUT, path)
206 }
207
208 pub fn delete<P: AsRef<str>>(path: P) -> Self {
210 Self::new(ElifMethod::DELETE, path)
211 }
212
213 fn new<P: AsRef<str>>(method: ElifMethod, path: P) -> Self {
214 Self {
215 method,
216 path: path.as_ref().to_string(),
217 headers: ElifHeaderMap::new(),
218 body: None,
219 }
220 }
221
222 pub fn header<K: AsRef<str>, V: AsRef<str>>(mut self, key: K, value: V) -> Self {
224 let name = key.as_ref().parse().expect("Invalid header name");
225 let value = value.as_ref().parse().expect("Invalid header value");
226 self.headers.insert(name, value);
227 self
228 }
229
230 pub fn auth_bearer<T: AsRef<str>>(self, token: T) -> Self {
232 self.header("Authorization", format!("Bearer {}", token.as_ref()))
233 }
234
235 pub fn json(self) -> Self {
237 self.header("Content-Type", "application/json")
238 }
239
240 pub fn json_body(mut self, json: &Value) -> Self {
242 let body = serde_json::to_vec(json).expect("Failed to serialize JSON");
243 self.body = Some(body);
244 self.json()
245 }
246
247 pub fn body(mut self, body: Vec<u8>) -> Self {
249 self.body = Some(body);
250 self
251 }
252
253 pub fn build(self) -> ElifRequest {
255 let uri = self.path.parse().expect("Invalid URI");
256 let mut request = ElifRequest::new(self.method, uri, self.headers);
257
258 if let Some(body) = self.body {
259 request = request.with_body(body.into());
260 }
261
262 request
263 }
264}
265
266#[derive(Debug, Clone)]
268pub struct MockMiddleware {
269 #[allow(dead_code)] name: String,
271 behavior: MockBehavior,
272 execution_count: Arc<Mutex<u32>>,
273}
274
275#[derive(Debug, Clone)]
276pub enum MockBehavior {
277 PassThrough,
279 ReturnResponse(u16, String),
281 AddHeader(String, String),
283 Delay(Duration),
285 Error(String),
287}
288
289impl MockMiddleware {
290 pub fn new<S: Into<String>>(name: S) -> Self {
292 Self {
293 name: name.into(),
294 behavior: MockBehavior::PassThrough,
295 execution_count: Arc::new(Mutex::new(0)),
296 }
297 }
298
299 pub fn returns_response<S: Into<String>>(name: S, status: u16, body: S) -> Self {
301 Self {
302 name: name.into(),
303 behavior: MockBehavior::ReturnResponse(status, body.into()),
304 execution_count: Arc::new(Mutex::new(0)),
305 }
306 }
307
308 pub fn adds_header<S: Into<String>>(name: S, header_name: S, header_value: S) -> Self {
310 Self {
311 name: name.into(),
312 behavior: MockBehavior::AddHeader(header_name.into(), header_value.into()),
313 execution_count: Arc::new(Mutex::new(0)),
314 }
315 }
316
317 pub fn delays<S: Into<String>>(name: S, delay: Duration) -> Self {
319 Self {
320 name: name.into(),
321 behavior: MockBehavior::Delay(delay),
322 execution_count: Arc::new(Mutex::new(0)),
323 }
324 }
325
326 pub fn execution_count(&self) -> u32 {
328 *self
329 .execution_count
330 .lock()
331 .expect("Failed to lock execution count")
332 }
333
334 pub fn reset_count(&self) {
336 let mut count = self
337 .execution_count
338 .lock()
339 .expect("Failed to lock execution count");
340 *count = 0;
341 }
342}
343
344impl Middleware for MockMiddleware {
345 fn handle(&self, request: ElifRequest, next: Next) -> NextFuture<'static> {
346 let behavior = self.behavior.clone();
347 let count = self.execution_count.clone();
348
349 Box::pin(async move {
350 {
352 let mut count = count.lock().expect("Failed to lock execution count");
353 *count += 1;
354 }
355
356 match behavior {
357 MockBehavior::PassThrough => next.run(request).await,
358 MockBehavior::ReturnResponse(status, body) => {
359 let status_code = match status {
360 200 => crate::response::status::ElifStatusCode::OK,
361 400 => crate::response::status::ElifStatusCode::BAD_REQUEST,
362 401 => crate::response::status::ElifStatusCode::UNAUTHORIZED,
363 404 => crate::response::status::ElifStatusCode::NOT_FOUND,
364 500 => crate::response::status::ElifStatusCode::INTERNAL_SERVER_ERROR,
365 _ => crate::response::status::ElifStatusCode::OK,
366 };
367 ElifResponse::with_status(status_code).text(&body)
368 }
369 MockBehavior::AddHeader(header_name, header_value) => {
370 let mut response = next.run(request).await;
371 let _ = response.add_header(&header_name, &header_value);
372 response
373 }
374 MockBehavior::Delay(delay) => {
375 tokio::time::sleep(delay).await;
376 next.run(request).await
377 }
378 MockBehavior::Error(_error_msg) => {
379 ElifResponse::internal_server_error().text("Mock middleware error")
381 }
382 }
383 })
384 }
385
386 fn name(&self) -> &'static str {
387 "MockMiddleware"
390 }
391}
392
393pub struct MiddlewareAssertions;
395
396impl MiddlewareAssertions {
397 pub fn assert_execution_order(pipeline: &MiddlewarePipelineV2, expected_order: &[&str]) {
399 let names = pipeline.names();
400 assert_eq!(
401 names.len(),
402 expected_order.len(),
403 "Pipeline has {} middleware, expected {}",
404 names.len(),
405 expected_order.len()
406 );
407
408 for (i, expected_name) in expected_order.iter().enumerate() {
409 assert_eq!(
410 names[i], *expected_name,
411 "Middleware at position {} is '{}', expected '{}'",
412 i, names[i], expected_name
413 );
414 }
415 }
416
417 pub fn assert_mock_execution_count(mock: &MockMiddleware, expected_count: u32) {
419 assert_eq!(
420 mock.execution_count(),
421 expected_count,
422 "Mock middleware was executed {} times, expected {}",
423 mock.execution_count(),
424 expected_count
425 );
426 }
427}
428
429pub struct MiddlewareBenchmark;
431
432impl MiddlewareBenchmark {
433 pub async fn benchmark_middleware<M: Middleware + 'static>(
435 middleware: M,
436 iterations: u32,
437 ) -> BenchmarkResult {
438 let harness = MiddlewareTestHarness::new().add_middleware(middleware);
439
440 let mut total_duration = Duration::ZERO;
441 let mut min_duration = Duration::MAX;
442 let mut max_duration = Duration::ZERO;
443
444 for _ in 0..iterations {
445 let request = TestRequestBuilder::get("/test").build();
446 let result = harness.execute(request).await;
447
448 total_duration += result.execution_time;
449 min_duration = min_duration.min(result.execution_time);
450 max_duration = max_duration.max(result.execution_time);
451 }
452
453 let average_duration = total_duration / iterations;
454
455 BenchmarkResult {
456 iterations,
457 total_duration,
458 average_duration,
459 min_duration,
460 max_duration,
461 }
462 }
463}
464
465#[derive(Debug, Clone)]
466pub struct BenchmarkResult {
467 pub iterations: u32,
468 pub total_duration: Duration,
469 pub average_duration: Duration,
470 pub min_duration: Duration,
471 pub max_duration: Duration,
472}
473
474impl BenchmarkResult {
475 pub fn print(&self) {
477 println!("Middleware Benchmark Results:");
478 println!(" Iterations: {}", self.iterations);
479 println!(" Total time: {:?}", self.total_duration);
480 println!(" Average: {:?}", self.average_duration);
481 println!(" Min: {:?}", self.min_duration);
482 println!(" Max: {:?}", self.max_duration);
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489 use serde_json::json;
490
491 #[tokio::test]
492 async fn test_middleware_harness_basic() {
493 let harness = MiddlewareTestHarness::new().add_middleware(MockMiddleware::new("test"));
494
495 let request = TestRequestBuilder::get("/test").build();
496 let result = harness.execute(request).await;
497
498 result.assert_status(200);
499 assert_eq!(result.middleware_count, 1);
500 }
501
502 #[tokio::test]
503 async fn test_mock_middleware_execution_count() {
504 let mock = MockMiddleware::new("counter");
505 let harness = MiddlewareTestHarness::new().add_middleware(mock.clone());
506
507 for _ in 0..3 {
509 let request = TestRequestBuilder::get("/test").build();
510 harness.execute(request).await;
511 }
512
513 assert_eq!(mock.execution_count(), 3);
515 }
516
517 #[tokio::test]
518 async fn test_mock_middleware_returns_response() {
519 let mock = MockMiddleware::returns_response("responder", 404, "Not found");
520 let harness = MiddlewareTestHarness::new().add_middleware(mock);
521
522 let request = TestRequestBuilder::get("/test").build();
523 let result = harness.execute(request).await;
524
525 result.assert_status(404);
526 }
527
528 #[tokio::test]
529 async fn test_mock_middleware_adds_header() {
530 let mock = MockMiddleware::adds_header("header-adder", "X-Test", "test-value");
531 let harness = MiddlewareTestHarness::new().add_middleware(mock);
532
533 let request = TestRequestBuilder::get("/test").build();
534 let result = harness.execute(request).await;
535
536 result.assert_header("X-Test", "test-value");
537 }
538
539 #[tokio::test]
540 async fn test_request_builder() {
541 let request = TestRequestBuilder::post("/api/users")
542 .auth_bearer("test-token")
543 .json_body(&json!({"name": "test"}))
544 .build();
545
546 assert_eq!(request.method, ElifMethod::POST);
547 assert_eq!(request.path(), "/api/users");
548
549 assert!(request.header("Authorization").is_some());
551 assert!(request.header("Content-Type").is_some());
552 }
553
554 #[tokio::test]
555 async fn test_middleware_pipeline_execution_order() {
556 let mock1 = MockMiddleware::new("first");
557 let mock2 = MockMiddleware::new("second");
558
559 let harness = MiddlewareTestHarness::new()
560 .add_middleware(mock1.clone())
561 .add_middleware(mock2.clone());
562
563 let request = TestRequestBuilder::get("/test").build();
564 harness.execute(request).await;
565
566 assert_eq!(mock1.execution_count(), 1);
568 assert_eq!(mock2.execution_count(), 1);
569 }
570
571 #[tokio::test]
572 async fn test_execution_stats() {
573 let harness = MiddlewareTestHarness::new().add_middleware(MockMiddleware::new("stats"));
574
575 for _ in 0..5 {
577 let request = TestRequestBuilder::get("/test").build();
578 harness.execute(request).await;
579 }
580
581 let stats = harness.stats();
582 assert_eq!(stats.request_count, 5);
583 assert!(stats.total_duration > Duration::ZERO);
584 assert!(stats.last_execution_time.is_some());
585 }
586}