mockforge_grpc/dynamic/
service_generator.rs

1//! Dynamic gRPC service generation
2//!
3//! This module generates actual gRPC service implementations from parsed proto definitions.
4
5use crate::dynamic::proto_parser::{ProtoMethod, ProtoParser, ProtoService};
6use crate::reflection::smart_mock_generator::{SmartMockConfig, SmartMockGenerator};
7use mockforge_core::latency::LatencyInjector;
8use prost_reflect::DescriptorPool;
9use prost_types::Any;
10use std::collections::HashMap;
11use std::sync::{Arc, Mutex};
12use std::time::Duration;
13use tokio::sync::mpsc;
14use tokio_stream::wrappers::ReceiverStream;
15use tonic::{Request, Response, Status, Streaming};
16use tracing::{debug, info, warn};
17
18/// Service factory for creating enhanced gRPC services from proto files
19pub struct EnhancedServiceFactory;
20
21impl EnhancedServiceFactory {
22    /// Create services from a proto directory with enhanced capabilities
23    pub async fn create_services_from_proto_dir(
24        proto_dir: &str,
25        latency_injector: Option<LatencyInjector>,
26        smart_config: SmartMockConfig,
27    ) -> Result<Vec<DynamicGrpcService>, Box<dyn std::error::Error + Send + Sync>> {
28        info!("Creating enhanced services from proto directory: {}", proto_dir);
29
30        // Parse proto files with full protoc support
31        let mut parser = ProtoParser::new();
32        parser.parse_directory(proto_dir).await?;
33
34        let mut services = Vec::new();
35
36        // Store services info before consuming parser
37        let services_info: Vec<(String, ProtoService)> = parser
38            .services()
39            .iter()
40            .map(|(name, service)| (name.clone(), service.clone()))
41            .collect();
42
43        // Create enhanced services for each parsed service
44        for (service_name, proto_service) in services_info {
45            debug!("Creating enhanced service: {}", service_name);
46
47            // Create a new parser instance for each service (we'll improve this later)
48            let mut service_parser = ProtoParser::new();
49            let _ = service_parser.parse_directory(proto_dir).await; // Re-parse for now
50
51            let service = DynamicGrpcService::new_enhanced(
52                proto_service,
53                latency_injector.clone(),
54                Some(service_parser),
55                smart_config.clone(),
56            );
57
58            services.push(service);
59        }
60
61        info!("Created {} enhanced services", services.len());
62        Ok(services)
63    }
64
65    /// Create a single service from proto service definition
66    pub fn create_service_from_proto(
67        proto_service: ProtoService,
68        latency_injector: Option<LatencyInjector>,
69        proto_parser: Option<ProtoParser>,
70        smart_config: SmartMockConfig,
71    ) -> DynamicGrpcService {
72        if proto_parser.is_some() {
73            info!("Creating enhanced service: {}", proto_service.name);
74            DynamicGrpcService::new_enhanced(
75                proto_service,
76                latency_injector,
77                proto_parser,
78                smart_config,
79            )
80        } else {
81            info!("Creating basic service: {}", proto_service.name);
82            DynamicGrpcService::new(proto_service, latency_injector)
83        }
84    }
85}
86
87/// A dynamically generated gRPC service
88pub struct DynamicGrpcService {
89    /// The service definition
90    service: ProtoService,
91    /// Latency injector for simulating delays
92    latency_injector: Option<LatencyInjector>,
93    /// Mock responses for each method
94    mock_responses: HashMap<String, MockResponse>,
95    /// Proto parser with descriptor pool for advanced type support
96    proto_parser: Option<ProtoParser>,
97    /// Smart mock generator for intelligent data generation
98    smart_generator: Arc<Mutex<SmartMockGenerator>>,
99}
100
101/// Configuration for mock responses
102#[derive(Debug, Clone)]
103pub struct MockResponse {
104    /// The response message as JSON
105    pub response_json: String,
106    /// Whether to simulate an error
107    pub simulate_error: bool,
108    /// Error message if simulating an error
109    pub error_message: Option<String>,
110    /// Error code if simulating an error
111    pub error_code: Option<i32>,
112}
113
114impl DynamicGrpcService {
115    /// Create a new dynamic gRPC service
116    pub fn new(service: ProtoService, latency_injector: Option<LatencyInjector>) -> Self {
117        let mut mock_responses = HashMap::new();
118
119        // Generate default mock responses for each method
120        for method in &service.methods {
121            let response = Self::generate_mock_response(&method.name, &method.output_type);
122            mock_responses.insert(method.name.clone(), response);
123        }
124
125        Self {
126            service,
127            latency_injector,
128            mock_responses,
129            proto_parser: None,
130            smart_generator: Arc::new(Mutex::new(SmartMockGenerator::new(
131                SmartMockConfig::default(),
132            ))),
133        }
134    }
135
136    /// Create a new enhanced dynamic gRPC service with proto parser and smart generator
137    pub fn new_enhanced(
138        service: ProtoService,
139        latency_injector: Option<LatencyInjector>,
140        proto_parser: Option<ProtoParser>,
141        smart_config: SmartMockConfig,
142    ) -> Self {
143        let mut mock_responses = HashMap::new();
144        let smart_generator = Arc::new(Mutex::new(SmartMockGenerator::new(smart_config)));
145
146        // Generate enhanced mock responses for each method using smart generator
147        for method in &service.methods {
148            let response = if proto_parser.is_some() {
149                Self::generate_enhanced_mock_response(
150                    &method.name,
151                    &method.output_type,
152                    &service.name,
153                    &smart_generator,
154                )
155            } else {
156                Self::generate_mock_response(&method.name, &method.output_type)
157            };
158            mock_responses.insert(method.name.clone(), response);
159        }
160
161        Self {
162            service,
163            latency_injector,
164            mock_responses,
165            proto_parser,
166            smart_generator,
167        }
168    }
169
170    /// Generate a mock response for a method
171    fn generate_mock_response(method_name: &str, output_type: &str) -> MockResponse {
172        // Generate different responses based on method name
173        let response_json = match method_name {
174            "SayHello" | "SayHelloStream" | "SayHelloClientStream" | "Chat" => {
175                r#"{"message": "Hello from MockForge!"}"#.to_string()
176            }
177            _ => {
178                // Generic response for unknown methods
179                format!(
180                    r#"{{"result": "Mock response for {}", "type": "{}"}}"#,
181                    method_name, output_type
182                )
183            }
184        };
185
186        MockResponse {
187            response_json,
188            simulate_error: false,
189            error_message: None,
190            error_code: None,
191        }
192    }
193
194    /// Generate an enhanced mock response using smart generator
195    fn generate_enhanced_mock_response(
196        method_name: &str,
197        output_type: &str,
198        service_name: &str,
199        smart_generator: &Arc<Mutex<SmartMockGenerator>>,
200    ) -> MockResponse {
201        debug!("Generating enhanced mock response for {}.{}", service_name, method_name);
202
203        // Use smart generator for more realistic responses
204        let response_json = if let Ok(mut generator) = smart_generator.lock() {
205            // Create sample fields based on common gRPC response patterns
206            let mut fields = HashMap::new();
207
208            // Add common response fields based on method name
209            match method_name.to_lowercase().as_str() {
210                name if name.contains("hello") || name.contains("greet") => {
211                    fields.insert("message".to_string(), "greeting".to_string());
212                    fields.insert("name".to_string(), "user_name".to_string());
213                    fields.insert("timestamp".to_string(), "timestamp".to_string());
214                }
215                name if name.contains("list") || name.contains("get") => {
216                    fields.insert("id".to_string(), "identifier".to_string());
217                    fields.insert("data".to_string(), "response_data".to_string());
218                    fields.insert("count".to_string(), "total_count".to_string());
219                }
220                name if name.contains("create") || name.contains("add") => {
221                    fields.insert("id".to_string(), "new_id".to_string());
222                    fields.insert("status".to_string(), "status".to_string());
223                    fields.insert("message".to_string(), "success_message".to_string());
224                }
225                name if name.contains("update") || name.contains("modify") => {
226                    fields.insert("updated".to_string(), "updated_fields".to_string());
227                    fields.insert("version".to_string(), "version_number".to_string());
228                    fields.insert("status".to_string(), "status".to_string());
229                }
230                name if name.contains("delete") || name.contains("remove") => {
231                    fields.insert("deleted".to_string(), "deleted_status".to_string());
232                    fields.insert("message".to_string(), "confirmation_message".to_string());
233                }
234                _ => {
235                    // Generic response structure
236                    fields.insert("result".to_string(), "result_data".to_string());
237                    fields.insert("status".to_string(), "status".to_string());
238                    fields.insert("message".to_string(), "response_message".to_string());
239                }
240            }
241
242            // Generate JSON response using field patterns
243            let mut json_parts = Vec::new();
244            for (field_name, field_type) in fields {
245                let mock_value = match field_type.as_str() {
246                    "greeting" => {
247                        format!("\"Hello from enhanced MockForge service {}!\"", service_name)
248                    }
249                    "user_name" => "\"MockForge User\"".to_string(),
250                    "timestamp" => format!(
251                        "\"{}\"",
252                        std::time::SystemTime::now()
253                            .duration_since(std::time::UNIX_EPOCH)
254                            .unwrap_or_default()
255                            .as_secs()
256                    ),
257                    "identifier" | "new_id" => format!("{}", generator.next_sequence()),
258                    "total_count" => "42".to_string(),
259                    "status" => "\"success\"".to_string(),
260                    "success_message" => {
261                        format!("\"Successfully processed {} request\"", method_name)
262                    }
263                    "confirmation_message" => {
264                        format!("\"Operation {} completed successfully\"", method_name)
265                    }
266                    "version_number" => "\"1.0.0\"".to_string(),
267                    "updated_status" | "deleted_status" => "true".to_string(),
268                    _ => format!("\"Enhanced mock data for {}\"", field_type),
269                };
270                json_parts.push(format!("\"{}\": {}", field_name, mock_value));
271            }
272
273            format!("{{{}}}", json_parts.join(", "))
274        } else {
275            // Fallback to basic response if generator lock fails
276            format!(
277                r#"{{"result": "Enhanced mock response for {}", "type": "{}"}}"#,
278                method_name, output_type
279            )
280        };
281
282        MockResponse {
283            response_json,
284            simulate_error: false,
285            error_message: None,
286            error_code: None,
287        }
288    }
289
290    /// Get the descriptor pool if available
291    pub fn descriptor_pool(&self) -> Option<&DescriptorPool> {
292        self.proto_parser.as_ref().map(|parser| parser.pool())
293    }
294
295    /// Get the smart generator for external use
296    pub fn smart_generator(&self) -> &Arc<Mutex<SmartMockGenerator>> {
297        &self.smart_generator
298    }
299
300    /// Get the service definition
301    pub fn service(&self) -> &ProtoService {
302        &self.service
303    }
304
305    /// Handle a unary request
306    pub async fn handle_unary(
307        &self,
308        method_name: &str,
309        _request: Request<Any>,
310    ) -> Result<Response<Any>, Status> {
311        debug!("Handling unary request for method: {}", method_name);
312
313        // Inject latency if configured
314        if let Some(ref injector) = self.latency_injector {
315            let _ = injector.inject_latency(&[]).await;
316        }
317
318        // Get mock response for this method
319        let mock_response = self
320            .mock_responses
321            .get(method_name)
322            .ok_or_else(|| Status::not_found(format!("Method {} not found", method_name)))?;
323
324        // Check if we should simulate an error
325        if mock_response.simulate_error {
326            let error_code = mock_response.error_code.unwrap_or(2); // UNKNOWN
327            let error_message = mock_response
328                .error_message
329                .as_deref()
330                .unwrap_or("Simulated error from MockForge");
331            return Err(Status::new(tonic::Code::from_i32(error_code), error_message));
332        }
333
334        // Create response
335        let response = Any {
336            type_url: format!("type.googleapis.com/{}", self.get_output_type(method_name)),
337            value: mock_response.response_json.as_bytes().to_vec(),
338        };
339
340        Ok(Response::new(response))
341    }
342
343    /// Handle a server streaming request
344    pub async fn handle_server_streaming(
345        &self,
346        method_name: &str,
347        request: Request<Any>,
348    ) -> Result<Response<ReceiverStream<Result<Any, Status>>>, Status> {
349        debug!("Handling server streaming request for method: {}", method_name);
350
351        // Inject latency if configured
352        if let Some(ref injector) = self.latency_injector {
353            let _ = injector.inject_latency(&[]).await;
354        }
355
356        // Get mock response for this method
357        let mock_response = self
358            .mock_responses
359            .get(method_name)
360            .ok_or_else(|| Status::not_found(format!("Method {} not found", method_name)))?;
361
362        // Check if we should simulate an error
363        if mock_response.simulate_error {
364            let error_code = mock_response.error_code.unwrap_or(2); // UNKNOWN
365            let error_message = mock_response
366                .error_message
367                .as_deref()
368                .unwrap_or("Simulated error from MockForge");
369            return Err(Status::new(tonic::Code::from_i32(error_code), error_message));
370        }
371
372        // Create a streaming response
373        let stream = self
374            .create_server_stream(method_name, &request.into_inner(), mock_response)
375            .await?;
376        Ok(Response::new(stream))
377    }
378
379    /// Create a server streaming response
380    async fn create_server_stream(
381        &self,
382        method_name: &str,
383        _request: &Any,
384        mock_response: &MockResponse,
385    ) -> Result<ReceiverStream<Result<Any, Status>>, Status> {
386        debug!("Creating server stream for method: {}", method_name);
387
388        let (tx, rx) = mpsc::channel(10);
389        let method_name = method_name.to_string();
390        let output_type = self.get_output_type(&method_name);
391        let response_json = mock_response.response_json.clone();
392
393        // Spawn a task to generate stream messages
394        tokio::spawn(async move {
395            // Generate multiple stream messages (3-5 messages per stream)
396            let message_count = 3 + (method_name.len() % 3); // 3-5 messages based on method name
397
398            for i in 0..message_count {
399                // Create a mock response message
400                let stream_response = Self::create_stream_response_message(
401                    &method_name,
402                    &output_type,
403                    &response_json,
404                    i,
405                    message_count,
406                );
407
408                if tx.send(Ok(stream_response)).await.is_err() {
409                    debug!("Stream receiver dropped for method: {}", method_name);
410                    break; // Receiver dropped
411                }
412
413                // Add delay between messages to simulate realistic streaming
414                let delay = Duration::from_millis(100 + (i as u64 * 50)); // Progressive delay
415                tokio::time::sleep(delay).await;
416            }
417
418            info!(
419                "Completed server streaming for method: {} with {} messages",
420                method_name, message_count
421            );
422        });
423
424        Ok(ReceiverStream::new(rx))
425    }
426
427    /// Create a single stream response message
428    fn create_stream_response_message(
429        method_name: &str,
430        output_type: &str,
431        base_response: &str,
432        index: usize,
433        total: usize,
434    ) -> Any {
435        // Create a streaming-specific response by modifying the base response
436        let stream_response = if base_response.starts_with('{') && base_response.ends_with('}') {
437            // It's JSON, add streaming fields
438            let mut response = base_response.trim_end_matches('}').to_string();
439            response.push_str(&format!(
440                r#", "stream_index": {}, "stream_total": {}, "is_final": {}, "timestamp": "{}""#,
441                index,
442                total,
443                index == total - 1,
444                std::time::SystemTime::now()
445                    .duration_since(std::time::UNIX_EPOCH)
446                    .unwrap_or_default()
447                    .as_secs()
448            ));
449            response.push('}');
450            response
451        } else {
452            // It's a simple string, create a structured response
453            format!(
454                r#"{{"message": "{}", "stream_index": {}, "stream_total": {}, "is_final": {}, "method": "{}"}}"#,
455                base_response.replace('"', r#"\""#), // Escape quotes
456                index,
457                total,
458                index == total - 1,
459                method_name
460            )
461        };
462
463        Any {
464            type_url: format!("type.googleapis.com/{}", output_type),
465            value: stream_response.as_bytes().to_vec(),
466        }
467    }
468
469    /// Handle a client streaming request
470    pub async fn handle_client_streaming(
471        &self,
472        method_name: &str,
473        mut request: Request<Streaming<Any>>,
474    ) -> Result<Response<Any>, Status> {
475        debug!("Handling client streaming request for method: {}", method_name);
476
477        // Inject latency if configured
478        if let Some(ref injector) = self.latency_injector {
479            let _ = injector.inject_latency(&[]).await;
480        }
481
482        // Collect all client messages
483        let mut messages = Vec::new();
484        while let Ok(Some(message)) = request.get_mut().message().await {
485            messages.push(message);
486        }
487
488        debug!("Received {} client messages", messages.len());
489
490        // Get mock response for this method
491        let mock_response = self
492            .mock_responses
493            .get(method_name)
494            .ok_or_else(|| Status::not_found(format!("Method {} not found", method_name)))?;
495
496        // Check if we should simulate an error
497        if mock_response.simulate_error {
498            let error_code = mock_response.error_code.unwrap_or(2); // UNKNOWN
499            let error_message = mock_response
500                .error_message
501                .as_deref()
502                .unwrap_or("Simulated error from MockForge");
503            return Err(Status::new(tonic::Code::from_i32(error_code), error_message));
504        }
505
506        // Create response based on collected messages
507        let response = Any {
508            type_url: format!("type.googleapis.com/{}", self.get_output_type(method_name)),
509            value: format!(
510                r#"{{"message": "Processed {} messages from MockForge!"}}"#,
511                messages.len()
512            )
513            .as_bytes()
514            .to_vec(),
515        };
516
517        Ok(Response::new(response))
518    }
519
520    /// Handle a bidirectional streaming request
521    pub async fn handle_bidirectional_streaming(
522        &self,
523        method_name: &str,
524        request: Request<Streaming<Any>>,
525    ) -> Result<Response<ReceiverStream<Result<Any, Status>>>, Status> {
526        debug!("Handling bidirectional streaming request for method: {}", method_name);
527
528        // Inject latency if configured
529        if let Some(ref injector) = self.latency_injector {
530            let _ = injector.inject_latency(&[]).await;
531        }
532
533        // Get mock response for this method
534        let mock_response = self
535            .mock_responses
536            .get(method_name)
537            .ok_or_else(|| Status::not_found(format!("Method {} not found", method_name)))?;
538
539        // Check if we should simulate an error
540        if mock_response.simulate_error {
541            let error_code = mock_response.error_code.unwrap_or(2); // UNKNOWN
542            let error_message = mock_response
543                .error_message
544                .as_deref()
545                .unwrap_or("Simulated error from MockForge");
546            return Err(Status::new(tonic::Code::from_i32(error_code), error_message));
547        }
548
549        // Create a bidirectional streaming response
550        let stream = self.create_bidirectional_stream(method_name, request, mock_response).await?;
551        Ok(Response::new(stream))
552    }
553
554    /// Create a bidirectional streaming response
555    async fn create_bidirectional_stream(
556        &self,
557        method_name: &str,
558        mut request: Request<Streaming<Any>>,
559        mock_response: &MockResponse,
560    ) -> Result<ReceiverStream<Result<Any, Status>>, Status> {
561        debug!("Creating bidirectional stream for method: {}", method_name);
562
563        let (tx, rx) = mpsc::channel(10);
564        let method_name = method_name.to_string();
565        let output_type = self.get_output_type(&method_name);
566        let response_json = mock_response.response_json.clone();
567
568        // Spawn a task to handle bidirectional streaming
569        tokio::spawn(async move {
570            let mut input_count = 0;
571            let mut output_count = 0;
572
573            // Read from input stream and respond to each message
574            while let Ok(Some(input_message)) = request.get_mut().message().await {
575                input_count += 1;
576                debug!(
577                    "Received bidirectional input message {} for method: {}",
578                    input_count, method_name
579                );
580
581                // For each input message, generate 1-2 response messages
582                let responses_per_input = if input_count % 3 == 0 { 2 } else { 1 };
583
584                for response_idx in 0..responses_per_input {
585                    output_count += 1;
586
587                    // Create a bidirectional response message
588                    let response_message = Self::create_bidirectional_response_message(
589                        &method_name,
590                        &output_type,
591                        &response_json,
592                        &input_message,
593                        input_count,
594                        output_count,
595                        response_idx,
596                    );
597
598                    if tx.send(Ok(response_message)).await.is_err() {
599                        debug!("Bidirectional stream receiver dropped for method: {}", method_name);
600                        return;
601                    }
602
603                    // Add small delay between responses
604                    tokio::time::sleep(Duration::from_millis(50)).await;
605                }
606
607                // Limit the number of messages we process to prevent infinite loops
608                if input_count >= 100 {
609                    warn!(
610                        "Reached maximum input message limit (100) for bidirectional method: {}",
611                        method_name
612                    );
613                    break;
614                }
615            }
616
617            info!("Bidirectional streaming completed for method: {}: processed {} inputs, sent {} outputs",
618                  method_name, input_count, output_count);
619        });
620
621        Ok(ReceiverStream::new(rx))
622    }
623
624    /// Create a single bidirectional response message
625    fn create_bidirectional_response_message(
626        method_name: &str,
627        output_type: &str,
628        base_response: &str,
629        input_message: &Any,
630        input_sequence: usize,
631        output_sequence: usize,
632        response_index: usize,
633    ) -> Any {
634        // Try to extract some context from the input message
635        let input_context = if let Ok(input_str) = String::from_utf8(input_message.value.clone()) {
636            if input_str.len() < 200 {
637                // Reasonable length limit
638                input_str
639            } else {
640                format!("Large input ({} bytes)", input_message.value.len())
641            }
642        } else {
643            format!("Binary input ({} bytes)", input_message.value.len())
644        };
645
646        // Create a bidirectional response
647        let response_json = if base_response.starts_with('{') && base_response.ends_with('}') {
648            // It's JSON, add bidirectional fields
649            let mut response = base_response.trim_end_matches('}').to_string();
650            response.push_str(&format!(
651                r#", "input_sequence": {}, "output_sequence": {}, "response_index": {}, "input_context": "{}", "is_final": {}, "timestamp": "{}""#,
652                input_sequence,
653                output_sequence,
654                response_index,
655                input_context.replace('"', r#"\""#), // Escape quotes
656                response_index > 0, // Mark as final if this is the second response
657                std::time::SystemTime::now()
658                    .duration_since(std::time::UNIX_EPOCH)
659                    .unwrap_or_default()
660                    .as_secs()
661            ));
662            response.push('}');
663            response
664        } else {
665            // It's a simple string, create a structured response
666            format!(
667                r#"{{"message": "{}", "input_sequence": {}, "output_sequence": {}, "response_index": {}, "input_context": "{}", "method": "{}"}}"#,
668                base_response.replace('"', r#"\""#), // Escape quotes
669                input_sequence,
670                output_sequence,
671                response_index,
672                input_context.replace('"', r#"\""#), // Escape quotes
673                method_name
674            )
675        };
676
677        Any {
678            type_url: format!("type.googleapis.com/{}", output_type),
679            value: response_json.as_bytes().to_vec(),
680        }
681    }
682
683    /// Get the output type for a method
684    fn get_output_type(&self, method_name: &str) -> String {
685        self.service
686            .methods
687            .iter()
688            .find(|m| m.name == method_name)
689            .map(|m| m.output_type.clone())
690            .unwrap_or_else(|| "google.protobuf.Any".to_string())
691    }
692
693    /// Get the service name
694    pub fn service_name(&self) -> &str {
695        &self.service.name
696    }
697
698    /// Set a custom mock response for a method
699    pub fn set_mock_response(&mut self, method_name: &str, response: MockResponse) {
700        self.mock_responses.insert(method_name.to_string(), response);
701    }
702
703    /// Set error simulation for a method
704    pub fn set_error_simulation(
705        &mut self,
706        method_name: &str,
707        error_message: &str,
708        error_code: i32,
709    ) {
710        if let Some(mock_response) = self.mock_responses.get_mut(method_name) {
711            mock_response.simulate_error = true;
712            mock_response.error_message = Some(error_message.to_string());
713            mock_response.error_code = Some(error_code);
714        }
715    }
716
717    /// Get the service methods
718    pub fn methods(&self) -> &Vec<ProtoMethod> {
719        &self.service.methods
720    }
721
722    /// Get the service package
723    pub fn package(&self) -> &str {
724        &self.service.package
725    }
726}
727
728#[cfg(test)]
729mod tests {
730    use super::*;
731
732    // Helper function to create a test ProtoService
733    fn create_test_proto_service() -> ProtoService {
734        ProtoService {
735            name: "test.package.TestService".to_string(),
736            package: "test.package".to_string(),
737            short_name: "TestService".to_string(),
738            methods: vec![
739                ProtoMethod {
740                    name: "SayHello".to_string(),
741                    input_type: "HelloRequest".to_string(),
742                    output_type: "HelloResponse".to_string(),
743                    client_streaming: false,
744                    server_streaming: false,
745                },
746                ProtoMethod {
747                    name: "GetUser".to_string(),
748                    input_type: "GetUserRequest".to_string(),
749                    output_type: "GetUserResponse".to_string(),
750                    client_streaming: false,
751                    server_streaming: false,
752                },
753                ProtoMethod {
754                    name: "CreateItem".to_string(),
755                    input_type: "CreateItemRequest".to_string(),
756                    output_type: "CreateItemResponse".to_string(),
757                    client_streaming: false,
758                    server_streaming: false,
759                },
760            ],
761        }
762    }
763
764    fn create_streaming_proto_service() -> ProtoService {
765        ProtoService {
766            name: "streaming.package.StreamingService".to_string(),
767            package: "streaming.package".to_string(),
768            short_name: "StreamingService".to_string(),
769            methods: vec![
770                ProtoMethod {
771                    name: "ServerStream".to_string(),
772                    input_type: "StreamRequest".to_string(),
773                    output_type: "StreamResponse".to_string(),
774                    client_streaming: false,
775                    server_streaming: true,
776                },
777                ProtoMethod {
778                    name: "ClientStream".to_string(),
779                    input_type: "StreamRequest".to_string(),
780                    output_type: "StreamResponse".to_string(),
781                    client_streaming: true,
782                    server_streaming: false,
783                },
784                ProtoMethod {
785                    name: "BiDiStream".to_string(),
786                    input_type: "StreamRequest".to_string(),
787                    output_type: "StreamResponse".to_string(),
788                    client_streaming: true,
789                    server_streaming: true,
790                },
791            ],
792        }
793    }
794
795    // ==================== MockResponse Tests ====================
796
797    #[test]
798    fn test_mock_response_creation() {
799        let response = MockResponse {
800            response_json: r#"{"message": "test"}"#.to_string(),
801            simulate_error: false,
802            error_message: None,
803            error_code: None,
804        };
805
806        assert_eq!(response.response_json, r#"{"message": "test"}"#);
807        assert!(!response.simulate_error);
808        assert!(response.error_message.is_none());
809        assert!(response.error_code.is_none());
810    }
811
812    #[test]
813    fn test_mock_response_with_error() {
814        let response = MockResponse {
815            response_json: "{}".to_string(),
816            simulate_error: true,
817            error_message: Some("Test error".to_string()),
818            error_code: Some(3),
819        };
820
821        assert!(response.simulate_error);
822        assert_eq!(response.error_message, Some("Test error".to_string()));
823        assert_eq!(response.error_code, Some(3));
824    }
825
826    #[test]
827    fn test_mock_response_clone() {
828        let response = MockResponse {
829            response_json: r#"{"key": "value"}"#.to_string(),
830            simulate_error: true,
831            error_message: Some("error".to_string()),
832            error_code: Some(5),
833        };
834
835        let cloned = response.clone();
836        assert_eq!(cloned.response_json, response.response_json);
837        assert_eq!(cloned.simulate_error, response.simulate_error);
838        assert_eq!(cloned.error_message, response.error_message);
839        assert_eq!(cloned.error_code, response.error_code);
840    }
841
842    // ==================== DynamicGrpcService Basic Tests ====================
843
844    #[test]
845    fn test_dynamic_grpc_service_new() {
846        let proto_service = create_test_proto_service();
847        let service = DynamicGrpcService::new(proto_service, None);
848
849        assert_eq!(service.service_name(), "test.package.TestService");
850        assert_eq!(service.package(), "test.package");
851        assert_eq!(service.methods().len(), 3);
852    }
853
854    #[test]
855    fn test_dynamic_grpc_service_with_latency_injector() {
856        use mockforge_core::latency::{FaultConfig, LatencyProfile};
857
858        let proto_service = create_test_proto_service();
859        let latency_injector =
860            LatencyInjector::new(LatencyProfile::default(), FaultConfig::default());
861        let service = DynamicGrpcService::new(proto_service, Some(latency_injector));
862
863        assert_eq!(service.service_name(), "test.package.TestService");
864        assert!(service.latency_injector.is_some());
865    }
866
867    #[test]
868    fn test_dynamic_grpc_service_service_accessor() {
869        let proto_service = create_test_proto_service();
870        let service = DynamicGrpcService::new(proto_service, None);
871
872        let accessed_service = service.service();
873        assert_eq!(accessed_service.name, "test.package.TestService");
874        assert_eq!(accessed_service.package, "test.package");
875        assert_eq!(accessed_service.short_name, "TestService");
876    }
877
878    #[test]
879    fn test_dynamic_grpc_service_methods_accessor() {
880        let proto_service = create_test_proto_service();
881        let service = DynamicGrpcService::new(proto_service, None);
882
883        let methods = service.methods();
884        assert_eq!(methods.len(), 3);
885        assert_eq!(methods[0].name, "SayHello");
886        assert_eq!(methods[1].name, "GetUser");
887        assert_eq!(methods[2].name, "CreateItem");
888    }
889
890    #[test]
891    fn test_dynamic_grpc_service_package_accessor() {
892        let proto_service = create_test_proto_service();
893        let service = DynamicGrpcService::new(proto_service, None);
894
895        assert_eq!(service.package(), "test.package");
896    }
897
898    // ==================== Mock Response Generation Tests ====================
899
900    #[test]
901    fn test_generate_mock_response_say_hello() {
902        let response = DynamicGrpcService::generate_mock_response("SayHello", "HelloResponse");
903
904        assert!(response.response_json.contains("Hello from MockForge"));
905        assert!(!response.simulate_error);
906    }
907
908    #[test]
909    fn test_generate_mock_response_say_hello_stream() {
910        let response =
911            DynamicGrpcService::generate_mock_response("SayHelloStream", "HelloResponse");
912
913        assert!(response.response_json.contains("Hello from MockForge"));
914    }
915
916    #[test]
917    fn test_generate_mock_response_client_stream() {
918        let response =
919            DynamicGrpcService::generate_mock_response("SayHelloClientStream", "HelloResponse");
920
921        assert!(response.response_json.contains("Hello from MockForge"));
922    }
923
924    #[test]
925    fn test_generate_mock_response_chat() {
926        let response = DynamicGrpcService::generate_mock_response("Chat", "ChatResponse");
927
928        assert!(response.response_json.contains("Hello from MockForge"));
929    }
930
931    #[test]
932    fn test_generate_mock_response_generic() {
933        let response = DynamicGrpcService::generate_mock_response("CustomMethod", "CustomResponse");
934
935        assert!(response.response_json.contains("Mock response for CustomMethod"));
936        assert!(response.response_json.contains("CustomResponse"));
937    }
938
939    // ==================== Enhanced Mock Response Tests ====================
940
941    #[test]
942    fn test_generate_enhanced_mock_response_hello() {
943        let smart_generator =
944            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
945
946        let response = DynamicGrpcService::generate_enhanced_mock_response(
947            "SayHello",
948            "HelloResponse",
949            "TestService",
950            &smart_generator,
951        );
952
953        assert!(response.response_json.contains("message"));
954        assert!(!response.simulate_error);
955    }
956
957    #[test]
958    fn test_generate_enhanced_mock_response_list() {
959        let smart_generator =
960            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
961
962        let response = DynamicGrpcService::generate_enhanced_mock_response(
963            "ListUsers",
964            "ListUsersResponse",
965            "UserService",
966            &smart_generator,
967        );
968
969        assert!(response.response_json.contains("id") || response.response_json.contains("data"));
970    }
971
972    #[test]
973    fn test_generate_enhanced_mock_response_create() {
974        let smart_generator =
975            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
976
977        let response = DynamicGrpcService::generate_enhanced_mock_response(
978            "CreateUser",
979            "CreateUserResponse",
980            "UserService",
981            &smart_generator,
982        );
983
984        assert!(
985            response.response_json.contains("status") || response.response_json.contains("message")
986        );
987    }
988
989    #[test]
990    fn test_generate_enhanced_mock_response_update() {
991        let smart_generator =
992            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
993
994        let response = DynamicGrpcService::generate_enhanced_mock_response(
995            "UpdateUser",
996            "UpdateUserResponse",
997            "UserService",
998            &smart_generator,
999        );
1000
1001        assert!(
1002            response.response_json.contains("status")
1003                || response.response_json.contains("version")
1004                || response.response_json.contains("updated")
1005        );
1006    }
1007
1008    #[test]
1009    fn test_generate_enhanced_mock_response_delete() {
1010        let smart_generator =
1011            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
1012
1013        let response = DynamicGrpcService::generate_enhanced_mock_response(
1014            "DeleteUser",
1015            "DeleteUserResponse",
1016            "UserService",
1017            &smart_generator,
1018        );
1019
1020        assert!(
1021            response.response_json.contains("deleted")
1022                || response.response_json.contains("message")
1023        );
1024    }
1025
1026    #[test]
1027    fn test_generate_enhanced_mock_response_generic() {
1028        let smart_generator =
1029            Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig::default())));
1030
1031        let response = DynamicGrpcService::generate_enhanced_mock_response(
1032            "ProcessData",
1033            "ProcessDataResponse",
1034            "DataService",
1035            &smart_generator,
1036        );
1037
1038        assert!(
1039            response.response_json.contains("result")
1040                || response.response_json.contains("status")
1041                || response.response_json.contains("message")
1042        );
1043    }
1044
1045    // ==================== Set Mock Response Tests ====================
1046
1047    #[test]
1048    fn test_set_mock_response() {
1049        let proto_service = create_test_proto_service();
1050        let mut service = DynamicGrpcService::new(proto_service, None);
1051
1052        let custom_response = MockResponse {
1053            response_json: r#"{"custom": "response"}"#.to_string(),
1054            simulate_error: false,
1055            error_message: None,
1056            error_code: None,
1057        };
1058
1059        service.set_mock_response("SayHello", custom_response.clone());
1060
1061        let stored = service.mock_responses.get("SayHello").unwrap();
1062        assert_eq!(stored.response_json, r#"{"custom": "response"}"#);
1063    }
1064
1065    #[test]
1066    fn test_set_mock_response_new_method() {
1067        let proto_service = create_test_proto_service();
1068        let mut service = DynamicGrpcService::new(proto_service, None);
1069
1070        let custom_response = MockResponse {
1071            response_json: r#"{"new": "method"}"#.to_string(),
1072            simulate_error: false,
1073            error_message: None,
1074            error_code: None,
1075        };
1076
1077        service.set_mock_response("NewMethod", custom_response);
1078
1079        assert!(service.mock_responses.contains_key("NewMethod"));
1080    }
1081
1082    // ==================== Error Simulation Tests ====================
1083
1084    #[test]
1085    fn test_set_error_simulation() {
1086        let proto_service = create_test_proto_service();
1087        let mut service = DynamicGrpcService::new(proto_service, None);
1088
1089        service.set_error_simulation("SayHello", "Test error message", 3);
1090
1091        let response = service.mock_responses.get("SayHello").unwrap();
1092        assert!(response.simulate_error);
1093        assert_eq!(response.error_message, Some("Test error message".to_string()));
1094        assert_eq!(response.error_code, Some(3));
1095    }
1096
1097    #[test]
1098    fn test_set_error_simulation_nonexistent_method() {
1099        let proto_service = create_test_proto_service();
1100        let mut service = DynamicGrpcService::new(proto_service, None);
1101
1102        // Should not panic, just do nothing
1103        service.set_error_simulation("NonExistent", "Error", 5);
1104
1105        assert!(!service.mock_responses.contains_key("NonExistent"));
1106    }
1107
1108    // ==================== Output Type Tests ====================
1109
1110    #[test]
1111    fn test_get_output_type_existing_method() {
1112        let proto_service = create_test_proto_service();
1113        let service = DynamicGrpcService::new(proto_service, None);
1114
1115        let output_type = service.get_output_type("SayHello");
1116        assert_eq!(output_type, "HelloResponse");
1117    }
1118
1119    #[test]
1120    fn test_get_output_type_nonexistent_method() {
1121        let proto_service = create_test_proto_service();
1122        let service = DynamicGrpcService::new(proto_service, None);
1123
1124        let output_type = service.get_output_type("NonExistent");
1125        assert_eq!(output_type, "google.protobuf.Any");
1126    }
1127
1128    // ==================== Stream Response Message Tests ====================
1129
1130    #[test]
1131    fn test_create_stream_response_message_json() {
1132        let base_response = r#"{"message": "test"}"#;
1133        let response = DynamicGrpcService::create_stream_response_message(
1134            "TestMethod",
1135            "TestOutput",
1136            base_response,
1137            0,
1138            3,
1139        );
1140
1141        assert!(response.type_url.contains("TestOutput"));
1142        let value_str = String::from_utf8(response.value.clone()).unwrap();
1143        assert!(value_str.contains("stream_index"));
1144        assert!(value_str.contains("stream_total"));
1145        assert!(value_str.contains("is_final"));
1146    }
1147
1148    #[test]
1149    fn test_create_stream_response_message_first() {
1150        let base_response = r#"{"data": "value"}"#;
1151        let response = DynamicGrpcService::create_stream_response_message(
1152            "TestMethod",
1153            "TestOutput",
1154            base_response,
1155            0,
1156            5,
1157        );
1158
1159        let value_str = String::from_utf8(response.value).unwrap();
1160        assert!(value_str.contains(r#""stream_index": 0"#));
1161        assert!(value_str.contains(r#""is_final": false"#));
1162    }
1163
1164    #[test]
1165    fn test_create_stream_response_message_last() {
1166        let base_response = r#"{"data": "value"}"#;
1167        let response = DynamicGrpcService::create_stream_response_message(
1168            "TestMethod",
1169            "TestOutput",
1170            base_response,
1171            4,
1172            5,
1173        );
1174
1175        let value_str = String::from_utf8(response.value).unwrap();
1176        assert!(value_str.contains(r#""stream_index": 4"#));
1177        assert!(value_str.contains(r#""is_final": true"#));
1178    }
1179
1180    #[test]
1181    fn test_create_stream_response_message_non_json() {
1182        let base_response = "simple string";
1183        let response = DynamicGrpcService::create_stream_response_message(
1184            "TestMethod",
1185            "TestOutput",
1186            base_response,
1187            1,
1188            3,
1189        );
1190
1191        let value_str = String::from_utf8(response.value).unwrap();
1192        assert!(value_str.contains("simple string"));
1193        assert!(value_str.contains("stream_index"));
1194        assert!(value_str.contains("method"));
1195    }
1196
1197    // ==================== Bidirectional Response Message Tests ====================
1198
1199    #[test]
1200    fn test_create_bidirectional_response_message_json() {
1201        let base_response = r#"{"message": "hello"}"#;
1202        let input_message = Any {
1203            type_url: "type.googleapis.com/test".to_string(),
1204            value: b"input data".to_vec(),
1205        };
1206
1207        let response = DynamicGrpcService::create_bidirectional_response_message(
1208            "TestMethod",
1209            "TestOutput",
1210            base_response,
1211            &input_message,
1212            1,
1213            1,
1214            0,
1215        );
1216
1217        let value_str = String::from_utf8(response.value).unwrap();
1218        assert!(value_str.contains("input_sequence"));
1219        assert!(value_str.contains("output_sequence"));
1220        assert!(value_str.contains("input_context"));
1221    }
1222
1223    #[test]
1224    fn test_create_bidirectional_response_message_with_binary_input() {
1225        let base_response = r#"{"data": "test"}"#;
1226        let input_message = Any {
1227            type_url: "type.googleapis.com/test".to_string(),
1228            value: vec![0xFF, 0xFE, 0x00, 0x01], // Invalid UTF-8
1229        };
1230
1231        let response = DynamicGrpcService::create_bidirectional_response_message(
1232            "TestMethod",
1233            "TestOutput",
1234            base_response,
1235            &input_message,
1236            2,
1237            3,
1238            1,
1239        );
1240
1241        let value_str = String::from_utf8(response.value).unwrap();
1242        assert!(value_str.contains("Binary input"));
1243    }
1244
1245    #[test]
1246    fn test_create_bidirectional_response_message_large_input() {
1247        let base_response = r#"{"data": "test"}"#;
1248        let large_input = "x".repeat(300); // Larger than 200 char limit
1249        let input_message = Any {
1250            type_url: "type.googleapis.com/test".to_string(),
1251            value: large_input.as_bytes().to_vec(),
1252        };
1253
1254        let response = DynamicGrpcService::create_bidirectional_response_message(
1255            "TestMethod",
1256            "TestOutput",
1257            base_response,
1258            &input_message,
1259            1,
1260            1,
1261            0,
1262        );
1263
1264        let value_str = String::from_utf8(response.value).unwrap();
1265        assert!(value_str.contains("Large input"));
1266    }
1267
1268    // ==================== Enhanced Service Tests ====================
1269
1270    #[test]
1271    fn test_dynamic_grpc_service_new_enhanced() {
1272        let proto_service = create_test_proto_service();
1273        let smart_config = SmartMockConfig::default();
1274
1275        let service = DynamicGrpcService::new_enhanced(proto_service, None, None, smart_config);
1276
1277        assert_eq!(service.service_name(), "test.package.TestService");
1278        assert!(service.proto_parser.is_none());
1279    }
1280
1281    #[test]
1282    fn test_smart_generator_accessor() {
1283        let proto_service = create_test_proto_service();
1284        let service = DynamicGrpcService::new(proto_service, None);
1285
1286        let generator = service.smart_generator();
1287        assert!(generator.lock().is_ok());
1288    }
1289
1290    #[test]
1291    fn test_descriptor_pool_none() {
1292        let proto_service = create_test_proto_service();
1293        let service = DynamicGrpcService::new(proto_service, None);
1294
1295        assert!(service.descriptor_pool().is_none());
1296    }
1297
1298    // ==================== EnhancedServiceFactory Tests ====================
1299
1300    #[test]
1301    fn test_create_service_from_proto_basic() {
1302        let proto_service = create_test_proto_service();
1303        let smart_config = SmartMockConfig::default();
1304
1305        let service = EnhancedServiceFactory::create_service_from_proto(
1306            proto_service,
1307            None,
1308            None,
1309            smart_config,
1310        );
1311
1312        assert_eq!(service.service_name(), "test.package.TestService");
1313        assert!(service.proto_parser.is_none());
1314    }
1315
1316    #[test]
1317    fn test_create_service_from_proto_with_latency() {
1318        use mockforge_core::latency::{FaultConfig, LatencyProfile};
1319
1320        let proto_service = create_test_proto_service();
1321        let latency_injector =
1322            LatencyInjector::new(LatencyProfile::default(), FaultConfig::default());
1323        let smart_config = SmartMockConfig::default();
1324
1325        let service = EnhancedServiceFactory::create_service_from_proto(
1326            proto_service,
1327            Some(latency_injector),
1328            None,
1329            smart_config,
1330        );
1331
1332        assert!(service.latency_injector.is_some());
1333    }
1334
1335    // ==================== Streaming Service Tests ====================
1336
1337    #[test]
1338    fn test_streaming_service_methods() {
1339        let proto_service = create_streaming_proto_service();
1340        let service = DynamicGrpcService::new(proto_service, None);
1341
1342        let methods = service.methods();
1343        assert_eq!(methods.len(), 3);
1344
1345        assert!(!methods[0].client_streaming && methods[0].server_streaming); // Server stream
1346        assert!(methods[1].client_streaming && !methods[1].server_streaming); // Client stream
1347        assert!(methods[2].client_streaming && methods[2].server_streaming); // BiDi
1348    }
1349
1350    #[test]
1351    fn test_mock_responses_generated_for_all_methods() {
1352        let proto_service = create_test_proto_service();
1353        let service = DynamicGrpcService::new(proto_service, None);
1354
1355        // All methods should have mock responses
1356        assert!(service.mock_responses.contains_key("SayHello"));
1357        assert!(service.mock_responses.contains_key("GetUser"));
1358        assert!(service.mock_responses.contains_key("CreateItem"));
1359    }
1360
1361    // ==================== Async Handler Tests ====================
1362
1363    #[tokio::test]
1364    async fn test_handle_unary_success() {
1365        let proto_service = create_test_proto_service();
1366        let service = DynamicGrpcService::new(proto_service, None);
1367
1368        let request = Request::new(Any {
1369            type_url: "type.googleapis.com/HelloRequest".to_string(),
1370            value: b"{}".to_vec(),
1371        });
1372
1373        let result = service.handle_unary("SayHello", request).await;
1374        assert!(result.is_ok());
1375
1376        let response = result.unwrap().into_inner();
1377        assert!(response.type_url.contains("HelloResponse"));
1378    }
1379
1380    #[tokio::test]
1381    async fn test_handle_unary_method_not_found() {
1382        let proto_service = create_test_proto_service();
1383        let service = DynamicGrpcService::new(proto_service, None);
1384
1385        let request = Request::new(Any {
1386            type_url: "type.googleapis.com/UnknownRequest".to_string(),
1387            value: b"{}".to_vec(),
1388        });
1389
1390        let result = service.handle_unary("UnknownMethod", request).await;
1391        assert!(result.is_err());
1392
1393        let status = result.unwrap_err();
1394        assert_eq!(status.code(), tonic::Code::NotFound);
1395    }
1396
1397    #[tokio::test]
1398    async fn test_handle_unary_with_error_simulation() {
1399        let proto_service = create_test_proto_service();
1400        let mut service = DynamicGrpcService::new(proto_service, None);
1401
1402        service.set_error_simulation("SayHello", "Simulated error", 3);
1403
1404        let request = Request::new(Any {
1405            type_url: "type.googleapis.com/HelloRequest".to_string(),
1406            value: b"{}".to_vec(),
1407        });
1408
1409        let result = service.handle_unary("SayHello", request).await;
1410        assert!(result.is_err());
1411
1412        let status = result.unwrap_err();
1413        assert_eq!(status.code(), tonic::Code::InvalidArgument); // Code 3
1414    }
1415
1416    #[tokio::test]
1417    async fn test_handle_server_streaming_success() {
1418        let proto_service = create_test_proto_service();
1419        let service = DynamicGrpcService::new(proto_service, None);
1420
1421        let request = Request::new(Any {
1422            type_url: "type.googleapis.com/HelloRequest".to_string(),
1423            value: b"{}".to_vec(),
1424        });
1425
1426        let result = service.handle_server_streaming("SayHello", request).await;
1427        assert!(result.is_ok());
1428    }
1429
1430    #[tokio::test]
1431    async fn test_handle_server_streaming_method_not_found() {
1432        let proto_service = create_test_proto_service();
1433        let service = DynamicGrpcService::new(proto_service, None);
1434
1435        let request = Request::new(Any {
1436            type_url: "type.googleapis.com/UnknownRequest".to_string(),
1437            value: b"{}".to_vec(),
1438        });
1439
1440        let result = service.handle_server_streaming("UnknownMethod", request).await;
1441        assert!(result.is_err());
1442    }
1443
1444    #[tokio::test]
1445    async fn test_handle_server_streaming_with_error_simulation() {
1446        let proto_service = create_test_proto_service();
1447        let mut service = DynamicGrpcService::new(proto_service, None);
1448
1449        service.set_error_simulation("SayHello", "Stream error", 13);
1450
1451        let request = Request::new(Any {
1452            type_url: "type.googleapis.com/HelloRequest".to_string(),
1453            value: b"{}".to_vec(),
1454        });
1455
1456        let result = service.handle_server_streaming("SayHello", request).await;
1457        assert!(result.is_err());
1458    }
1459}