mockforge_http/
verification.rs1use axum::{
7 extract::State,
8 http::StatusCode,
9 response::IntoResponse,
10 routing::{get, post},
11 Json, Router,
12};
13use mockforge_core::{
14 request_logger::get_global_logger,
15 verification::{
16 verify_at_least, verify_never, verify_requests, verify_sequence, VerificationCount,
17 VerificationRequest, VerificationResult,
18 },
19};
20use serde::{Deserialize, Serialize};
21use std::sync::Arc;
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct VerifyRequest {
26 pub pattern: VerificationRequest,
28 pub expected: VerificationCount,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct CountRequest {
35 pub pattern: VerificationRequest,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct CountResponse {
42 pub count: usize,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct SequenceRequest {
49 pub patterns: Vec<VerificationRequest>,
51}
52
53#[derive(Clone)]
55pub struct VerificationState;
56
57impl VerificationState {
58 pub fn new() -> Self {
60 Self
61 }
62}
63
64pub fn verification_router() -> Router {
66 Router::new()
67 .route("/api/verification/verify", post(handle_verify))
68 .route("/api/verification/count", post(handle_count))
69 .route("/api/verification/sequence", post(handle_sequence))
70 .route("/api/verification/never", post(handle_never))
71 .route("/api/verification/at-least", post(handle_at_least))
72}
73
74async fn handle_verify(Json(request): Json<VerifyRequest>) -> impl IntoResponse {
76 let logger = match get_global_logger() {
77 Some(logger) => logger,
78 None => {
79 return (
80 StatusCode::SERVICE_UNAVAILABLE,
81 Json(VerificationResult::failure(
82 0,
83 request.expected.clone(),
84 Vec::new(),
85 "Request logger not initialized".to_string(),
86 )),
87 )
88 .into_response();
89 }
90 };
91
92 let result = verify_requests(logger, &request.pattern, request.expected).await;
93
94 let status = if result.matched {
95 StatusCode::OK
96 } else {
97 StatusCode::EXPECTATION_FAILED
98 };
99
100 (status, Json(result)).into_response()
101}
102
103async fn handle_count(Json(request): Json<CountRequest>) -> impl IntoResponse {
105 let logger = match get_global_logger() {
106 Some(logger) => logger,
107 None => {
108 return (StatusCode::SERVICE_UNAVAILABLE, Json(CountResponse { count: 0 }))
109 .into_response();
110 }
111 };
112
113 let count = logger.count_matching_requests(&request.pattern).await;
114
115 (StatusCode::OK, Json(CountResponse { count })).into_response()
116}
117
118async fn handle_sequence(Json(request): Json<SequenceRequest>) -> impl IntoResponse {
120 let logger = match get_global_logger() {
121 Some(logger) => logger,
122 None => {
123 return (
124 StatusCode::SERVICE_UNAVAILABLE,
125 Json(VerificationResult::failure(
126 0,
127 VerificationCount::Exactly(request.patterns.len()),
128 Vec::new(),
129 "Request logger not initialized".to_string(),
130 )),
131 )
132 .into_response();
133 }
134 };
135
136 let result = verify_sequence(logger, &request.patterns).await;
137
138 let status = if result.matched {
139 StatusCode::OK
140 } else {
141 StatusCode::EXPECTATION_FAILED
142 };
143
144 (status, Json(result)).into_response()
145}
146
147async fn handle_never(Json(request): Json<VerificationRequest>) -> impl IntoResponse {
149 let logger = match get_global_logger() {
150 Some(logger) => logger,
151 None => {
152 return (
153 StatusCode::SERVICE_UNAVAILABLE,
154 Json(VerificationResult::failure(
155 0,
156 VerificationCount::Never,
157 Vec::new(),
158 "Request logger not initialized".to_string(),
159 )),
160 )
161 .into_response();
162 }
163 };
164
165 let result = verify_never(logger, &request).await;
166
167 let status = if result.matched {
168 StatusCode::OK
169 } else {
170 StatusCode::EXPECTATION_FAILED
171 };
172
173 (status, Json(result)).into_response()
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
178struct AtLeastRequest {
179 pub pattern: VerificationRequest,
181 pub min: usize,
183}
184
185async fn handle_at_least(Json(request): Json<AtLeastRequest>) -> impl IntoResponse {
186 let logger = match get_global_logger() {
187 Some(logger) => logger,
188 None => {
189 return (
190 StatusCode::SERVICE_UNAVAILABLE,
191 Json(VerificationResult::failure(
192 0,
193 VerificationCount::AtLeast(request.min),
194 Vec::new(),
195 "Request logger not initialized".to_string(),
196 )),
197 )
198 .into_response();
199 }
200 };
201
202 let result = verify_at_least(logger, &request.pattern, request.min).await;
203
204 let status = if result.matched {
205 StatusCode::OK
206 } else {
207 StatusCode::EXPECTATION_FAILED
208 };
209
210 (status, Json(result)).into_response()
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use axum::body::Body;
217 use axum::http::Request;
218 use axum::http::StatusCode;
219 use tower::ServiceExt;
220
221 #[tokio::test]
222 async fn test_verification_router_creation() {
223 let router = verification_router();
224 assert!(true);
226 }
227}