mockforge_grpc/lib.rs
1//! # MockForge gRPC
2//!
3//! Flexible gRPC mocking library with dynamic service discovery and HTTP bridge.
4//!
5//! This crate provides comprehensive gRPC mocking capabilities with:
6//!
7//! - **Dynamic Service Discovery**: Auto-discover and mock services from `.proto` files
8//! - **HTTP Bridge**: Expose gRPC services as REST APIs with OpenAPI documentation
9//! - **gRPC Reflection**: Built-in server reflection for service discovery
10//! - **Streaming Support**: Full support for unary, server, client, and bidirectional streaming
11//! - **Protocol Buffer Parsing**: Runtime parsing of `.proto` files without code generation
12//!
13//! ## Overview
14//!
15//! MockForge gRPC eliminates the need to hardcode service implementations. Simply provide
16//! `.proto` files, and MockForge will automatically:
17//!
18//! 1. Parse protobuf definitions
19//! 2. Generate mock service implementations
20//! 3. Handle all RPC methods (unary and streaming)
21//! 4. Optionally expose as REST APIs via HTTP Bridge
22//!
23//! ## Quick Start
24//!
25//! ### Basic gRPC Server
26//!
27//! ```rust,no_run
28//! use mockforge_grpc::start;
29//!
30//! #[tokio::main]
31//! async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
32//! // Start gRPC server on port 50051
33//! // Automatically discovers .proto files in ./proto directory
34//! start(50051).await?;
35//! Ok(())
36//! }
37//! ```
38//!
39//! ### With Custom Configuration
40//!
41//! ```rust,no_run
42//! use mockforge_grpc::{start_with_config, DynamicGrpcConfig};
43//! use mockforge_core::LatencyProfile;
44//!
45//! # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
46//! let config = DynamicGrpcConfig {
47//! proto_dir: "./my-protos".to_string(),
48//! enable_reflection: true,
49//! max_message_size: 8 * 1024 * 1024, // 8MB
50//! ..Default::default()
51//! };
52//!
53//! let latency = Some(LatencyProfile::normal());
54//! start_with_config(50051, latency, config).await?;
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! ### HTTP Bridge Mode
60//!
61//! Expose gRPC services as REST APIs:
62//!
63//! ```rust,no_run
64//! use mockforge_grpc::{DynamicGrpcConfig, start_with_config};
65//!
66//! # async fn example() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
67//! let config = DynamicGrpcConfig {
68//! proto_dir: "./proto".to_string(),
69//! enable_http_bridge: true,
70//! http_bridge_port: 8080,
71//! generate_openapi: true,
72//! ..Default::default()
73//! };
74//!
75//! start_with_config(50051, None, config).await?;
76//! // Now accessible via:
77//! // - gRPC: localhost:50051
78//! // - REST: http://localhost:8080/api/{service}/{method}
79//! // - OpenAPI: http://localhost:8080/api/docs
80//! # Ok(())
81//! # }
82//! ```
83//!
84//! ## Dynamic Service Discovery
85//!
86//! MockForge automatically discovers and mocks all services defined in your `.proto` files:
87//!
88//! ```protobuf
89//! // user.proto
90//! service UserService {
91//! rpc GetUser(GetUserRequest) returns (GetUserResponse);
92//! rpc ListUsers(ListUsersRequest) returns (stream User);
93//! rpc CreateUser(stream CreateUserRequest) returns (CreateUserResponse);
94//! rpc Chat(stream ChatMessage) returns (stream ChatMessage);
95//! }
96//! ```
97//!
98//! All four method types (unary, server streaming, client streaming, bidirectional) are
99//! automatically supported without any code generation or manual implementation.
100//!
101//! ## gRPC Reflection
102//!
103//! Enable reflection for service discovery by gRPC clients:
104//!
105//! ```bash
106//! # List services
107//! grpcurl -plaintext localhost:50051 list
108//!
109//! # Describe a service
110//! grpcurl -plaintext localhost:50051 describe UserService
111//!
112//! # Call a method
113//! grpcurl -plaintext -d '{"user_id": "123"}' localhost:50051 UserService/GetUser
114//! ```
115//!
116//! ## HTTP Bridge
117//!
118//! The HTTP Bridge automatically converts gRPC services to REST endpoints:
119//!
120//! ```bash
121//! # gRPC call
122//! grpcurl -d '{"user_id": "123"}' localhost:50051 UserService/GetUser
123//!
124//! # Equivalent HTTP call
125//! curl -X POST http://localhost:8080/api/userservice/getuser \
126//! -H "Content-Type: application/json" \
127//! -d '{"user_id": "123"}'
128//!
129//! # OpenAPI documentation
130//! curl http://localhost:8080/api/docs
131//! ```
132//!
133//! ## Advanced Data Synthesis
134//!
135//! Generate realistic mock data using intelligent field inference:
136//!
137//! - Detects field types from names (`email`, `phone`, `id`, etc.)
138//! - Maintains referential integrity across related messages
139//! - Supports deterministic seeding for reproducible tests
140//!
141//! ## Key Modules
142//!
143//! - [`dynamic`]: Dynamic service discovery and mocking
144//! - [`reflection`]: gRPC reflection protocol implementation
145//! - [`registry`]: Service and method registry
146//!
147//! ## Examples
148//!
149//! See the [examples directory](https://github.com/SaaSy-Solutions/mockforge/tree/main/examples)
150//! for complete working examples.
151//!
152//! ## Related Crates
153//!
154//! - [`mockforge-core`](https://docs.rs/mockforge-core): Core mocking functionality
155//! - [`mockforge-data`](https://docs.rs/mockforge-data): Synthetic data generation
156//!
157//! ## Documentation
158//!
159//! - [MockForge Book](https://docs.mockforge.dev/)
160//! - [gRPC Mocking Guide](https://docs.mockforge.dev/user-guide/grpc-mocking.html)
161//! - [API Reference](https://docs.rs/mockforge-grpc)
162
163use mockforge_core::LatencyProfile;
164
165pub mod dynamic;
166pub mod reflection;
167pub mod registry;
168
169// Include generated proto code
170pub mod generated {
171 // Include all generated proto files
172 tonic::include_proto!("mockforge.greeter");
173}
174
175pub use dynamic::proto_parser::ProtoService;
176pub use dynamic::service_generator::MockResponse;
177pub use dynamic::{DynamicGrpcConfig, ServiceRegistry};
178pub use reflection::{MockReflectionProxy, ProxyConfig, ReflectionProxy};
179pub use registry::GrpcProtoRegistry;
180
181/// Start gRPC server with default configuration
182pub async fn start(port: u16) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
183 start_with_latency(port, None).await
184}
185
186/// Start gRPC server with latency configuration
187pub async fn start_with_latency(
188 port: u16,
189 latency_profile: Option<LatencyProfile>,
190) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
191 let config = DynamicGrpcConfig::default();
192 start_with_config(port, latency_profile, config).await
193}
194
195/// Start gRPC server with custom configuration
196pub async fn start_with_config(
197 port: u16,
198 latency_profile: Option<LatencyProfile>,
199 config: DynamicGrpcConfig,
200) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
201 dynamic::start_dynamic_server(port, config, latency_profile).await
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_dynamic_grpc_config_default() {
210 let _config = DynamicGrpcConfig::default();
211 // Config should be created successfully
212 }
213
214 #[test]
215 fn test_latency_profile_creation() {
216 let profile = LatencyProfile::default();
217 assert_eq!(profile.base_ms, 50);
218 assert_eq!(profile.jitter_ms, 20);
219 assert_eq!(profile.min_ms, 0);
220 }
221
222 #[test]
223 fn test_latency_profile_custom() {
224 let profile = LatencyProfile::new(100, 25);
225
226 assert_eq!(profile.base_ms, 100);
227 assert_eq!(profile.jitter_ms, 25);
228 assert_eq!(profile.min_ms, 0);
229 }
230}