mockforge_bench/
param_overrides.rs1use crate::error::{BenchError, Result};
37use serde::{Deserialize, Serialize};
38use serde_json::Value;
39use std::collections::HashMap;
40use std::path::Path;
41
42#[derive(Debug, Clone, Default, Serialize, Deserialize)]
44pub struct ParameterOverrides {
45 #[serde(default)]
47 pub defaults: OperationOverrides,
48
49 #[serde(default)]
51 pub operations: HashMap<String, OperationOverrides>,
52}
53
54#[derive(Debug, Clone, Default, Serialize, Deserialize)]
56pub struct OperationOverrides {
57 #[serde(default)]
59 pub path_params: HashMap<String, String>,
60
61 #[serde(default)]
63 pub query_params: HashMap<String, String>,
64
65 #[serde(default)]
67 pub headers: HashMap<String, String>,
68
69 #[serde(default)]
71 pub body: Option<Value>,
72}
73
74impl ParameterOverrides {
75 pub fn from_file(path: &Path) -> Result<Self> {
77 let content = std::fs::read_to_string(path).map_err(|e| {
78 BenchError::Other(format!("Failed to read params file '{}': {}", path.display(), e))
79 })?;
80
81 let extension = path.extension().and_then(|e| e.to_str()).unwrap_or("");
82
83 match extension.to_lowercase().as_str() {
84 "json" => serde_json::from_str(&content)
85 .map_err(|e| BenchError::Other(format!("Failed to parse JSON params file: {}", e))),
86 "yaml" | "yml" => serde_yaml::from_str(&content)
87 .map_err(|e| BenchError::Other(format!("Failed to parse YAML params file: {}", e))),
88 _ => {
89 serde_json::from_str(&content)
91 .or_else(|_| serde_yaml::from_str(&content))
92 .map_err(|e| {
93 BenchError::Other(format!(
94 "Failed to parse params file (tried JSON and YAML): {}",
95 e
96 ))
97 })
98 }
99 }
100 }
101
102 pub fn get_for_operation(
107 &self,
108 operation_id: Option<&str>,
109 method: &str,
110 path: &str,
111 ) -> OperationOverrides {
112 let mut result = self.defaults.clone();
113
114 let op_overrides = operation_id
116 .and_then(|id| self.operations.get(id))
117 .or_else(|| {
118 let key = format!("{} {}", method.to_uppercase(), path);
120 self.operations.get(&key)
121 })
122 .or_else(|| {
123 self.operations.get(path)
125 });
126
127 if let Some(overrides) = op_overrides {
128 for (k, v) in &overrides.path_params {
130 result.path_params.insert(k.clone(), v.clone());
131 }
132 for (k, v) in &overrides.query_params {
133 result.query_params.insert(k.clone(), v.clone());
134 }
135 for (k, v) in &overrides.headers {
136 result.headers.insert(k.clone(), v.clone());
137 }
138 if overrides.body.is_some() {
139 result.body = overrides.body.clone();
140 }
141 }
142
143 result
144 }
145
146 pub fn is_empty(&self) -> bool {
148 self.defaults.is_empty() && self.operations.is_empty()
149 }
150}
151
152impl OperationOverrides {
153 pub fn is_empty(&self) -> bool {
155 self.path_params.is_empty()
156 && self.query_params.is_empty()
157 && self.headers.is_empty()
158 && self.body.is_none()
159 }
160
161 pub fn get_path_param(&self, name: &str) -> Option<&String> {
163 self.path_params.get(name)
164 }
165
166 pub fn get_query_param(&self, name: &str) -> Option<&String> {
168 self.query_params.get(name)
169 }
170
171 pub fn get_header(&self, name: &str) -> Option<&String> {
173 self.headers.get(name)
174 }
175
176 pub fn get_body(&self) -> Option<&Value> {
178 self.body.as_ref()
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use serde_json::json;
186
187 #[test]
188 fn test_parse_json_overrides() {
189 let json = r#"{
190 "defaults": {
191 "path_params": {
192 "id": "default-id"
193 },
194 "query_params": {
195 "limit": "50"
196 }
197 },
198 "operations": {
199 "getUser": {
200 "path_params": {
201 "id": "user-123"
202 }
203 },
204 "POST /users": {
205 "body": {
206 "name": "Test User"
207 }
208 }
209 }
210 }"#;
211
212 let overrides: ParameterOverrides = serde_json::from_str(json).unwrap();
213
214 assert_eq!(overrides.defaults.path_params.get("id"), Some(&"default-id".to_string()));
216 assert_eq!(overrides.defaults.query_params.get("limit"), Some(&"50".to_string()));
217
218 let get_user = overrides.operations.get("getUser").unwrap();
220 assert_eq!(get_user.path_params.get("id"), Some(&"user-123".to_string()));
221
222 let post_users = overrides.operations.get("POST /users").unwrap();
223 assert!(post_users.body.is_some());
224 }
225
226 #[test]
227 fn test_get_for_operation_with_defaults() {
228 let overrides = ParameterOverrides {
229 defaults: OperationOverrides {
230 path_params: [("id".to_string(), "default-id".to_string())].into_iter().collect(),
231 query_params: [("limit".to_string(), "10".to_string())].into_iter().collect(),
232 ..Default::default()
233 },
234 operations: HashMap::new(),
235 };
236
237 let result = overrides.get_for_operation(Some("unknownOp"), "GET", "/users");
238 assert_eq!(result.path_params.get("id"), Some(&"default-id".to_string()));
239 assert_eq!(result.query_params.get("limit"), Some(&"10".to_string()));
240 }
241
242 #[test]
243 fn test_get_for_operation_with_override() {
244 let mut operations = HashMap::new();
245 operations.insert(
246 "getUser".to_string(),
247 OperationOverrides {
248 path_params: [("id".to_string(), "user-456".to_string())].into_iter().collect(),
249 ..Default::default()
250 },
251 );
252
253 let overrides = ParameterOverrides {
254 defaults: OperationOverrides {
255 path_params: [("id".to_string(), "default-id".to_string())].into_iter().collect(),
256 ..Default::default()
257 },
258 operations,
259 };
260
261 let result = overrides.get_for_operation(Some("getUser"), "GET", "/users/{id}");
263 assert_eq!(result.path_params.get("id"), Some(&"user-456".to_string()));
264 }
265
266 #[test]
267 fn test_get_for_operation_by_method_path() {
268 let mut operations = HashMap::new();
269 operations.insert(
270 "POST /virtualservice".to_string(),
271 OperationOverrides {
272 body: Some(json!({"name": "my-service"})),
273 ..Default::default()
274 },
275 );
276
277 let overrides = ParameterOverrides {
278 defaults: OperationOverrides::default(),
279 operations,
280 };
281
282 let result = overrides.get_for_operation(None, "POST", "/virtualservice");
283 assert!(result.body.is_some());
284 assert_eq!(result.body.unwrap()["name"], "my-service");
285 }
286
287 #[test]
288 fn test_empty_overrides() {
289 let overrides = ParameterOverrides::default();
290 assert!(overrides.is_empty());
291
292 let result = overrides.get_for_operation(Some("anyOp"), "GET", "/any");
293 assert!(result.is_empty());
294 }
295}