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//!     Config, LatencyProfile, OpenApiRouteRegistry, OpenApiSpec, Result, ValidationOptions,
28//! };
29//!
30//! #[tokio::main]
31//! async fn main() -> Result<()> {
32//!     // Load OpenAPI specification
33//!     let spec = OpenApiSpec::from_file("api.json").await?;
34//!
35//!     // Create route registry with validation
36//!     let registry = OpenApiRouteRegistry::new_with_options(spec, ValidationOptions::default());
37//!
38//!     // Configure core features
39//!     let config = Config {
40//!         latency_enabled: true,
41//!         failures_enabled: false,
42//!         default_latency: LatencyProfile::with_normal_distribution(400, 120.0),
43//!         ..Default::default()
44//!     };
45//!
46//!     // Build your HTTP server with the registry
47//!     // (See mockforge-http crate for router building)
48//!
49//!     Ok(())
50//! }
51//! ```
52//!
53//! ### Request Chaining
54//!
55//! Chain multiple requests together with shared context:
56//!
57//! ```rust,no_run
58//! use mockforge_core::{
59//!     ChainConfig, ChainDefinition, ChainLink, ChainRequest, RequestChainRegistry, Result,
60//! };
61//! use mockforge_core::request_chaining::RequestBody;
62//! use serde_json::json;
63//! use std::collections::HashMap;
64//!
65//! # async fn example() -> Result<()> {
66//! let registry = RequestChainRegistry::new(ChainConfig::default());
67//!
68//! // Define a chain: create user → add to group → verify membership
69//! let chain = ChainDefinition {
70//!     id: "user_onboarding".to_string(),
71//!     name: "User Onboarding".to_string(),
72//!     description: Some("Create user → add to group".to_string()),
73//!     config: ChainConfig {
74//!         enabled: true,
75//!         ..ChainConfig::default()
76//!     },
77//!     links: vec![
78//!         ChainLink {
79//!             request: ChainRequest {
80//!                 id: "create_user".to_string(),
81//!                 method: "POST".to_string(),
82//!                 url: "https://api.example.com/users".to_string(),
83//!                 headers: HashMap::new(),
84//!                 body: Some(RequestBody::json(json!({"name": "{{faker.name}}"}))),
85//!                 depends_on: Vec::new(),
86//!                 timeout_secs: None,
87//!                 expected_status: None,
88//!                 scripting: None,
89//!             },
90//!             extract: HashMap::from([("user_id".to_string(), "create_user.body.id".to_string())]),
91//!             store_as: Some("create_user_response".to_string()),
92//!         },
93//!         ChainLink {
94//!             request: ChainRequest {
95//!                 id: "add_to_group".to_string(),
96//!                 method: "POST".to_string(),
97//!                 url: "https://api.example.com/groups/{{user_id}}/members".to_string(),
98//!                 headers: HashMap::new(),
99//!                 body: None,
100//!                 depends_on: vec!["create_user".to_string()],
101//!                 timeout_secs: None,
102//!                 expected_status: None,
103//!                 scripting: None,
104//!             },
105//!             extract: HashMap::new(),
106//!             store_as: None,
107//!         },
108//!     ],
109//!     variables: HashMap::new(),
110//!     tags: vec!["onboarding".to_string()],
111//! };
112//!
113//! registry.store().register_chain(chain).await?;
114//! # Ok(())
115//! # }
116//! ```
117//!
118//! ### Latency & Failure Injection
119//!
120//! Simulate realistic network conditions and errors:
121//!
122//! ```rust,no_run
123//! use mockforge_core::{LatencyProfile, FailureConfig, create_failure_injector};
124//!
125//! // Configure latency simulation
126//! let latency = LatencyProfile::with_normal_distribution(400, 120.0)
127//!     .with_min_ms(100)
128//!     .with_max_ms(800);
129//!
130//! // Configure failure injection
131//! let failure_config = FailureConfig {
132//!     global_error_rate: 0.05, // 5% of requests fail
133//!     default_status_codes: vec![500, 502, 503],
134//!     ..Default::default()
135//! };
136//!
137//! let injector = create_failure_injector(true, Some(failure_config));
138//! ```
139//!
140//! ## Key Modules
141//!
142//! ### OpenAPI Support
143//! - [`openapi`]: Parse and work with OpenAPI specifications
144//! - [`openapi_routes`]: Register routes from OpenAPI specs with validation
145//! - [`validation`]: Request/response validation against schemas
146//!
147//! ### Request Processing
148//! - [`routing`]: Route matching and registration
149//! - [`templating`]: Template variable expansion ({{uuid}}, {{now}}, etc.)
150//! - [`request_chaining`]: Multi-step request workflows
151//! - [`overrides`]: Dynamic request/response modifications
152//!
153//! ### Chaos Engineering
154//! - [`latency`]: Latency injection with configurable profiles
155//! - [`failure_injection`]: Simulate service failures and errors
156//! - [`traffic_shaping`]: Bandwidth limiting and packet loss
157//!
158//! ### Proxy & Hybrid
159//! - [`proxy`]: Forward requests to upstream services
160//! - [`ws_proxy`]: WebSocket proxy with message transformation
161//!
162//! ### Persistence & Import
163//! - [`workspace`]: Workspace management for organizing mocks
164//! - [`workspace_import`]: Import from Postman, Insomnia, cURL, HAR
165//! - [`record_replay`]: Record real requests and replay as fixtures
166//!
167//! ### Observability
168//! - [`request_logger`]: Centralized request logging
169//! - [`performance`]: Performance metrics and profiling
170//!
171//! ## Feature Flags
172//!
173//! This crate supports several optional features:
174//!
175//! - `openapi`: OpenAPI specification support (enabled by default)
176//! - `validation`: Request/response validation (enabled by default)
177//! - `templating`: Template expansion (enabled by default)
178//! - `chaos`: Chaos engineering features (enabled by default)
179//! - `proxy`: Proxy and hybrid mode (enabled by default)
180//! - `workspace`: Workspace management (enabled by default)
181//!
182//! ## Examples
183//!
184//! See the [examples directory](https://github.com/SaaSy-Solutions/mockforge/tree/main/examples)
185//! for complete working examples.
186//!
187//! ## Related Crates
188//!
189//! - [`mockforge-http`](https://docs.rs/mockforge-http): HTTP/REST mock server
190//! - [`mockforge-grpc`](https://docs.rs/mockforge-grpc): gRPC mock server
191//! - [`mockforge-ws`](https://docs.rs/mockforge-ws): WebSocket mock server
192//! - [`mockforge-graphql`](https://docs.rs/mockforge-graphql): GraphQL mock server
193//! - [`mockforge-plugin-core`](https://docs.rs/mockforge-plugin-core): Plugin development
194//! - [`mockforge-data`](https://docs.rs/mockforge-data): Synthetic data generation
195//!
196//! ## Documentation
197//!
198//! - [MockForge Book](https://docs.mockforge.dev/)
199//! - [API Reference](https://docs.rs/mockforge-core)
200//! - [GitHub Repository](https://github.com/SaaSy-Solutions/mockforge)
201
202#![allow(deprecated)]
203
204pub mod ab_testing;
205pub mod ai_contract_diff;
206pub mod ai_response;
207/// AI Studio - Unified AI Copilot for all AI-powered features
208pub mod ai_studio;
209/// Behavioral cloning of backends - learn from recorded traffic to create realistic mock behavior
210pub mod behavioral_cloning;
211pub mod behavioral_economics;
212pub mod cache;
213pub mod chain_execution;
214pub mod chaos_utilities;
215pub mod codegen;
216/// Collection export utilities for exporting mock data in various formats
217pub mod collection_export;
218pub mod conditions;
219pub mod config;
220/// Cross-protocol consistency engine for unified state across all protocols
221pub mod consistency;
222/// Consumer-driven contracts for tracking usage and detecting consumer-specific breaking changes
223pub mod consumer_contracts;
224/// Contract validation for ensuring API contracts match specifications
225pub mod contract_drift;
226/// Contract validation for ensuring API contracts match specifications
227pub mod contract_validation;
228/// Contract webhooks for notifying external systems about contract changes
229pub mod contract_webhooks;
230pub mod custom_fixture;
231/// Data source abstraction for loading test data from multiple sources
232pub mod data_source;
233/// Deceptive canary mode for routing team traffic to deceptive deploys
234pub mod deceptive_canary;
235/// Docker Compose integration for containerized mock deployments
236pub mod docker_compose;
237/// GitOps integration for drift budget violations
238pub mod drift_gitops;
239pub mod encryption;
240pub mod error;
241pub mod failure_analysis;
242pub mod failure_injection;
243pub mod fidelity;
244pub mod generate_config;
245pub mod generative_schema;
246pub mod git_watch;
247pub mod graph;
248pub mod import;
249pub mod incidents;
250pub mod intelligent_behavior;
251pub mod latency;
252pub mod lifecycle;
253pub mod multi_tenant;
254pub mod network_profiles;
255pub mod openapi;
256pub mod openapi_routes;
257pub mod output_control;
258pub mod overrides;
259pub mod performance;
260/// Pillar usage tracking utilities
261pub mod pillar_tracking;
262/// Pillar metadata system for compile-time pillar tagging
263pub mod pillars;
264pub mod pr_generation;
265pub mod priority_handler;
266pub mod protocol_abstraction;
267pub mod proxy;
268pub mod reality;
269pub mod reality_continuum;
270pub mod record_replay;
271pub mod request_capture;
272pub mod request_chaining;
273pub mod request_fingerprint;
274pub mod request_logger;
275pub mod request_scripting;
276// Route chaos has been moved to mockforge-route-chaos crate to avoid Send issues
277// Import directly from mockforge-route-chaos crate instead of re-exporting here
278// to avoid circular dependency (mockforge-route-chaos depends on mockforge-core for config types)
279pub mod persona_lifecycle_time;
280pub mod routing;
281/// Runtime validation for SDKs (request/response validation at runtime)
282pub mod runtime_validation;
283/// Scenario Studio - Visual editor for co-editing business flows
284pub mod scenario_studio;
285pub mod scenarios;
286pub mod schema_diff;
287pub mod security;
288pub mod server_utils;
289/// Time travel and snapshot functionality for saving and restoring system states
290pub mod snapshots;
291pub mod spec_parser;
292pub mod stateful_handler;
293pub mod sync_watcher;
294/// Template expansion utilities (Send-safe, isolated from templating module)
295pub mod template_expansion;
296/// Template library system for shared templates, versioning, and marketplace
297pub mod template_library;
298pub mod templating;
299pub mod time_travel;
300pub mod time_travel_handler;
301pub mod traffic_shaping;
302pub mod validation;
303pub mod verification;
304pub mod voice;
305pub mod workspace;
306pub mod workspace_import;
307pub mod workspace_persistence;
308pub mod ws_proxy;
309
310pub use ab_testing::{
311    apply_variant_to_response, select_variant, ABTestConfig, ABTestReport,
312    ABTestingMiddlewareState, MockVariant, VariantAllocation, VariantAnalytics, VariantComparison,
313    VariantManager, VariantSelectionStrategy,
314};
315pub use behavioral_cloning::{
316    AmplificationScope, BehavioralSequence, EdgeAmplificationConfig, EdgeAmplifier,
317    EndpointProbabilityModel, ErrorPattern, LatencyDistribution, PayloadVariation,
318    ProbabilisticModel, SequenceLearner, SequenceStep,
319};
320pub use chain_execution::{ChainExecutionEngine, ChainExecutionResult, ChainExecutionStatus};
321pub use chaos_utilities::{ChaosConfig, ChaosEngine, ChaosResult, ChaosStatistics};
322pub use conditions::{evaluate_condition, ConditionContext, ConditionError};
323pub use config::{
324    apply_env_overrides, load_config, load_config_with_fallback, save_config, ApiKeyConfig,
325    AuthConfig, ServerConfig,
326};
327pub use consistency::{
328    ConsistencyEngine, EntityState, ProtocolState, SessionInfo, StateChangeEvent, UnifiedState,
329};
330pub use custom_fixture::{CustomFixture, CustomFixtureLoader, NestedFixture};
331pub use data_source::{
332    DataSource, DataSourceConfig, DataSourceContent, DataSourceFactory, DataSourceManager,
333    DataSourceType, GitDataSource, HttpDataSource, LocalDataSource,
334};
335pub use deceptive_canary::{
336    CanaryRoutingStrategy, CanaryStats, DeceptiveCanaryConfig, DeceptiveCanaryRouter,
337    TeamIdentifiers,
338};
339pub use error::{Error, Result};
340pub use failure_analysis::{
341    ContributingFactor, FailureContext, FailureContextCollector, FailureNarrative,
342    FailureNarrativeGenerator, NarrativeFrame,
343};
344pub use failure_injection::{
345    create_failure_injector, FailureConfig, FailureInjector, TagFailureConfig,
346};
347pub use fidelity::{FidelityCalculator, FidelityScore, SampleComparator, SchemaComparator};
348pub use generate_config::{
349    discover_config_file, load_generate_config, load_generate_config_with_fallback,
350    save_generate_config, BarrelType, GenerateConfig, GenerateOptions, InputConfig, OutputConfig,
351    PluginConfig,
352};
353pub use git_watch::{GitWatchConfig, GitWatchService};
354pub use graph::{
355    builder::GraphBuilder, relationships, ClusterType, EdgeType, GraphCluster, GraphData,
356    GraphEdge, GraphNode, NodeType, Protocol as GraphProtocol,
357};
358pub use latency::LatencyProfile;
359pub use lifecycle::{
360    LifecycleHook, LifecycleHookRegistry, MockLifecycleEvent, RequestContext, ResponseContext,
361    ServerLifecycleEvent,
362};
363pub use multi_tenant::{
364    MultiTenantConfig, MultiTenantWorkspaceRegistry, RoutingStrategy, TenantWorkspace,
365    WorkspaceContext, WorkspaceRouter, WorkspaceStats,
366};
367pub use network_profiles::{NetworkProfile, NetworkProfileCatalog};
368pub use openapi::{
369    OpenApiOperation, OpenApiRoute, OpenApiSchema, OpenApiSecurityRequirement, OpenApiSpec,
370};
371pub use openapi_routes::{
372    create_registry_from_file, create_registry_from_json, OpenApiRouteRegistry, ValidationOptions,
373};
374pub use output_control::{
375    apply_banner, apply_extension, apply_file_naming_template, build_file_naming_context,
376    process_generated_file, BarrelGenerator, FileNamingContext, GeneratedFile,
377};
378pub use overrides::{OverrideMode, OverrideRule, Overrides, PatchOp};
379pub use pillars::{Pillar, PillarMetadata};
380pub use priority_handler::{
381    MockGenerator, MockResponse, PriorityHttpHandler, PriorityResponse, SimpleMockGenerator,
382};
383pub use protocol_abstraction::{
384    MessagePattern, MiddlewareChain, Protocol, ProtocolMiddleware, ProtocolRequest,
385    ProtocolResponse, RequestMatcher, ResponseStatus, SpecOperation, SpecRegistry,
386    ValidationError as ProtocolValidationError, ValidationResult as ProtocolValidationResult,
387};
388pub use proxy::{ProxyConfig, ProxyHandler, ProxyResponse};
389pub use reality::{PresetMetadata, RealityConfig, RealityEngine, RealityLevel, RealityPreset};
390pub use reality_continuum::{
391    ContinuumConfig, ContinuumRule, MergeStrategy, RealityContinuumEngine, ResponseBlender,
392    TimeSchedule, TransitionCurve, TransitionMode,
393};
394pub use record_replay::{
395    clean_old_fixtures, list_fixtures, list_ready_fixtures, list_smoke_endpoints, RecordHandler,
396    RecordReplayHandler, RecordedRequest, ReplayHandler,
397};
398pub use request_chaining::{
399    ChainConfig, ChainContext, ChainDefinition, ChainExecutionContext, ChainLink, ChainRequest,
400    ChainResponse, ChainStore, ChainTemplatingContext, RequestChainRegistry,
401};
402pub use request_fingerprint::{
403    RequestFingerprint, RequestHandlerResult, ResponsePriority, ResponseSource,
404};
405pub use request_logger::{
406    create_grpc_log_entry, create_http_log_entry, create_http_log_entry_with_query,
407    create_websocket_log_entry, get_global_logger, init_global_logger, log_request_global,
408    CentralizedRequestLogger, RequestLogEntry,
409};
410// Route chaos types moved to mockforge-route-chaos crate
411// Import directly: use mockforge_route_chaos::{RouteChaosInjector, RouteFaultResponse, RouteMatcher};
412pub use routing::{HttpMethod, Route, RouteRegistry};
413pub use runtime_validation::{
414    RuntimeValidationError, RuntimeValidationResult, RuntimeValidatorConfig, SchemaMetadata,
415};
416pub use scenario_studio::{
417    ConditionOperator, FlowCondition, FlowConnection, FlowDefinition, FlowExecutionResult,
418    FlowExecutor, FlowPosition, FlowStep, FlowStepResult, FlowType, FlowVariant, StepType,
419};
420pub use scenarios::types::StepResult;
421pub use scenarios::{
422    ScenarioDefinition, ScenarioExecutor, ScenarioParameter, ScenarioRegistry, ScenarioResult,
423    ScenarioStep,
424};
425pub use schema_diff::{to_enhanced_422_json, validation_diff, ValidationError};
426pub use server_utils::errors::{json_error, json_success};
427pub use server_utils::{create_socket_addr, localhost_socket_addr, wildcard_socket_addr};
428pub use snapshots::{SnapshotComponents, SnapshotManager, SnapshotManifest, SnapshotMetadata};
429pub use spec_parser::{GraphQLValidator, OpenApiValidator, SpecFormat};
430pub use stateful_handler::{
431    ResourceIdExtract, StateInfo, StateResponse, StatefulConfig, StatefulResponse,
432    StatefulResponseHandler, TransitionTrigger,
433};
434pub use sync_watcher::{FileChange, SyncEvent, SyncService, SyncWatcher};
435pub use template_library::{
436    TemplateLibrary, TemplateLibraryEntry, TemplateLibraryManager, TemplateMarketplace,
437    TemplateMetadata, TemplateVersion,
438};
439pub use templating::{expand_str, expand_tokens};
440pub use time_travel::{
441    cron::{CronJob, CronJobAction, CronScheduler},
442    get_global_clock, is_time_travel_enabled, now as time_travel_now, register_global_clock,
443    unregister_global_clock, RepeatConfig, ResponseScheduler, ScheduledResponse, TimeScenario,
444    TimeTravelConfig, TimeTravelManager, TimeTravelStatus, VirtualClock,
445};
446pub use time_travel_handler::{
447    time_travel_middleware, ScheduledResponseWrapper, TimeTravelHandler,
448};
449pub use traffic_shaping::{BandwidthConfig, BurstLossConfig, TrafficShaper, TrafficShapingConfig};
450pub use uuid::Uuid;
451pub use validation::{validate_openapi_operation_security, validate_openapi_security, Validator};
452pub use verification::{
453    matches_verification_pattern, verify_at_least, verify_never, verify_requests, verify_sequence,
454    VerificationCount, VerificationRequest, VerificationResult,
455};
456pub use voice::{
457    ConversationContext, ConversationManager, ConversationState, GeneratedWorkspaceScenario,
458    HookTranspiler, ParsedCommand, ParsedWorkspaceScenario, VoiceCommandParser, VoiceSpecGenerator,
459    WorkspaceConfigSummary, WorkspaceScenarioGenerator,
460};
461pub use workspace::promotion_trait::PromotionService;
462pub use workspace::{EntityId, Folder, MockRequest, Workspace, WorkspaceConfig, WorkspaceRegistry};
463pub use workspace_import::{
464    create_workspace_from_curl, create_workspace_from_har, create_workspace_from_insomnia,
465    create_workspace_from_postman, import_postman_to_existing_workspace,
466    import_postman_to_workspace, WorkspaceImportConfig, WorkspaceImportResult,
467};
468pub use workspace_persistence::WorkspacePersistence;
469pub use ws_proxy::{WsProxyConfig, WsProxyHandler, WsProxyRule};
470// Note: ValidationError and ValidationResult from spec_parser conflict with schema_diff::ValidationError
471// Use qualified paths: spec_parser::ValidationError, spec_parser::ValidationResult
472
473/// Core configuration for MockForge
474#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
475#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
476#[serde(default)]
477pub struct Config {
478    /// Enable latency simulation
479    pub latency_enabled: bool,
480    /// Enable failure simulation
481    pub failures_enabled: bool,
482    /// Enable response overrides
483    pub overrides_enabled: bool,
484    /// Enable traffic shaping (bandwidth + burst loss)
485    pub traffic_shaping_enabled: bool,
486    /// Failure injection configuration
487    pub failure_config: Option<FailureConfig>,
488    /// Proxy configuration
489    pub proxy: Option<ProxyConfig>,
490    /// Default latency profile
491    pub default_latency: LatencyProfile,
492    /// Traffic shaping configuration
493    pub traffic_shaping: TrafficShapingConfig,
494    /// Random chaos configuration
495    pub chaos_random: Option<ChaosConfig>,
496    /// Maximum number of request logs to keep in memory (default: 1000)
497    /// Helps prevent unbounded memory growth from request logging
498    pub max_request_logs: usize,
499    /// Time travel configuration for temporal testing
500    pub time_travel: TimeTravelConfig,
501}
502
503/// Default configuration
504impl Default for Config {
505    fn default() -> Self {
506        Self {
507            latency_enabled: true,
508            failures_enabled: false,
509            overrides_enabled: true,
510            traffic_shaping_enabled: false,
511            failure_config: None,
512            proxy: None,
513            default_latency: LatencyProfile::default(),
514            traffic_shaping: TrafficShapingConfig::default(),
515            chaos_random: None,
516            max_request_logs: 1000, // Default: keep last 1000 requests
517            time_travel: TimeTravelConfig::default(),
518        }
519    }
520}
521
522impl Config {
523    /// Create a ChaosEngine from the chaos_random configuration if enabled
524    pub fn create_chaos_engine(&self) -> Option<ChaosEngine> {
525        self.chaos_random.as_ref().map(|config| ChaosEngine::new(config.clone()))
526    }
527
528    /// Check if random chaos mode is enabled
529    pub fn is_chaos_random_enabled(&self) -> bool {
530        self.chaos_random.as_ref().map(|c| c.enabled).unwrap_or(false)
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537
538    #[test]
539    fn test_config_default() {
540        let config = Config::default();
541        assert!(config.latency_enabled);
542        assert!(!config.failures_enabled);
543        assert!(config.overrides_enabled);
544        assert!(!config.traffic_shaping_enabled);
545        assert!(config.failure_config.is_none());
546        assert!(config.proxy.is_none());
547    }
548
549    #[test]
550    fn test_config_serialization() {
551        let config = Config::default();
552        let json = serde_json::to_string(&config).unwrap();
553        assert!(json.contains("latency_enabled"));
554        assert!(json.contains("failures_enabled"));
555    }
556
557    #[test]
558    fn test_config_deserialization() {
559        // Use default config and modify
560        let config = Config {
561            latency_enabled: false,
562            failures_enabled: true,
563            ..Default::default()
564        };
565
566        // Serialize and deserialize
567        let json = serde_json::to_string(&config).unwrap();
568        let deserialized: Config = serde_json::from_str(&json).unwrap();
569
570        assert!(!deserialized.latency_enabled);
571        assert!(deserialized.failures_enabled);
572        assert!(deserialized.overrides_enabled);
573    }
574
575    #[test]
576    fn test_config_with_custom_values() {
577        let config = Config {
578            latency_enabled: false,
579            failures_enabled: true,
580            ..Default::default()
581        };
582
583        assert!(!config.latency_enabled);
584        assert!(config.failures_enabled);
585    }
586}