1use 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
18pub struct EnhancedServiceFactory;
20
21impl EnhancedServiceFactory {
22 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 let mut parser = ProtoParser::new();
32 parser.parse_directory(proto_dir).await?;
33
34 let mut services = Vec::new();
35
36 let services_info: Vec<(String, ProtoService)> = parser
38 .services()
39 .iter()
40 .map(|(name, service)| (name.clone(), service.clone()))
41 .collect();
42
43 for (service_name, proto_service) in services_info {
45 debug!("Creating enhanced service: {}", service_name);
46
47 let mut service_parser = ProtoParser::new();
49 let _ = service_parser.parse_directory(proto_dir).await; 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 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
87pub struct DynamicGrpcService {
89 service: ProtoService,
91 latency_injector: Option<LatencyInjector>,
93 mock_responses: HashMap<String, MockResponse>,
95 proto_parser: Option<ProtoParser>,
97 smart_generator: Arc<Mutex<SmartMockGenerator>>,
99}
100
101#[derive(Debug, Clone)]
103pub struct MockResponse {
104 pub response_json: String,
106 pub simulate_error: bool,
108 pub error_message: Option<String>,
110 pub error_code: Option<i32>,
112}
113
114impl DynamicGrpcService {
115 pub fn new(service: ProtoService, latency_injector: Option<LatencyInjector>) -> Self {
117 let mut mock_responses = HashMap::new();
118
119 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 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 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 fn generate_mock_response(method_name: &str, output_type: &str) -> MockResponse {
172 let response_json = match method_name {
174 "SayHello" | "SayHelloStream" | "SayHelloClientStream" | "Chat" => {
175 r#"{"message": "Hello from MockForge!"}"#.to_string()
176 }
177 _ => {
178 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 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 let response_json = if let Ok(mut generator) = smart_generator.lock() {
205 let mut fields = HashMap::new();
207
208 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 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 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 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 pub fn descriptor_pool(&self) -> Option<&DescriptorPool> {
292 self.proto_parser.as_ref().map(|parser| parser.pool())
293 }
294
295 pub fn smart_generator(&self) -> &Arc<Mutex<SmartMockGenerator>> {
297 &self.smart_generator
298 }
299
300 pub fn service(&self) -> &ProtoService {
302 &self.service
303 }
304
305 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 if let Some(ref injector) = self.latency_injector {
315 let _ = injector.inject_latency(&[]).await;
316 }
317
318 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 if mock_response.simulate_error {
326 let error_code = mock_response.error_code.unwrap_or(2); 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 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 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 if let Some(ref injector) = self.latency_injector {
353 let _ = injector.inject_latency(&[]).await;
354 }
355
356 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 if mock_response.simulate_error {
364 let error_code = mock_response.error_code.unwrap_or(2); 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 let stream = self
374 .create_server_stream(method_name, &request.into_inner(), mock_response)
375 .await?;
376 Ok(Response::new(stream))
377 }
378
379 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 tokio::spawn(async move {
395 let message_count = 3 + (method_name.len() % 3); for i in 0..message_count {
399 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; }
412
413 let delay = Duration::from_millis(100 + (i as u64 * 50)); 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 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 let stream_response = if base_response.starts_with('{') && base_response.ends_with('}') {
437 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 format!(
454 r#"{{"message": "{}", "stream_index": {}, "stream_total": {}, "is_final": {}, "method": "{}"}}"#,
455 base_response.replace('"', r#"\""#), 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 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 if let Some(ref injector) = self.latency_injector {
479 let _ = injector.inject_latency(&[]).await;
480 }
481
482 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 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 if mock_response.simulate_error {
498 let error_code = mock_response.error_code.unwrap_or(2); 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 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 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 if let Some(ref injector) = self.latency_injector {
530 let _ = injector.inject_latency(&[]).await;
531 }
532
533 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 if mock_response.simulate_error {
541 let error_code = mock_response.error_code.unwrap_or(2); 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 let stream = self.create_bidirectional_stream(method_name, request, mock_response).await?;
551 Ok(Response::new(stream))
552 }
553
554 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 tokio::spawn(async move {
570 let mut input_count = 0;
571 let mut output_count = 0;
572
573 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 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 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 tokio::time::sleep(Duration::from_millis(50)).await;
605 }
606
607 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 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 let input_context = if let Ok(input_str) = String::from_utf8(input_message.value.clone()) {
636 if input_str.len() < 200 {
637 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 let response_json = if base_response.starts_with('{') && base_response.ends_with('}') {
648 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#"\""#), response_index > 0, 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 format!(
667 r#"{{"message": "{}", "input_sequence": {}, "output_sequence": {}, "response_index": {}, "input_context": "{}", "method": "{}"}}"#,
668 base_response.replace('"', r#"\""#), input_sequence,
670 output_sequence,
671 response_index,
672 input_context.replace('"', r#"\""#), 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 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 pub fn service_name(&self) -> &str {
695 &self.service.name
696 }
697
698 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 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 pub fn methods(&self) -> &Vec<ProtoMethod> {
719 &self.service.methods
720 }
721
722 pub fn package(&self) -> &str {
724 &self.service.package
725 }
726}
727
728#[cfg(test)]
729mod tests {
730 use super::*;
731
732 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 #[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 #[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 #[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 #[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 #[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 #[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 service.set_error_simulation("NonExistent", "Error", 5);
1104
1105 assert!(!service.mock_responses.contains_key("NonExistent"));
1106 }
1107
1108 #[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 #[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 #[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], };
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); 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 #[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 #[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 #[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); assert!(methods[1].client_streaming && !methods[1].server_streaming); assert!(methods[2].client_streaming && methods[2].server_streaming); }
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 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 #[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); }
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}