mockforge_grpc/reflection/
integration_tests.rs

1//! Integration tests for advanced data synthesis features
2//!
3//! This module contains comprehensive tests that demonstrate the full
4//! data synthesis pipeline including SmartMockGenerator, RAG synthesis,
5//! schema graph extraction, and validation framework integration.
6
7#[cfg(test)]
8mod tests {
9    use crate::reflection::{
10        rag_synthesis::{RagDataSynthesizer, RagSynthesisConfig},
11        schema_graph::SchemaGraph,
12        smart_mock_generator::{SmartMockConfig, SmartMockGenerator},
13        validation_framework::{
14            CustomValidationRule, GeneratedEntity, ValidationConfig, ValidationFramework,
15            ValidationRuleType,
16        },
17    };
18
19    use std::collections::HashMap;
20    use std::time::SystemTime;
21
22    /// Test the complete data synthesis pipeline
23    #[tokio::test]
24    async fn test_complete_data_synthesis_pipeline() {
25        // Step 1: Create a deterministic smart mock generator
26        let config = SmartMockConfig {
27            field_name_inference: true,
28            use_faker: true,
29            field_overrides: HashMap::new(),
30            service_profiles: HashMap::new(),
31            max_depth: 3,
32            seed: Some(12345),
33            deterministic: true,
34        };
35
36        let _generator = SmartMockGenerator::new_with_seed(config, 12345);
37
38        // Step 2: Create RAG synthesizer
39        let rag_config = RagSynthesisConfig {
40            enabled: false, // Disable for testing without external dependencies
41            rag_config: None,
42            context_sources: vec![],
43            prompt_templates: HashMap::new(),
44            max_context_length: 2000,
45            cache_contexts: true,
46        };
47
48        let _rag_synthesizer = RagDataSynthesizer::new(rag_config);
49
50        // Step 3: Create validation framework
51        let validation_config = ValidationConfig {
52            enabled: true,
53            strict_mode: false,
54            max_validation_depth: 3,
55            custom_rules: vec![CustomValidationRule {
56                name: "email_format".to_string(),
57                applies_to_entities: vec!["User".to_string()],
58                validates_fields: vec!["email".to_string()],
59                rule_type: ValidationRuleType::FieldFormat,
60                parameters: HashMap::from([(
61                    "pattern".to_string(),
62                    r"^[^@\s]+@[^@\s]+\.[^@\s]+$".to_string(),
63                )]),
64                error_message: "Invalid email format".to_string(),
65            }],
66            cache_results: true,
67        };
68
69        let mut validator = ValidationFramework::new(validation_config);
70
71        // Step 4: Generate multiple entities and validate them
72        let entities = vec![
73            GeneratedEntity {
74                entity_type: "User".to_string(),
75                primary_key: Some("user_1".to_string()),
76                field_values: HashMap::from([
77                    ("id".to_string(), "user_1".to_string()),
78                    ("name".to_string(), "John Doe".to_string()),
79                    ("email".to_string(), "john@example.com".to_string()),
80                ]),
81                endpoint: "/users".to_string(),
82                generated_at: SystemTime::now(),
83            },
84            GeneratedEntity {
85                entity_type: "Order".to_string(),
86                primary_key: Some("order_1".to_string()),
87                field_values: HashMap::from([
88                    ("id".to_string(), "order_1".to_string()),
89                    ("user_id".to_string(), "user_1".to_string()),
90                    ("total".to_string(), "99.99".to_string()),
91                ]),
92                endpoint: "/orders".to_string(),
93                generated_at: SystemTime::now(),
94            },
95        ];
96
97        // Register entities with validator
98        for entity in entities {
99            validator.register_entity(entity).expect("Should register entity");
100        }
101
102        // Step 5: Run validation
103        let validation_result = validator.validate_all_entities();
104
105        // Verify validation results
106        assert!(validation_result.is_valid, "Validation should pass");
107        assert!(validation_result.errors.is_empty(), "Should have no validation errors");
108
109        let stats = validator.get_statistics();
110        assert_eq!(stats.total_entities, 2);
111        assert_eq!(stats.entity_type_count, 2);
112    }
113
114    #[test]
115    fn test_deterministic_data_generation() {
116        // Create two identical generators with same seed
117        let config = SmartMockConfig {
118            seed: Some(999),
119            deterministic: true,
120            ..Default::default()
121        };
122
123        let mut gen1 = SmartMockGenerator::new(config.clone());
124        let mut gen2 = SmartMockGenerator::new(config);
125
126        // Generate UUIDs - should be identical
127        let uuid1 = gen1.generate_uuid();
128        let uuid2 = gen2.generate_uuid();
129        assert_eq!(uuid1, uuid2, "Deterministic generators should produce identical UUIDs");
130
131        // Generate strings - should be identical
132        let str1 = gen1.generate_random_string(10);
133        let str2 = gen2.generate_random_string(10);
134        assert_eq!(str1, str2, "Deterministic generators should produce identical strings");
135    }
136
137    #[test]
138    fn test_validation_with_foreign_key_violations() {
139        let mut validator = ValidationFramework::new(ValidationConfig::default());
140
141        // Create a mock schema graph with foreign key relationships
142        let schema_graph = SchemaGraph {
143            entities: HashMap::new(),
144            relationships: vec![],
145            foreign_keys: HashMap::from([(
146                "Order".to_string(),
147                vec![crate::reflection::schema_graph::ForeignKeyMapping {
148                    field_name: "user_id".to_string(),
149                    target_entity: "User".to_string(),
150                    confidence: 0.9,
151                    detection_method:
152                        crate::reflection::schema_graph::ForeignKeyDetectionMethod::NamingConvention,
153                }],
154            )]),
155        };
156
157        validator.set_schema_graph(schema_graph);
158
159        // Register an order without corresponding user
160        let order_entity = GeneratedEntity {
161            entity_type: "Order".to_string(),
162            primary_key: Some("order_1".to_string()),
163            field_values: HashMap::from([
164                ("id".to_string(), "order_1".to_string()),
165                ("user_id".to_string(), "nonexistent_user".to_string()),
166            ]),
167            endpoint: "/orders".to_string(),
168            generated_at: SystemTime::now(),
169        };
170
171        validator.register_entity(order_entity).unwrap();
172
173        let result = validator.validate_all_entities();
174
175        // Should have validation errors due to missing foreign key
176        assert!(!result.errors.is_empty(), "Should have foreign key validation errors");
177        assert!(result.errors.iter().any(|e| matches!(
178            e.error_type,
179            crate::reflection::validation_framework::ValidationErrorType::ForeignKeyNotFound
180        )));
181    }
182
183    #[test]
184    fn test_rag_synthesizer_deterministic_behavior() {
185        let config = RagSynthesisConfig::default();
186        let synthesizer = RagDataSynthesizer::new(config);
187
188        // Test deterministic field hashing
189        let hash1 = synthesizer.hash_field_name("user_id");
190        let hash2 = synthesizer.hash_field_name("user_id");
191        assert_eq!(hash1, hash2, "Field name hashing should be deterministic");
192
193        let hash3 = synthesizer.hash_field_name("different_field");
194        assert_ne!(hash1, hash3, "Different field names should have different hashes");
195    }
196
197    #[cfg(feature = "data-faker")]
198    #[test]
199    fn test_faker_integration_with_deterministic_seeding() {
200        let config = SmartMockConfig {
201            use_faker: true,
202            seed: Some(777),
203            deterministic: true,
204            ..Default::default()
205        };
206
207        let generator = SmartMockGenerator::new(config);
208
209        // Verify faker is initialized
210        assert!(generator.is_faker_enabled(), "Faker should be initialized");
211
212        // Test that deterministic behavior works
213        assert!(generator.config().deterministic);
214        assert_eq!(generator.config().seed, Some(777));
215    }
216
217    #[test]
218    fn test_validation_custom_rules_comprehensive() {
219        let config = ValidationConfig {
220            enabled: true,
221            strict_mode: true,
222            max_validation_depth: 3,
223            custom_rules: vec![
224                CustomValidationRule {
225                    name: "age_range".to_string(),
226                    applies_to_entities: vec!["User".to_string()],
227                    validates_fields: vec!["age".to_string()],
228                    rule_type: ValidationRuleType::Range,
229                    parameters: HashMap::from([
230                        ("min".to_string(), "0".to_string()),
231                        ("max".to_string(), "120".to_string()),
232                    ]),
233                    error_message: "Age must be between 0 and 120".to_string(),
234                },
235                CustomValidationRule {
236                    name: "unique_email".to_string(),
237                    applies_to_entities: vec!["User".to_string()],
238                    validates_fields: vec!["email".to_string()],
239                    rule_type: ValidationRuleType::Unique,
240                    parameters: HashMap::new(),
241                    error_message: "Email must be unique".to_string(),
242                },
243            ],
244            cache_results: true,
245        };
246
247        let mut validator = ValidationFramework::new(config);
248
249        // Add entities with validation violations
250        let entities = vec![
251            GeneratedEntity {
252                entity_type: "User".to_string(),
253                primary_key: Some("user_1".to_string()),
254                field_values: HashMap::from([
255                    ("id".to_string(), "user_1".to_string()),
256                    ("age".to_string(), "150".to_string()), // Invalid age
257                    ("email".to_string(), "test@example.com".to_string()),
258                ]),
259                endpoint: "/users".to_string(),
260                generated_at: SystemTime::now(),
261            },
262            GeneratedEntity {
263                entity_type: "User".to_string(),
264                primary_key: Some("user_2".to_string()),
265                field_values: HashMap::from([
266                    ("id".to_string(), "user_2".to_string()),
267                    ("age".to_string(), "25".to_string()),
268                    ("email".to_string(), "test@example.com".to_string()), // Duplicate email
269                ]),
270                endpoint: "/users".to_string(),
271                generated_at: SystemTime::now(),
272            },
273        ];
274
275        for entity in entities {
276            validator.register_entity(entity).unwrap();
277        }
278
279        let result = validator.validate_all_entities();
280
281        // Should have multiple validation errors
282        assert!(!result.is_valid, "Validation should fail in strict mode");
283        assert!(result.errors.len() >= 2, "Should have age range and duplicate email errors");
284
285        // Verify specific error types
286        assert!(result.errors.iter().any(|e| matches!(
287            e.error_type,
288            crate::reflection::validation_framework::ValidationErrorType::OutOfRange
289        )));
290        assert!(result.errors.iter().any(|e| matches!(
291            e.error_type,
292            crate::reflection::validation_framework::ValidationErrorType::DuplicateValue
293        )));
294    }
295
296    #[test]
297    fn test_generator_reset_functionality() {
298        let config = SmartMockConfig {
299            seed: Some(555),
300            deterministic: true,
301            ..Default::default()
302        };
303
304        let mut generator = SmartMockGenerator::new(config);
305
306        // Generate some data
307        let uuid1 = generator.generate_uuid();
308        let seq1 = generator.next_sequence();
309        let str1 = generator.generate_random_string(8);
310
311        assert_eq!(seq1, 1);
312
313        // Generate more data
314        let seq2 = generator.next_sequence();
315        assert_eq!(seq2, 2);
316
317        // Reset generator
318        generator.reset();
319
320        // Should produce same initial results
321        let uuid2 = generator.generate_uuid();
322        let seq3 = generator.next_sequence();
323        let str2 = generator.generate_random_string(8);
324
325        assert_eq!(uuid1, uuid2, "UUID should be same after reset");
326        assert_eq!(seq3, 1, "Sequence should reset to 1");
327        assert_eq!(str1, str2, "Random string should be same after reset");
328    }
329
330    #[test]
331    fn test_comprehensive_validation_statistics() {
332        let config = ValidationConfig::default();
333        let mut validator = ValidationFramework::new(config);
334
335        // Add multiple entities of different types
336        for i in 1..=10 {
337            let user = GeneratedEntity {
338                entity_type: "User".to_string(),
339                primary_key: Some(format!("user_{}", i)),
340                field_values: HashMap::from([
341                    ("id".to_string(), format!("user_{}", i)),
342                    ("name".to_string(), format!("User {}", i)),
343                ]),
344                endpoint: "/users".to_string(),
345                generated_at: SystemTime::now(),
346            };
347            validator.register_entity(user).unwrap();
348        }
349
350        for i in 1..=5 {
351            let order = GeneratedEntity {
352                entity_type: "Order".to_string(),
353                primary_key: Some(format!("order_{}", i)),
354                field_values: HashMap::from([
355                    ("id".to_string(), format!("order_{}", i)),
356                    ("user_id".to_string(), format!("user_{}", i)),
357                ]),
358                endpoint: "/orders".to_string(),
359                generated_at: SystemTime::now(),
360            };
361            validator.register_entity(order).unwrap();
362        }
363
364        let stats = validator.get_statistics();
365        assert_eq!(stats.total_entities, 15);
366        assert_eq!(stats.entity_type_count, 2);
367        assert_eq!(stats.indexed_foreign_keys, 15); // 10 users + 5 orders
368
369        // Clear and verify
370        validator.clear();
371        let stats_after_clear = validator.get_statistics();
372        assert_eq!(stats_after_clear.total_entities, 0);
373        assert_eq!(stats_after_clear.entity_type_count, 0);
374        assert_eq!(stats_after_clear.indexed_foreign_keys, 0);
375    }
376
377    #[tokio::test]
378    async fn test_end_to_end_synthesis_workflow() {
379        // This test simulates a complete workflow from schema analysis to validation
380
381        // Step 1: Setup deterministic generator
382        let mut generator = SmartMockGenerator::new_with_seed(SmartMockConfig::default(), 99999);
383
384        // Step 2: Generate consistent test data
385        let users_data: Vec<_> = (1..=3)
386            .map(|i| {
387                HashMap::from([
388                    ("id".to_string(), format!("user_{}", i)),
389                    ("name".to_string(), format!("User {}", i)),
390                    ("email".to_string(), format!("user{}@example.com", i)),
391                ])
392            })
393            .collect();
394
395        let orders_data: Vec<_> = (1..=5)
396            .map(|i| {
397                HashMap::from([
398                    ("id".to_string(), format!("order_{}", i)),
399                    ("user_id".to_string(), format!("user_{}", (i % 3) + 1)),
400                    ("total".to_string(), format!("{}.99", 10 + i * 10)),
401                ])
402            })
403            .collect();
404
405        // Step 3: Create validation framework with comprehensive rules
406        let validation_config = ValidationConfig {
407            enabled: true,
408            strict_mode: false,
409            max_validation_depth: 5,
410            custom_rules: vec![CustomValidationRule {
411                name: "positive_total".to_string(),
412                applies_to_entities: vec!["Order".to_string()],
413                validates_fields: vec!["total".to_string()],
414                rule_type: ValidationRuleType::Range,
415                parameters: HashMap::from([
416                    ("min".to_string(), "0.01".to_string()),
417                    ("max".to_string(), "10000.00".to_string()),
418                ]),
419                error_message: "Order total must be positive".to_string(),
420            }],
421            cache_results: true,
422        };
423
424        let mut validator = ValidationFramework::new(validation_config);
425
426        // Step 4: Register all generated entities
427        for user_data in users_data.iter() {
428            let entity = GeneratedEntity {
429                entity_type: "User".to_string(),
430                primary_key: Some(user_data.get("id").unwrap().clone()),
431                field_values: user_data.clone(),
432                endpoint: "/users".to_string(),
433                generated_at: SystemTime::now(),
434            };
435            validator.register_entity(entity).unwrap();
436        }
437
438        for order_data in orders_data.iter() {
439            let entity = GeneratedEntity {
440                entity_type: "Order".to_string(),
441                primary_key: Some(order_data.get("id").unwrap().clone()),
442                field_values: order_data.clone(),
443                endpoint: "/orders".to_string(),
444                generated_at: SystemTime::now(),
445            };
446            validator.register_entity(entity).unwrap();
447        }
448
449        // Step 5: Run comprehensive validation
450        let result = validator.validate_all_entities();
451
452        // Step 6: Verify results
453        assert!(result.is_valid, "End-to-end workflow should produce valid data");
454
455        let stats = validator.get_statistics();
456        assert_eq!(stats.total_entities, 8); // 3 users + 5 orders
457        assert_eq!(stats.entity_type_count, 2);
458
459        // Step 7: Test deterministic regeneration
460        generator.reset();
461        let uuid_after_reset = generator.generate_uuid();
462        let string_after_reset = generator.generate_random_string(12);
463
464        // Reset again and verify same results
465        generator.reset();
466        let uuid_again = generator.generate_uuid();
467        let string_again = generator.generate_random_string(12);
468
469        assert_eq!(uuid_after_reset, uuid_again);
470        assert_eq!(string_after_reset, string_again);
471
472        println!("✓ End-to-end synthesis workflow completed successfully");
473        println!("  - Generated {} users and {} orders", users_data.len(), orders_data.len());
474        println!(
475            "  - Validation: {} errors, {} warnings",
476            result.errors.len(),
477            result.warnings.len()
478        );
479        println!("  - Deterministic generation verified");
480    }
481}