1use axum::extract::State;
7use axum::response::Json;
8use mockforge_core::{
9 request_logger::get_global_logger,
10 verification::{
11 verify_at_least, verify_never, verify_requests, verify_sequence, VerificationCount,
12 VerificationRequest, VerificationResult,
13 },
14};
15use serde::{Deserialize, Serialize};
16
17use crate::handlers::AdminState;
18use crate::models::ApiResponse;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct VerifyRequest {
23 pub pattern: VerificationRequest,
25 pub expected: VerificationCount,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct CountRequest {
32 pub pattern: VerificationRequest,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct CountResponse {
39 pub count: usize,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct SequenceRequest {
46 pub patterns: Vec<VerificationRequest>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct AtLeastRequest {
53 pub pattern: VerificationRequest,
55 pub min: usize,
57}
58
59pub async fn verify(
61 State(_state): State<AdminState>,
62 axum::extract::Json(request): axum::extract::Json<VerifyRequest>,
63) -> Json<ApiResponse<VerificationResult>> {
64 let logger = match get_global_logger() {
65 Some(logger) => logger,
66 None => {
67 return Json(ApiResponse::error("Request logger not initialized".to_string()));
68 }
69 };
70
71 let result = verify_requests(logger, &request.pattern, request.expected).await;
72
73 if result.matched {
74 Json(ApiResponse::success(result))
75 } else {
76 Json(ApiResponse::error(result.error_message.unwrap_or_else(|| {
77 format!(
78 "Verification failed: expected {:?}, but found {} matching requests",
79 result.expected, result.count
80 )
81 })))
82 }
83}
84
85pub async fn count(
87 State(_state): State<AdminState>,
88 axum::extract::Json(request): axum::extract::Json<CountRequest>,
89) -> Json<ApiResponse<CountResponse>> {
90 let logger = match get_global_logger() {
91 Some(logger) => logger,
92 None => {
93 return Json(ApiResponse::error("Request logger not initialized".to_string()));
94 }
95 };
96
97 let count = logger.count_matching_requests(&request.pattern).await;
98
99 Json(ApiResponse::success(CountResponse { count }))
100}
101
102pub async fn verify_sequence_handler(
104 State(_state): State<AdminState>,
105 axum::extract::Json(request): axum::extract::Json<SequenceRequest>,
106) -> Json<ApiResponse<VerificationResult>> {
107 let logger = match get_global_logger() {
108 Some(logger) => logger,
109 None => {
110 return Json(ApiResponse::error("Request logger not initialized".to_string()));
111 }
112 };
113
114 let result = verify_sequence(logger, &request.patterns).await;
115
116 if result.matched {
117 Json(ApiResponse::success(result))
118 } else {
119 Json(ApiResponse::error(
120 result
121 .error_message
122 .unwrap_or_else(|| "Sequence verification failed".to_string()),
123 ))
124 }
125}
126
127pub async fn verify_never_handler(
129 State(_state): State<AdminState>,
130 axum::extract::Json(pattern): axum::extract::Json<VerificationRequest>,
131) -> Json<ApiResponse<VerificationResult>> {
132 let logger = match get_global_logger() {
133 Some(logger) => logger,
134 None => {
135 return Json(ApiResponse::error("Request logger not initialized".to_string()));
136 }
137 };
138
139 let result = verify_never(logger, &pattern).await;
140
141 if result.matched {
142 Json(ApiResponse::success(result))
143 } else {
144 Json(ApiResponse::error(
145 result.error_message.unwrap_or_else(|| {
146 format!(
147 "Verification failed: expected request to never occur, but found {} matching requests",
148 result.count
149 )
150 }),
151 ))
152 }
153}
154
155pub async fn verify_at_least_handler(
157 State(_state): State<AdminState>,
158 axum::extract::Json(request): axum::extract::Json<AtLeastRequest>,
159) -> Json<ApiResponse<VerificationResult>> {
160 let logger = match get_global_logger() {
161 Some(logger) => logger,
162 None => {
163 return Json(ApiResponse::error("Request logger not initialized".to_string()));
164 }
165 };
166
167 let result = verify_at_least(logger, &request.pattern, request.min).await;
168
169 if result.matched {
170 Json(ApiResponse::success(result))
171 } else {
172 Json(ApiResponse::error(result.error_message.unwrap_or_else(|| {
173 format!(
174 "Verification failed: expected at least {} requests, but found {}",
175 request.min, result.count
176 )
177 })))
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[test]
188 fn test_verify_request_creation() {
189 let pattern = VerificationRequest {
190 method: Some("GET".to_string()),
191 path: Some("/api/users".to_string()),
192 ..Default::default()
193 };
194
195 let request = VerifyRequest {
196 pattern,
197 expected: VerificationCount::Exactly(1),
198 };
199
200 assert!(request.pattern.method.is_some());
201 assert_eq!(request.pattern.method.unwrap(), "GET");
202 }
203
204 #[test]
205 fn test_verify_request_structure() {
206 let request = VerifyRequest {
207 pattern: VerificationRequest {
208 method: Some("POST".to_string()),
209 path: Some("/api/orders".to_string()),
210 ..Default::default()
211 },
212 expected: VerificationCount::AtLeast(2),
213 };
214
215 assert_eq!(request.pattern.method, Some("POST".to_string()));
217 assert_eq!(request.pattern.path, Some("/api/orders".to_string()));
218 }
219
220 #[test]
221 fn test_verify_request_pattern_fields() {
222 let pattern = VerificationRequest {
223 method: Some("DELETE".to_string()),
224 path: Some("/api/items/123".to_string()),
225 ..Default::default()
226 };
227
228 let request = VerifyRequest {
229 pattern,
230 expected: VerificationCount::Exactly(1),
231 };
232
233 assert_eq!(request.pattern.method, Some("DELETE".to_string()));
234 assert_eq!(request.pattern.path, Some("/api/items/123".to_string()));
235 }
236
237 #[test]
238 fn test_verify_request_clone() {
239 let request = VerifyRequest {
240 pattern: VerificationRequest {
241 method: Some("PUT".to_string()),
242 path: None,
243 ..Default::default()
244 },
245 expected: VerificationCount::Never,
246 };
247
248 let cloned = request.clone();
249 assert_eq!(cloned.pattern.method, request.pattern.method);
250 }
251
252 #[test]
255 fn test_count_request_creation() {
256 let request = CountRequest {
257 pattern: VerificationRequest {
258 method: Some("GET".to_string()),
259 path: Some("/health".to_string()),
260 ..Default::default()
261 },
262 };
263
264 assert_eq!(request.pattern.method, Some("GET".to_string()));
265 }
266
267 #[test]
268 fn test_count_request_serialization() {
269 let request = CountRequest {
270 pattern: VerificationRequest {
271 method: Some("POST".to_string()),
272 path: Some("/api/data".to_string()),
273 ..Default::default()
274 },
275 };
276
277 let json = serde_json::to_string(&request).unwrap();
278 assert!(json.contains("POST"));
279 assert!(json.contains("/api/data"));
280 }
281
282 #[test]
283 fn test_count_request_clone() {
284 let request = CountRequest {
285 pattern: VerificationRequest {
286 method: Some("GET".to_string()),
287 ..Default::default()
288 },
289 };
290
291 let cloned = request.clone();
292 assert_eq!(cloned.pattern.method, request.pattern.method);
293 }
294
295 #[test]
298 fn test_count_response_creation() {
299 let response = CountResponse { count: 42 };
300 assert_eq!(response.count, 42);
301 }
302
303 #[test]
304 fn test_count_response_serialization() {
305 let response = CountResponse { count: 100 };
306 let json = serde_json::to_string(&response).unwrap();
307 assert!(json.contains("100"));
308 }
309
310 #[test]
311 fn test_count_response_deserialization() {
312 let json = r#"{"count": 25}"#;
313 let response: CountResponse = serde_json::from_str(json).unwrap();
314 assert_eq!(response.count, 25);
315 }
316
317 #[test]
318 fn test_count_response_clone() {
319 let response = CountResponse { count: 10 };
320 let cloned = response.clone();
321 assert_eq!(cloned.count, response.count);
322 }
323
324 #[test]
325 fn test_count_response_zero() {
326 let response = CountResponse { count: 0 };
327 assert_eq!(response.count, 0);
328 }
329
330 #[test]
333 fn test_sequence_request_creation() {
334 let request = SequenceRequest {
335 patterns: vec![
336 VerificationRequest {
337 method: Some("POST".to_string()),
338 path: Some("/api/login".to_string()),
339 ..Default::default()
340 },
341 VerificationRequest {
342 method: Some("GET".to_string()),
343 path: Some("/api/profile".to_string()),
344 ..Default::default()
345 },
346 ],
347 };
348
349 assert_eq!(request.patterns.len(), 2);
350 }
351
352 #[test]
353 fn test_sequence_request_empty() {
354 let request = SequenceRequest { patterns: vec![] };
355 assert!(request.patterns.is_empty());
356 }
357
358 #[test]
359 fn test_sequence_request_serialization() {
360 let request = SequenceRequest {
361 patterns: vec![VerificationRequest {
362 method: Some("GET".to_string()),
363 ..Default::default()
364 }],
365 };
366
367 let json = serde_json::to_string(&request).unwrap();
368 assert!(json.contains("GET"));
369 }
370
371 #[test]
372 fn test_sequence_request_clone() {
373 let request = SequenceRequest {
374 patterns: vec![VerificationRequest {
375 method: Some("POST".to_string()),
376 ..Default::default()
377 }],
378 };
379
380 let cloned = request.clone();
381 assert_eq!(cloned.patterns.len(), request.patterns.len());
382 }
383
384 #[test]
387 fn test_at_least_request_creation() {
388 let request = AtLeastRequest {
389 pattern: VerificationRequest {
390 method: Some("GET".to_string()),
391 path: Some("/api/users".to_string()),
392 ..Default::default()
393 },
394 min: 5,
395 };
396
397 assert_eq!(request.min, 5);
398 }
399
400 #[test]
401 fn test_at_least_request_serialization() {
402 let request = AtLeastRequest {
403 pattern: VerificationRequest {
404 method: Some("POST".to_string()),
405 ..Default::default()
406 },
407 min: 10,
408 };
409
410 let json = serde_json::to_string(&request).unwrap();
411 assert!(json.contains("10"));
412 }
413
414 #[test]
415 fn test_at_least_request_pattern() {
416 let request = AtLeastRequest {
417 pattern: VerificationRequest {
418 method: Some("DELETE".to_string()),
419 ..Default::default()
420 },
421 min: 3,
422 };
423
424 assert_eq!(request.min, 3);
425 assert_eq!(request.pattern.method, Some("DELETE".to_string()));
426 }
427
428 #[test]
429 fn test_at_least_request_clone() {
430 let request = AtLeastRequest {
431 pattern: VerificationRequest::default(),
432 min: 1,
433 };
434
435 let cloned = request.clone();
436 assert_eq!(cloned.min, request.min);
437 }
438
439 #[test]
440 fn test_at_least_request_zero_min() {
441 let request = AtLeastRequest {
442 pattern: VerificationRequest::default(),
443 min: 0,
444 };
445
446 assert_eq!(request.min, 0);
447 }
448
449 #[test]
452 fn test_verify_request_debug() {
453 let request = VerifyRequest {
454 pattern: VerificationRequest::default(),
455 expected: VerificationCount::Exactly(1),
456 };
457
458 let debug = format!("{:?}", request);
459 assert!(debug.contains("VerifyRequest"));
460 }
461
462 #[test]
463 fn test_count_request_debug() {
464 let request = CountRequest {
465 pattern: VerificationRequest::default(),
466 };
467
468 let debug = format!("{:?}", request);
469 assert!(debug.contains("CountRequest"));
470 }
471
472 #[test]
473 fn test_count_response_debug() {
474 let response = CountResponse { count: 5 };
475 let debug = format!("{:?}", response);
476 assert!(debug.contains("5"));
477 }
478
479 #[test]
480 fn test_sequence_request_debug() {
481 let request = SequenceRequest { patterns: vec![] };
482 let debug = format!("{:?}", request);
483 assert!(debug.contains("SequenceRequest"));
484 }
485
486 #[test]
487 fn test_at_least_request_debug() {
488 let request = AtLeastRequest {
489 pattern: VerificationRequest::default(),
490 min: 2,
491 };
492
493 let debug = format!("{:?}", request);
494 assert!(debug.contains("AtLeastRequest"));
495 }
496}