1use axum::{http::StatusCode, response::IntoResponse, routing::post, Json, Router};
7use mockforge_core::{
8 request_logger::get_global_logger,
9 verification::{
10 verify_at_least, verify_never, verify_requests, verify_sequence, VerificationCount,
11 VerificationRequest, VerificationResult,
12 },
13};
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct VerifyRequest {
19 pub pattern: VerificationRequest,
21 pub expected: VerificationCount,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct CountRequest {
28 pub pattern: VerificationRequest,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct CountResponse {
35 pub count: usize,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct SequenceRequest {
42 pub patterns: Vec<VerificationRequest>,
44}
45
46#[derive(Clone)]
48pub struct VerificationState;
49
50impl Default for VerificationState {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56impl VerificationState {
57 pub fn new() -> Self {
59 Self
60 }
61}
62
63pub fn verification_router() -> Router {
65 Router::new()
66 .route("/api/verification/verify", post(handle_verify))
67 .route("/api/verification/count", post(handle_count))
68 .route("/api/verification/sequence", post(handle_sequence))
69 .route("/api/verification/never", post(handle_never))
70 .route("/api/verification/at-least", post(handle_at_least))
71}
72
73async fn handle_verify(Json(request): Json<VerifyRequest>) -> impl IntoResponse {
75 let logger = match get_global_logger() {
76 Some(logger) => logger,
77 None => {
78 return (
79 StatusCode::SERVICE_UNAVAILABLE,
80 Json(VerificationResult::failure(
81 0,
82 request.expected.clone(),
83 Vec::new(),
84 "Request logger not initialized".to_string(),
85 )),
86 )
87 .into_response();
88 }
89 };
90
91 let result = verify_requests(logger, &request.pattern, request.expected).await;
92
93 let status = if result.matched {
94 StatusCode::OK
95 } else {
96 StatusCode::EXPECTATION_FAILED
97 };
98
99 (status, Json(result)).into_response()
100}
101
102async fn handle_count(Json(request): Json<CountRequest>) -> impl IntoResponse {
104 let logger = match get_global_logger() {
105 Some(logger) => logger,
106 None => {
107 return (StatusCode::SERVICE_UNAVAILABLE, Json(CountResponse { count: 0 }))
108 .into_response();
109 }
110 };
111
112 let count = logger.count_matching_requests(&request.pattern).await;
113
114 (StatusCode::OK, Json(CountResponse { count })).into_response()
115}
116
117async fn handle_sequence(Json(request): Json<SequenceRequest>) -> impl IntoResponse {
119 let logger = match get_global_logger() {
120 Some(logger) => logger,
121 None => {
122 return (
123 StatusCode::SERVICE_UNAVAILABLE,
124 Json(VerificationResult::failure(
125 0,
126 VerificationCount::Exactly(request.patterns.len()),
127 Vec::new(),
128 "Request logger not initialized".to_string(),
129 )),
130 )
131 .into_response();
132 }
133 };
134
135 let result = verify_sequence(logger, &request.patterns).await;
136
137 let status = if result.matched {
138 StatusCode::OK
139 } else {
140 StatusCode::EXPECTATION_FAILED
141 };
142
143 (status, Json(result)).into_response()
144}
145
146async fn handle_never(Json(request): Json<VerificationRequest>) -> impl IntoResponse {
148 let logger = match get_global_logger() {
149 Some(logger) => logger,
150 None => {
151 return (
152 StatusCode::SERVICE_UNAVAILABLE,
153 Json(VerificationResult::failure(
154 0,
155 VerificationCount::Never,
156 Vec::new(),
157 "Request logger not initialized".to_string(),
158 )),
159 )
160 .into_response();
161 }
162 };
163
164 let result = verify_never(logger, &request).await;
165
166 let status = if result.matched {
167 StatusCode::OK
168 } else {
169 StatusCode::EXPECTATION_FAILED
170 };
171
172 (status, Json(result)).into_response()
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
177struct AtLeastRequest {
178 pub pattern: VerificationRequest,
180 pub min: usize,
182}
183
184async fn handle_at_least(Json(request): Json<AtLeastRequest>) -> impl IntoResponse {
185 let logger = match get_global_logger() {
186 Some(logger) => logger,
187 None => {
188 return (
189 StatusCode::SERVICE_UNAVAILABLE,
190 Json(VerificationResult::failure(
191 0,
192 VerificationCount::AtLeast(request.min),
193 Vec::new(),
194 "Request logger not initialized".to_string(),
195 )),
196 )
197 .into_response();
198 }
199 };
200
201 let result = verify_at_least(logger, &request.pattern, request.min).await;
202
203 let status = if result.matched {
204 StatusCode::OK
205 } else {
206 StatusCode::EXPECTATION_FAILED
207 };
208
209 (status, Json(result)).into_response()
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215 use axum::body::Body;
216 use axum::http::Request;
217 use mockforge_core::verification::{VerificationCount, VerificationRequest};
218 use tower::ServiceExt;
219
220 #[tokio::test]
223 async fn test_verification_router_creation() {
224 let router = verification_router();
225 assert!(std::mem::size_of_val(&router) > 0);
227 }
228
229 #[tokio::test]
230 async fn test_verification_router_has_verify_route() {
231 let router = verification_router();
232
233 let request = Request::builder()
234 .method("POST")
235 .uri("/api/verification/verify")
236 .header("Content-Type", "application/json")
237 .body(Body::empty())
238 .unwrap();
239
240 let response = router.oneshot(request).await.unwrap();
241 assert!(response.status().is_client_error() || response.status().is_server_error());
243 }
244
245 #[tokio::test]
246 async fn test_verification_router_has_count_route() {
247 let router = verification_router();
248
249 let request = Request::builder()
250 .method("POST")
251 .uri("/api/verification/count")
252 .header("Content-Type", "application/json")
253 .body(Body::empty())
254 .unwrap();
255
256 let response = router.oneshot(request).await.unwrap();
257 assert!(response.status().is_client_error() || response.status().is_server_error());
259 }
260
261 #[tokio::test]
262 async fn test_verification_router_has_sequence_route() {
263 let router = verification_router();
264
265 let request = Request::builder()
266 .method("POST")
267 .uri("/api/verification/sequence")
268 .header("Content-Type", "application/json")
269 .body(Body::empty())
270 .unwrap();
271
272 let response = router.oneshot(request).await.unwrap();
273 assert!(response.status().is_client_error() || response.status().is_server_error());
275 }
276
277 #[tokio::test]
278 async fn test_verification_router_has_never_route() {
279 let router = verification_router();
280
281 let request = Request::builder()
282 .method("POST")
283 .uri("/api/verification/never")
284 .header("Content-Type", "application/json")
285 .body(Body::empty())
286 .unwrap();
287
288 let response = router.oneshot(request).await.unwrap();
289 assert!(response.status().is_client_error() || response.status().is_server_error());
291 }
292
293 #[tokio::test]
294 async fn test_verification_router_has_at_least_route() {
295 let router = verification_router();
296
297 let request = Request::builder()
298 .method("POST")
299 .uri("/api/verification/at-least")
300 .header("Content-Type", "application/json")
301 .body(Body::empty())
302 .unwrap();
303
304 let response = router.oneshot(request).await.unwrap();
305 assert!(response.status().is_client_error() || response.status().is_server_error());
307 }
308
309 #[test]
312 fn test_verification_state_new() {
313 let state = VerificationState::new();
314 let _ = std::mem::size_of_val(&state);
316 }
317
318 #[test]
319 fn test_verification_state_default() {
320 let state = VerificationState::default();
321 let _ = std::mem::size_of_val(&state);
323 }
324
325 #[test]
326 fn test_verification_state_clone() {
327 let state = VerificationState::new();
328 let _cloned = state.clone();
329 }
331
332 #[test]
335 fn test_verify_request_creation() {
336 let pattern = VerificationRequest {
337 method: Some("GET".to_string()),
338 path: Some("/api/users".to_string()),
339 ..Default::default()
340 };
341
342 let verify_request = VerifyRequest {
343 pattern,
344 expected: VerificationCount::Exactly(1),
345 };
346
347 assert!(verify_request.pattern.method.is_some());
348 assert!(matches!(verify_request.expected, VerificationCount::Exactly(1)));
349 }
350
351 #[test]
352 fn test_verify_request_structure() {
353 let pattern = VerificationRequest {
354 method: Some("POST".to_string()),
355 path: Some("/api/create".to_string()),
356 ..Default::default()
357 };
358
359 let verify_request = VerifyRequest {
360 pattern,
361 expected: VerificationCount::AtLeast(2),
362 };
363
364 assert_eq!(verify_request.pattern.method, Some("POST".to_string()));
366 assert!(matches!(verify_request.expected, VerificationCount::AtLeast(2)));
367 }
368
369 #[test]
370 fn test_verify_request_clone() {
371 let pattern = VerificationRequest {
372 method: Some("GET".to_string()),
373 path: Some("/test".to_string()),
374 ..Default::default()
375 };
376
377 let verify_request = VerifyRequest {
378 pattern,
379 expected: VerificationCount::Exactly(5),
380 };
381
382 let cloned = verify_request.clone();
383 assert_eq!(cloned.pattern.method, verify_request.pattern.method);
384 }
385
386 #[test]
389 fn test_count_request_creation() {
390 let pattern = VerificationRequest {
391 method: Some("DELETE".to_string()),
392 path: Some("/api/users/123".to_string()),
393 ..Default::default()
394 };
395
396 let count_request = CountRequest { pattern };
397 assert_eq!(count_request.pattern.method, Some("DELETE".to_string()));
398 }
399
400 #[test]
401 fn test_count_request_serialization() {
402 let count_request = CountRequest {
403 pattern: VerificationRequest {
404 method: Some("PUT".to_string()),
405 path: Some("/api/update".to_string()),
406 ..Default::default()
407 },
408 };
409
410 let json = serde_json::to_string(&count_request);
411 assert!(json.is_ok());
412 }
413
414 #[test]
415 fn test_count_request_clone() {
416 let count_request = CountRequest {
417 pattern: VerificationRequest {
418 method: Some("GET".to_string()),
419 path: Some("/test".to_string()),
420 ..Default::default()
421 },
422 };
423
424 let cloned = count_request.clone();
425 assert_eq!(cloned.pattern.method, Some("GET".to_string()));
426 }
427
428 #[test]
431 fn test_count_response_creation() {
432 let response = CountResponse { count: 42 };
433 assert_eq!(response.count, 42);
434 }
435
436 #[test]
437 fn test_count_response_serialization() {
438 let response = CountResponse { count: 100 };
439 let json = serde_json::to_string(&response).unwrap();
440 assert!(json.contains("100"));
441 }
442
443 #[test]
444 fn test_count_response_deserialization() {
445 let json = r#"{"count":25}"#;
446 let response: CountResponse = serde_json::from_str(json).unwrap();
447 assert_eq!(response.count, 25);
448 }
449
450 #[test]
451 fn test_count_response_zero() {
452 let response = CountResponse { count: 0 };
453 assert_eq!(response.count, 0);
454 }
455
456 #[test]
459 fn test_sequence_request_creation() {
460 let patterns = vec![
461 VerificationRequest {
462 method: Some("POST".to_string()),
463 path: Some("/api/login".to_string()),
464 ..Default::default()
465 },
466 VerificationRequest {
467 method: Some("GET".to_string()),
468 path: Some("/api/profile".to_string()),
469 ..Default::default()
470 },
471 ];
472
473 let sequence_request = SequenceRequest { patterns };
474 assert_eq!(sequence_request.patterns.len(), 2);
475 }
476
477 #[test]
478 fn test_sequence_request_empty() {
479 let sequence_request = SequenceRequest { patterns: vec![] };
480 assert!(sequence_request.patterns.is_empty());
481 }
482
483 #[test]
484 fn test_sequence_request_serialization() {
485 let sequence_request = SequenceRequest {
486 patterns: vec![VerificationRequest {
487 method: Some("GET".to_string()),
488 path: Some("/health".to_string()),
489 ..Default::default()
490 }],
491 };
492
493 let json = serde_json::to_string(&sequence_request);
494 assert!(json.is_ok());
495 }
496
497 #[test]
500 fn test_at_least_request_creation() {
501 let request = AtLeastRequest {
502 pattern: VerificationRequest {
503 method: Some("GET".to_string()),
504 path: Some("/api/data".to_string()),
505 ..Default::default()
506 },
507 min: 3,
508 };
509
510 assert_eq!(request.min, 3);
511 assert_eq!(request.pattern.method, Some("GET".to_string()));
512 }
513
514 #[test]
515 fn test_at_least_request_serialization() {
516 let request = AtLeastRequest {
517 pattern: VerificationRequest {
518 method: Some("POST".to_string()),
519 path: Some("/api/submit".to_string()),
520 ..Default::default()
521 },
522 min: 5,
523 };
524
525 let json = serde_json::to_string(&request);
526 assert!(json.is_ok());
527 }
528
529 #[test]
530 fn test_at_least_request_clone() {
531 let request = AtLeastRequest {
532 pattern: VerificationRequest {
533 method: Some("GET".to_string()),
534 path: Some("/test".to_string()),
535 ..Default::default()
536 },
537 min: 2,
538 };
539
540 let cloned = request.clone();
541 assert_eq!(cloned.min, 2);
542 assert_eq!(cloned.pattern.method, Some("GET".to_string()));
543 }
544}