1pub mod database;
53pub mod federation;
54pub mod router;
55pub mod service;
56
57pub use database::FederationDatabase;
58pub use federation::{Federation, FederationConfig, FederationService};
59pub use router::{FederationRouter, RoutingResult};
60pub use service::{ServiceBoundary, ServiceRealityLevel};
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65 use std::collections::HashMap;
66 use std::sync::Arc;
67 use uuid::Uuid;
68
69 #[test]
72 fn test_service_reality_level_public_api() {
73 let level = ServiceRealityLevel::Real;
75 assert_eq!(level.as_str(), "real");
76
77 let parsed = ServiceRealityLevel::from_str("mock_v3");
78 assert_eq!(parsed, Some(ServiceRealityLevel::MockV3));
79 }
80
81 #[test]
82 fn test_service_boundary_public_api() {
83 let workspace_id = Uuid::new_v4();
85 let service = ServiceBoundary::new(
86 "test-service".to_string(),
87 workspace_id,
88 "/api".to_string(),
89 ServiceRealityLevel::Blended,
90 );
91
92 assert_eq!(service.name, "test-service");
93 assert_eq!(service.workspace_id, workspace_id);
94 assert_eq!(service.base_path, "/api");
95 assert_eq!(service.reality_level, ServiceRealityLevel::Blended);
96 assert!(service.matches_path("/api/users"));
97 assert!(!service.matches_path("/other"));
98 }
99
100 #[test]
101 fn test_federation_config_public_api() {
102 let config = FederationConfig {
104 name: "test-fed".to_string(),
105 description: "Test federation".to_string(),
106 services: vec![FederationService {
107 name: "service1".to_string(),
108 workspace_id: Uuid::new_v4().to_string(),
109 base_path: "/service1".to_string(),
110 reality_level: "real".to_string(),
111 config: HashMap::new(),
112 dependencies: Vec::new(),
113 }],
114 };
115
116 assert_eq!(config.name, "test-fed");
117 assert_eq!(config.services.len(), 1);
118
119 let json = serde_json::to_string(&config).unwrap();
121 assert!(json.contains("test-fed"));
122 }
123
124 #[test]
125 fn test_federation_public_api() {
126 let org_id = Uuid::new_v4();
128 let config = FederationConfig {
129 name: "my-federation".to_string(),
130 description: "My test federation".to_string(),
131 services: vec![FederationService {
132 name: "auth".to_string(),
133 workspace_id: Uuid::new_v4().to_string(),
134 base_path: "/auth".to_string(),
135 reality_level: "real".to_string(),
136 config: HashMap::new(),
137 dependencies: Vec::new(),
138 }],
139 };
140
141 let federation = Federation::from_config(org_id, config).unwrap();
142
143 assert_eq!(federation.name, "my-federation");
144 assert_eq!(federation.org_id, org_id);
145 assert_eq!(federation.services.len(), 1);
146 assert_eq!(federation.services[0].name, "auth");
147 }
148
149 #[test]
150 fn test_federation_router_public_api() {
151 let org_id = Uuid::new_v4();
153 let workspace_id = Uuid::new_v4();
154
155 let config = FederationConfig {
156 name: "router-test".to_string(),
157 description: String::new(),
158 services: vec![
159 FederationService {
160 name: "auth".to_string(),
161 workspace_id: workspace_id.to_string(),
162 base_path: "/auth".to_string(),
163 reality_level: "real".to_string(),
164 config: HashMap::new(),
165 dependencies: Vec::new(),
166 },
167 FederationService {
168 name: "payments".to_string(),
169 workspace_id: Uuid::new_v4().to_string(),
170 base_path: "/payments".to_string(),
171 reality_level: "mock_v3".to_string(),
172 config: HashMap::new(),
173 dependencies: Vec::new(),
174 },
175 ],
176 };
177
178 let federation = Federation::from_config(org_id, config).unwrap();
179 let router = FederationRouter::new(Arc::new(federation));
180
181 let result = router.route("/auth/login").unwrap();
183 assert_eq!(result.service.name, "auth");
184 assert_eq!(result.workspace_id, workspace_id);
185 assert_eq!(result.service_path, "/login");
186
187 assert!(router.route("/unknown").is_none());
189 }
190
191 #[test]
192 fn test_routing_result_public_api() {
193 let workspace_id = Uuid::new_v4();
195 let service = Arc::new(ServiceBoundary::new(
196 "test".to_string(),
197 workspace_id,
198 "/test".to_string(),
199 ServiceRealityLevel::Real,
200 ));
201
202 let result = RoutingResult {
203 workspace_id,
204 service,
205 service_path: "/path".to_string(),
206 };
207
208 assert_eq!(result.workspace_id, workspace_id);
209 assert_eq!(result.service.name, "test");
210 assert_eq!(result.service_path, "/path");
211
212 let cloned = result.clone();
214 assert_eq!(cloned.workspace_id, result.workspace_id);
215 }
216
217 #[test]
218 fn test_federation_service_with_config() {
219 let mut config = HashMap::new();
221 config.insert("timeout".to_string(), serde_json::json!(3000));
222 config.insert("retries".to_string(), serde_json::json!(5));
223
224 let service = FederationService {
225 name: "api".to_string(),
226 workspace_id: Uuid::new_v4().to_string(),
227 base_path: "/api".to_string(),
228 reality_level: "blended".to_string(),
229 config: config.clone(),
230 dependencies: vec!["auth".to_string(), "db".to_string()],
231 };
232
233 assert_eq!(service.config.len(), 2);
234 assert_eq!(service.dependencies.len(), 2);
235
236 let json = serde_json::to_string(&service).unwrap();
238 let deserialized: FederationService = serde_json::from_str(&json).unwrap();
239 assert_eq!(deserialized.name, service.name);
240 assert_eq!(deserialized.config.len(), service.config.len());
241 }
242
243 #[test]
244 fn test_all_reality_levels_exposed() {
245 assert_eq!(ServiceRealityLevel::Real.as_str(), "real");
248 assert_eq!(ServiceRealityLevel::MockV3.as_str(), "mock_v3");
249 assert_eq!(ServiceRealityLevel::Blended.as_str(), "blended");
250 assert_eq!(ServiceRealityLevel::ChaosDriven.as_str(), "chaos_driven");
251
252 assert_eq!(ServiceRealityLevel::Real.as_str(), "real");
254 assert_eq!(ServiceRealityLevel::MockV3.as_str(), "mock_v3");
255 assert_eq!(ServiceRealityLevel::Blended.as_str(), "blended");
256 assert_eq!(ServiceRealityLevel::ChaosDriven.as_str(), "chaos_driven");
257 }
258
259 #[test]
260 fn test_federation_mutation_methods() {
261 let org_id = Uuid::new_v4();
263 let config = FederationConfig {
264 name: "mutable-fed".to_string(),
265 description: String::new(),
266 services: vec![FederationService {
267 name: "initial".to_string(),
268 workspace_id: Uuid::new_v4().to_string(),
269 base_path: "/initial".to_string(),
270 reality_level: "real".to_string(),
271 config: HashMap::new(),
272 dependencies: Vec::new(),
273 }],
274 };
275
276 let mut federation = Federation::from_config(org_id, config).unwrap();
277 assert_eq!(federation.services.len(), 1);
278
279 federation.add_service(ServiceBoundary::new(
281 "added".to_string(),
282 Uuid::new_v4(),
283 "/added".to_string(),
284 ServiceRealityLevel::MockV3,
285 ));
286 assert_eq!(federation.services.len(), 2);
287
288 let removed = federation.remove_service("initial");
290 assert!(removed);
291 assert_eq!(federation.services.len(), 1);
292 assert_eq!(federation.services[0].name, "added");
293 }
294
295 #[test]
296 fn test_service_path_extraction() {
297 let service = ServiceBoundary::new(
299 "api".to_string(),
300 Uuid::new_v4(),
301 "/api/v1".to_string(),
302 ServiceRealityLevel::Real,
303 );
304
305 assert_eq!(service.extract_service_path("/api/v1/users"), Some("/users".to_string()));
306 assert_eq!(service.extract_service_path("/api/v1"), Some("/".to_string()));
307 assert_eq!(service.extract_service_path("/other"), None);
308 }
309
310 #[test]
311 fn test_federation_service_lookup() {
312 let org_id = Uuid::new_v4();
314 let config = FederationConfig {
315 name: "lookup-test".to_string(),
316 description: String::new(),
317 services: vec![
318 FederationService {
319 name: "service-a".to_string(),
320 workspace_id: Uuid::new_v4().to_string(),
321 base_path: "/a".to_string(),
322 reality_level: "real".to_string(),
323 config: HashMap::new(),
324 dependencies: Vec::new(),
325 },
326 FederationService {
327 name: "service-b".to_string(),
328 workspace_id: Uuid::new_v4().to_string(),
329 base_path: "/b".to_string(),
330 reality_level: "mock_v3".to_string(),
331 config: HashMap::new(),
332 dependencies: Vec::new(),
333 },
334 ],
335 };
336
337 let federation = Federation::from_config(org_id, config).unwrap();
338
339 let service_a = federation.get_service("service-a");
341 assert!(service_a.is_some());
342 assert_eq!(service_a.unwrap().base_path, "/a");
343
344 let service_b = federation.find_service_by_path("/b/endpoint");
346 assert!(service_b.is_some());
347 assert_eq!(service_b.unwrap().name, "service-b");
348 }
349
350 #[test]
351 fn test_complete_workflow() {
352 let org_id = Uuid::new_v4();
354
355 let config = FederationConfig {
357 name: "e-commerce".to_string(),
358 description: "E-commerce platform federation".to_string(),
359 services: vec![
360 FederationService {
361 name: "auth".to_string(),
362 workspace_id: Uuid::new_v4().to_string(),
363 base_path: "/auth".to_string(),
364 reality_level: "real".to_string(),
365 config: HashMap::new(),
366 dependencies: Vec::new(),
367 },
368 FederationService {
369 name: "catalog".to_string(),
370 workspace_id: Uuid::new_v4().to_string(),
371 base_path: "/catalog".to_string(),
372 reality_level: "mock_v3".to_string(),
373 config: HashMap::new(),
374 dependencies: vec!["auth".to_string()],
375 },
376 ],
377 };
378
379 let federation = Federation::from_config(org_id, config).unwrap();
381 assert_eq!(federation.services.len(), 2);
382
383 let router = FederationRouter::new(Arc::new(federation));
385
386 let auth_route = router.route("/auth/login").unwrap();
388 assert_eq!(auth_route.service.name, "auth");
389 assert_eq!(auth_route.service.reality_level, ServiceRealityLevel::Real);
390
391 let catalog_route = router.route("/catalog/products/123").unwrap();
392 assert_eq!(catalog_route.service.name, "catalog");
393 assert_eq!(catalog_route.service_path, "/products/123");
394 assert_eq!(catalog_route.service.reality_level, ServiceRealityLevel::MockV3);
395
396 let catalog_service = router.services().iter().find(|s| s.name == "catalog").unwrap();
398 assert_eq!(catalog_service.dependencies, vec!["auth".to_string()]);
399 }
400
401 #[test]
402 fn test_yaml_config_roundtrip() {
403 let config = FederationConfig {
405 name: "yaml-test".to_string(),
406 description: "Testing YAML".to_string(),
407 services: vec![FederationService {
408 name: "test".to_string(),
409 workspace_id: Uuid::new_v4().to_string(),
410 base_path: "/test".to_string(),
411 reality_level: "real".to_string(),
412 config: HashMap::new(),
413 dependencies: Vec::new(),
414 }],
415 };
416
417 let yaml = serde_yaml::to_string(&config).unwrap();
418 let deserialized: FederationConfig = serde_yaml::from_str(&yaml).unwrap();
419
420 assert_eq!(deserialized.name, config.name);
421 assert_eq!(deserialized.description, config.description);
422 assert_eq!(deserialized.services.len(), config.services.len());
423 }
424
425 #[test]
426 fn test_json_config_roundtrip() {
427 let mut service_config = HashMap::new();
429 service_config.insert("key".to_string(), serde_json::json!("value"));
430
431 let config = FederationConfig {
432 name: "json-test".to_string(),
433 description: "Testing JSON".to_string(),
434 services: vec![FederationService {
435 name: "test".to_string(),
436 workspace_id: Uuid::new_v4().to_string(),
437 base_path: "/test".to_string(),
438 reality_level: "blended".to_string(),
439 config: service_config,
440 dependencies: vec!["dep1".to_string()],
441 }],
442 };
443
444 let json = serde_json::to_string(&config).unwrap();
445 let deserialized: FederationConfig = serde_json::from_str(&json).unwrap();
446
447 assert_eq!(deserialized.name, config.name);
448 assert_eq!(deserialized.services[0].config.len(), 1);
449 assert_eq!(deserialized.services[0].dependencies.len(), 1);
450 }
451}