mockforge_http/
verification.rs1use 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 axum::http::StatusCode;
218 use tower::ServiceExt;
219
220 #[tokio::test]
221 async fn test_verification_router_creation() {
222 let router = verification_router();
223 assert!(true);
225 }
226}