mockforge_core/lib.rs
1//! # MockForge Core
2//!
3//! Core functionality and shared logic for the MockForge mocking framework.
4//!
5//! This crate provides the foundational building blocks used across all MockForge protocols
6//! (HTTP, WebSocket, gRPC, GraphQL). It can be used as a library to programmatically create
7//! and manage mock servers, or to build custom mocking solutions.
8//!
9//! ## Overview
10//!
11//! MockForge Core includes:
12//!
13//! - **Routing & Validation**: OpenAPI-based route registration and request validation
14//! - **Request/Response Processing**: Template expansion, data generation, and transformation
15//! - **Chaos Engineering**: Latency injection, failure simulation, and traffic shaping
16//! - **Proxy & Hybrid Mode**: Forward requests to real backends with intelligent fallback
17//! - **Request Chaining**: Multi-step request workflows with context passing
18//! - **Workspace Management**: Organize and persist mock configurations
19//! - **Observability**: Request logging, metrics collection, and tracing
20//!
21//! ## Quick Start: Embedding MockForge
22//!
23//! ### Creating a Simple HTTP Mock Server
24//!
25//! ```rust,no_run
26//! use mockforge_core::{
27//! OpenApiSpec, OpenApiRouteRegistry, ValidationOptions,
28//! LatencyProfile, Config,
29//! };
30//!
31//! #[tokio::main]
32//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
33//! // Load OpenAPI specification
34//! let spec = OpenApiSpec::from_file("api.json").await?;
35//!
36//! // Create route registry with validation
37//! let registry = OpenApiRouteRegistry::new(spec, ValidationOptions::default());
38//!
39//! // Configure core features
40//! let config = Config {
41//! latency_enabled: true,
42//! failures_enabled: false,
43//! default_latency: LatencyProfile::normal(),
44//! ..Default::default()
45//! };
46//!
47//! // Build your HTTP server with the registry
48//! // (See mockforge-http crate for router building)
49//!
50//! Ok(())
51//! }
52//! ```
53//!
54//! ### Request Chaining
55//!
56//! Chain multiple requests together with shared context:
57//!
58//! ```rust,no_run
59//! use mockforge_core::{ChainDefinition, ChainRequest, RequestChainRegistry};
60//!
61//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
62//! let mut registry = RequestChainRegistry::new();
63//!
64//! // Define a chain: create user → add to group → verify membership
65//! let chain = ChainDefinition {
66//! name: "user_onboarding".to_string(),
67//! steps: vec![
68//! ChainRequest {
69//! method: "POST".to_string(),
70//! path: "/users".to_string(),
71//! body: Some(r#"{"name": "{{faker.name}}"}"#.to_string()),
72//! extract: vec![("user_id".to_string(), "$.id".to_string())],
73//! ..Default::default()
74//! },
75//! ChainRequest {
76//! method: "POST".to_string(),
77//! path: "/groups/{{user_id}}/members".to_string(),
78//! ..Default::default()
79//! },
80//! ],
81//! };
82//!
83//! registry.register_chain("user_onboarding", chain)?;
84//! # Ok(())
85//! # }
86//! ```
87//!
88//! ### Latency & Failure Injection
89//!
90//! Simulate realistic network conditions and errors:
91//!
92//! ```rust,no_run
93//! use mockforge_core::{LatencyProfile, FailureConfig, create_failure_injector};
94//!
95//! // Configure latency simulation
96//! let latency = LatencyProfile::slow(); // 300-800ms
97//!
98//! // Configure failure injection
99//! let failure_config = FailureConfig {
100//! global_error_rate: 0.05, // 5% of requests fail
101//! default_status_codes: vec![500, 502, 503],
102//! ..Default::default()
103//! };
104//!
105//! let injector = create_failure_injector(Some(failure_config));
106//! ```
107//!
108//! ## Key Modules
109//!
110//! ### OpenAPI Support
111//! - [`openapi`]: Parse and work with OpenAPI specifications
112//! - [`openapi_routes`]: Register routes from OpenAPI specs with validation
113//! - [`validation`]: Request/response validation against schemas
114//!
115//! ### Request Processing
116//! - [`routing`]: Route matching and registration
117//! - [`templating`]: Template variable expansion ({{uuid}}, {{now}}, etc.)
118//! - [`request_chaining`]: Multi-step request workflows
119//! - [`overrides`]: Dynamic request/response modifications
120//!
121//! ### Chaos Engineering
122//! - [`latency`]: Latency injection with configurable profiles
123//! - [`failure_injection`]: Simulate service failures and errors
124//! - [`traffic_shaping`]: Bandwidth limiting and packet loss
125//!
126//! ### Proxy & Hybrid
127//! - [`proxy`]: Forward requests to upstream services
128//! - [`ws_proxy`]: WebSocket proxy with message transformation
129//!
130//! ### Persistence & Import
131//! - [`workspace`]: Workspace management for organizing mocks
132//! - [`workspace_import`]: Import from Postman, Insomnia, cURL, HAR
133//! - [`record_replay`]: Record real requests and replay as fixtures
134//!
135//! ### Observability
136//! - [`request_logger`]: Centralized request logging
137//! - [`performance`]: Performance metrics and profiling
138//!
139//! ## Feature Flags
140//!
141//! This crate supports several optional features:
142//!
143//! - `openapi`: OpenAPI specification support (enabled by default)
144//! - `validation`: Request/response validation (enabled by default)
145//! - `templating`: Template expansion (enabled by default)
146//! - `chaos`: Chaos engineering features (enabled by default)
147//! - `proxy`: Proxy and hybrid mode (enabled by default)
148//! - `workspace`: Workspace management (enabled by default)
149//!
150//! ## Examples
151//!
152//! See the [examples directory](https://github.com/SaaSy-Solutions/mockforge/tree/main/examples)
153//! for complete working examples.
154//!
155//! ## Related Crates
156//!
157//! - [`mockforge-http`](https://docs.rs/mockforge-http): HTTP/REST mock server
158//! - [`mockforge-grpc`](https://docs.rs/mockforge-grpc): gRPC mock server
159//! - [`mockforge-ws`](https://docs.rs/mockforge-ws): WebSocket mock server
160//! - [`mockforge-graphql`](https://docs.rs/mockforge-graphql): GraphQL mock server
161//! - [`mockforge-plugin-core`](https://docs.rs/mockforge-plugin-core): Plugin development
162//! - [`mockforge-data`](https://docs.rs/mockforge-data): Synthetic data generation
163//!
164//! ## Documentation
165//!
166//! - [MockForge Book](https://docs.mockforge.dev/)
167//! - [API Reference](https://docs.rs/mockforge-core)
168//! - [GitHub Repository](https://github.com/SaaSy-Solutions/mockforge)
169
170#![allow(deprecated)]
171
172pub mod ai_response;
173pub mod cache;
174pub mod chain_execution;
175pub mod chaos_utilities;
176pub mod collection_export;
177pub mod conditions;
178pub mod config;
179pub mod contract_validation;
180pub mod docker_compose;
181pub mod encryption;
182pub mod error;
183pub mod failure_injection;
184pub mod import;
185pub mod intelligent_behavior;
186pub mod latency;
187pub mod multi_tenant;
188pub mod network_profiles;
189pub mod openapi;
190pub mod openapi_routes;
191pub mod overrides;
192pub mod performance;
193pub mod priority_handler;
194pub mod protocol_abstraction;
195pub mod proxy;
196pub mod record_replay;
197pub mod request_chaining;
198pub mod request_fingerprint;
199pub mod request_logger;
200pub mod request_scripting;
201pub mod routing;
202pub mod schema_diff;
203pub mod server_utils;
204pub mod sync_watcher;
205pub mod templating;
206pub mod time_travel;
207pub mod time_travel_handler;
208pub mod traffic_shaping;
209pub mod validation;
210pub mod workspace;
211pub mod workspace_import;
212pub mod workspace_persistence;
213pub mod ws_proxy;
214
215pub use chain_execution::{ChainExecutionEngine, ChainExecutionResult, ChainExecutionStatus};
216pub use chaos_utilities::{ChaosConfig, ChaosEngine, ChaosResult, ChaosStatistics};
217pub use conditions::{evaluate_condition, ConditionContext, ConditionError};
218pub use config::{
219 apply_env_overrides, load_config, load_config_with_fallback, save_config, ApiKeyConfig,
220 AuthConfig, ServerConfig,
221};
222pub use error::{Error, Result};
223pub use failure_injection::{
224 create_failure_injector, FailureConfig, FailureInjector, TagFailureConfig,
225};
226pub use latency::LatencyProfile;
227pub use multi_tenant::{
228 MultiTenantConfig, MultiTenantWorkspaceRegistry, RoutingStrategy, TenantWorkspace,
229 WorkspaceContext, WorkspaceRouter, WorkspaceStats,
230};
231pub use network_profiles::{NetworkProfile, NetworkProfileCatalog};
232pub use openapi::{
233 OpenApiOperation, OpenApiRoute, OpenApiSchema, OpenApiSecurityRequirement, OpenApiSpec,
234};
235pub use openapi_routes::{
236 create_registry_from_file, create_registry_from_json, OpenApiRouteRegistry, ValidationOptions,
237};
238pub use overrides::{OverrideMode, OverrideRule, Overrides, PatchOp};
239pub use priority_handler::{
240 MockGenerator, MockResponse, PriorityHttpHandler, PriorityResponse, SimpleMockGenerator,
241};
242pub use protocol_abstraction::{
243 MessagePattern, MiddlewareChain, Protocol, ProtocolMiddleware, ProtocolRequest,
244 ProtocolResponse, RequestMatcher, ResponseStatus, SpecOperation, SpecRegistry,
245 ValidationError as ProtocolValidationError, ValidationResult as ProtocolValidationResult,
246};
247pub use proxy::{ProxyConfig, ProxyHandler, ProxyResponse};
248pub use record_replay::{
249 clean_old_fixtures, list_fixtures, list_ready_fixtures, list_smoke_endpoints, RecordHandler,
250 RecordReplayHandler, RecordedRequest, ReplayHandler,
251};
252pub use request_chaining::{
253 ChainConfig, ChainContext, ChainDefinition, ChainExecutionContext, ChainLink, ChainRequest,
254 ChainResponse, ChainStore, ChainTemplatingContext, RequestChainRegistry,
255};
256pub use request_fingerprint::{
257 RequestFingerprint, RequestHandlerResult, ResponsePriority, ResponseSource,
258};
259pub use request_logger::{
260 create_grpc_log_entry, create_http_log_entry, create_websocket_log_entry, get_global_logger,
261 init_global_logger, log_request_global, CentralizedRequestLogger, RequestLogEntry,
262};
263pub use routing::{HttpMethod, Route, RouteRegistry};
264pub use schema_diff::{to_enhanced_422_json, validation_diff, ValidationError};
265pub use server_utils::errors::{json_error, json_success};
266pub use server_utils::{create_socket_addr, localhost_socket_addr, wildcard_socket_addr};
267pub use sync_watcher::{FileChange, SyncEvent, SyncService, SyncWatcher};
268pub use templating::{expand_str, expand_tokens};
269pub use time_travel::{
270 RepeatConfig, ResponseScheduler, ScheduledResponse, TimeTravelConfig, TimeTravelManager,
271 TimeTravelStatus, VirtualClock,
272};
273pub use time_travel_handler::{
274 time_travel_middleware, ScheduledResponseWrapper, TimeTravelHandler,
275};
276pub use traffic_shaping::{BandwidthConfig, BurstLossConfig, TrafficShaper, TrafficShapingConfig};
277pub use uuid::Uuid;
278pub use validation::{validate_openapi_operation_security, validate_openapi_security, Validator};
279pub use workspace::{EntityId, Folder, MockRequest, Workspace, WorkspaceConfig, WorkspaceRegistry};
280pub use workspace_import::{
281 create_workspace_from_curl, create_workspace_from_har, create_workspace_from_insomnia,
282 create_workspace_from_postman, import_postman_to_existing_workspace,
283 import_postman_to_workspace, WorkspaceImportConfig, WorkspaceImportResult,
284};
285pub use workspace_persistence::WorkspacePersistence;
286pub use ws_proxy::{WsProxyConfig, WsProxyHandler, WsProxyRule};
287
288/// Core configuration for MockForge
289#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
290#[serde(default)]
291pub struct Config {
292 /// Enable latency simulation
293 pub latency_enabled: bool,
294 /// Enable failure simulation
295 pub failures_enabled: bool,
296 /// Enable response overrides
297 pub overrides_enabled: bool,
298 /// Enable traffic shaping (bandwidth + burst loss)
299 pub traffic_shaping_enabled: bool,
300 /// Failure injection configuration
301 pub failure_config: Option<FailureConfig>,
302 /// Proxy configuration
303 pub proxy: Option<ProxyConfig>,
304 /// Default latency profile
305 pub default_latency: LatencyProfile,
306 /// Traffic shaping configuration
307 pub traffic_shaping: TrafficShapingConfig,
308 /// Random chaos configuration
309 pub chaos_random: Option<ChaosConfig>,
310 /// Maximum number of request logs to keep in memory (default: 1000)
311 /// Helps prevent unbounded memory growth from request logging
312 pub max_request_logs: usize,
313 /// Time travel configuration for temporal testing
314 pub time_travel: TimeTravelConfig,
315}
316
317/// Default configuration
318impl Default for Config {
319 fn default() -> Self {
320 Self {
321 latency_enabled: true,
322 failures_enabled: false,
323 overrides_enabled: true,
324 traffic_shaping_enabled: false,
325 failure_config: None,
326 proxy: None,
327 default_latency: LatencyProfile::default(),
328 traffic_shaping: TrafficShapingConfig::default(),
329 chaos_random: None,
330 max_request_logs: 1000, // Default: keep last 1000 requests
331 time_travel: TimeTravelConfig::default(),
332 }
333 }
334}
335
336impl Config {
337 /// Create a ChaosEngine from the chaos_random configuration if enabled
338 pub fn create_chaos_engine(&self) -> Option<ChaosEngine> {
339 self.chaos_random.as_ref().map(|config| ChaosEngine::new(config.clone()))
340 }
341
342 /// Check if random chaos mode is enabled
343 pub fn is_chaos_random_enabled(&self) -> bool {
344 self.chaos_random.as_ref().map(|c| c.enabled).unwrap_or(false)
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351
352 #[test]
353 fn test_config_default() {
354 let config = Config::default();
355 assert!(config.latency_enabled);
356 assert!(!config.failures_enabled);
357 assert!(config.overrides_enabled);
358 assert!(!config.traffic_shaping_enabled);
359 assert!(config.failure_config.is_none());
360 assert!(config.proxy.is_none());
361 }
362
363 #[test]
364 fn test_config_serialization() {
365 let config = Config::default();
366 let json = serde_json::to_string(&config).unwrap();
367 assert!(json.contains("latency_enabled"));
368 assert!(json.contains("failures_enabled"));
369 }
370
371 #[test]
372 fn test_config_deserialization() {
373 // Use default config and modify
374 let config = Config {
375 latency_enabled: false,
376 failures_enabled: true,
377 ..Default::default()
378 };
379
380 // Serialize and deserialize
381 let json = serde_json::to_string(&config).unwrap();
382 let deserialized: Config = serde_json::from_str(&json).unwrap();
383
384 assert!(!deserialized.latency_enabled);
385 assert!(deserialized.failures_enabled);
386 assert!(deserialized.overrides_enabled);
387 }
388
389 #[test]
390 fn test_config_with_custom_values() {
391 let config = Config {
392 latency_enabled: false,
393 failures_enabled: true,
394 ..Default::default()
395 };
396
397 assert!(!config.latency_enabled);
398 assert!(config.failures_enabled);
399 }
400}