## Coverage Report

#### Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/trueno/src/chaos.rs

    Line
    Count
    Source
    1
    //! Chaos Engineering Configuration
    2
    //!
    3
    //! This module provides chaos engineering infrastructure for testing Trueno under
    4
    //! adverse conditions. Integrated from renacer v0.4.1 (https://github.com/paiml/renacer).
    5
    //!
    6
    //! # Examples
    7
    //!
    8
    //! ```
    9
    //! use trueno::chaos::ChaosConfig;
    10
    //! use std::time::Duration;
    11
    //!
    12
    //! // Use gentle preset for gradual stress testing
    13
    //! let gentle = ChaosConfig::gentle();
    14
    //!
    15
    //! // Use aggressive preset for extreme conditions
    16
    //! let aggressive = ChaosConfig::aggressive();
    17
    //!
    18
    //! // Custom configuration using builder pattern
    19
    //! let custom = ChaosConfig::new()
    20
    //!     .with_memory_limit(100 * 1024 * 1024)  // 100 MB
    21
    //!     .with_cpu_limit(0.5)                    // 50% CPU
    22
    //!     .with_timeout(Duration::from_secs(30))
    23
    //!     .with_signal_injection(true)
    24
    //!     .build();
    25
    //! ```
    26
    27
    use std::time::Duration;
    28
    29
    /// Chaos engineering configuration for stress testing
    30
    ///
    31
    /// Provides configurable limits and constraints for chaos testing scenarios.
    32
    /// All limits are optional and disabled by default (value of 0 means no limit).
    33
    #[derive(Debug, Clone, PartialEq)]
    34
    pub struct ChaosConfig {
    35
        /// Memory limit in bytes (0 = no limit)
    36
        pub memory_limit: usize,
    37
        /// CPU usage limit as fraction 0.0-1.0 (0.0 = no limit)
    38
        pub cpu_limit: f64,
    39
        /// Maximum execution time
    40
        pub timeout: Duration,
    41
        /// Whether to inject random signals during execution
    42
        pub signal_injection: bool,
    43
    }
    44
    45
    impl Default for ChaosConfig {
    46
    0
        fn default() -> Self {
    47
    0
            Self {
    48
    0
                memory_limit: 0,
    49
    0
                cpu_limit: 0.0,
    50
    0
                timeout: Duration::from_secs(60),
    51
    0
                signal_injection: false,
    52
    0
            }
    53
    0
        }
    54
    }
    55
    56
    impl ChaosConfig {
    57
        /// Create a new chaos configuration with default values (no limits)
    58
    0
        pub fn new() -> Self {
    59
    0
            Self::default()
    60
    0
        }
    61
    62
        /// Set memory limit in bytes
    63
        ///
    64
        /// # Examples
    65
        ///
    66
        /// ```
    67
        /// use trueno::chaos::ChaosConfig;
    68
        ///
    69
        /// let config = ChaosConfig::new()
    70
        ///     .with_memory_limit(512 * 1024 * 1024); // 512 MB
    71
        /// assert_eq!(config.memory_limit, 512 * 1024 * 1024);
    72
        /// ```
    73
    0
        pub fn with_memory_limit(mut self, bytes: usize) -> Self {
    74
    0
            self.memory_limit = bytes;
    75
    0
            self
    76
    0
        }
    77
    78
        /// Set CPU usage limit as fraction (0.0-1.0)
    79
        ///
    80
        /// Values are automatically clamped to valid range.
    81
        ///
    82
        /// # Examples
    83
        ///
    84
        /// ```
    85
        /// use trueno::chaos::ChaosConfig;
    86
        ///
    87
        /// let config = ChaosConfig::new().with_cpu_limit(0.75);
    88
        /// assert_eq!(config.cpu_limit, 0.75);
    89
        ///
    90
        /// // Values outside range are clamped
    91
        /// let clamped = ChaosConfig::new().with_cpu_limit(1.5);
    92
        /// assert_eq!(clamped.cpu_limit, 1.0);
    93
        /// ```
    94
    0
        pub fn with_cpu_limit(mut self, fraction: f64) -> Self {
    95
    0
            self.cpu_limit = fraction.clamp(0.0, 1.0);
    96
    0
            self
    97
    0
        }
    98
    99
        /// Set maximum execution timeout
    100
        ///
    101
        /// # Examples
    102
        ///
    103
        /// ```
    104
        /// use trueno::chaos::ChaosConfig;
    105
        /// use std::time::Duration;
    106
        ///
    107
        /// let config = ChaosConfig::new()
    108
        ///     .with_timeout(Duration::from_secs(30));
    109
        /// assert_eq!(config.timeout, Duration::from_secs(30));
    110
        /// ```
    111
    0
        pub fn with_timeout(mut self, timeout: Duration) -> Self {
    112
    0
            self.timeout = timeout;
    113
    0
            self
    114
    0
        }
    115
    116
        /// Enable/disable random signal injection during execution
    117
        ///
    118
        /// # Examples
    119
        ///
    120
        /// ```
    121
        /// use trueno::chaos::ChaosConfig;
    122
        ///
    123
        /// let config = ChaosConfig::new().with_signal_injection(true);
    124
        /// assert!(config.signal_injection);
    125
        /// ```
    126
    0
        pub fn with_signal_injection(mut self, enabled: bool) -> Self {
    127
    0
            self.signal_injection = enabled;
    128
    0
            self
    129
    0
        }
    130
    131
        /// Finalize configuration (no-op, for builder pattern consistency)
    132
    0
        pub fn build(self) -> Self {
    133
    0
            self
    134
    0
        }
    135
    136
        /// Gentle chaos configuration preset
    137
        ///
    138
        /// - 512 MB memory limit
    139
        /// - 80% CPU limit
    140
        /// - 120 second timeout
    141
        /// - No signal injection
    142
        ///
    143
        /// Suitable for gradual stress testing and CI environments.
    144
        ///
    145
        /// # Examples
    146
        ///
    147
        /// ```
    148
        /// use trueno::chaos::ChaosConfig;
    149
        /// use std::time::Duration;
    150
        ///
    151
        /// let config = ChaosConfig::gentle();
    152
        /// assert_eq!(config.memory_limit, 512 * 1024 * 1024);
    153
        /// assert_eq!(config.cpu_limit, 0.8);
    154
        /// assert_eq!(config.timeout, Duration::from_secs(120));
    155
        /// assert!(!config.signal_injection);
    156
        /// ```
    157
    0
        pub fn gentle() -> Self {
    158
    0
            Self::new()
    159
    0
                .with_memory_limit(512 * 1024 * 1024)
    160
    0
                .with_cpu_limit(0.8)
    161
    0
                .with_timeout(Duration::from_secs(120))
    162
    0
        }
    163
    164
        /// Aggressive chaos configuration preset
    165
        ///
    166
        /// - 64 MB memory limit
    167
        /// - 25% CPU limit
    168
        /// - 10 second timeout
    169
        /// - Signal injection enabled
    170
        ///
    171
        /// Suitable for extreme stress testing and finding edge cases.
    172
        ///
    173
        /// # Examples
    174
        ///
    175
        /// ```
    176
        /// use trueno::chaos::ChaosConfig;
    177
        /// use std::time::Duration;
    178
        ///
    179
        /// let config = ChaosConfig::aggressive();
    180
        /// assert_eq!(config.memory_limit, 64 * 1024 * 1024);
    181
        /// assert_eq!(config.cpu_limit, 0.25);
    182
        /// assert_eq!(config.timeout, Duration::from_secs(10));
    183
        /// assert!(config.signal_injection);
    184
        /// ```
    185
    0
        pub fn aggressive() -> Self {
    186
    0
            Self::new()
    187
    0
                .with_memory_limit(64 * 1024 * 1024)
    188
    0
                .with_cpu_limit(0.25)
    189
    0
                .with_timeout(Duration::from_secs(10))
    190
    0
                .with_signal_injection(true)
    191
    0
        }
    192
    }
    193
    194
    /// Result type for chaos operations
    195
    pub type ChaosResult<T> = Result<T, ChaosError>;
    196
    197
    /// Errors that can occur during chaos testing
    198
    #[derive(Debug, Clone, PartialEq, Eq)]
    199
    pub enum ChaosError {
    200
        /// Memory limit was exceeded during execution
    201
        MemoryLimitExceeded {
    202
            /// Configured memory limit in bytes
    203
            limit: usize,
    204
            /// Actual memory used in bytes
    205
            used: usize,
    206
        },
    207
        /// Execution exceeded timeout
    208
        Timeout {
    209
            /// Time elapsed before timeout
    210
            elapsed: Duration,
    211
            /// Configured timeout limit
    212
            limit: Duration,
    213
        },
    214
        /// Signal injection failed
    215
        SignalInjectionFailed {
    216
            /// Signal number that failed to inject
    217
            signal: i32,
    218
            /// Reason for failure
    219
            reason: String,
    220
        },
    221
    }
    222
    223
    impl std::fmt::Display for ChaosError {
    224
    0
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    225
    0
            match self {
    226
    0
                ChaosError::MemoryLimitExceeded { limit, used } => {
    227
    0
                    write!(f, "Memory limit exceeded: {} > {} bytes", used, limit)
    228
                }
    229
    0
                ChaosError::Timeout { elapsed, limit } => {
    230
    0
                    write!(f, "Timeout: {:?} > {:?}", elapsed, limit)
    231
                }
    232
    0
                ChaosError::SignalInjectionFailed { signal, reason } => {
    233
    0
                    write!(f, "Signal injection failed ({}): {}", signal, reason)
    234
                }
    235
            }
    236
    0
        }
    237
    }
    238
    239
    impl std::error::Error for ChaosError {}
    240
    241
    #[cfg(test)]
    242
    mod tests {
    243
        use super::*;
    244
    245
        #[test]
    246
        fn test_default_config() {
    247
            let config = ChaosConfig::default();
    248
            assert_eq!(config.memory_limit, 0);
    249
            assert_eq!(config.cpu_limit, 0.0);
    250
            assert_eq!(config.timeout, Duration::from_secs(60));
    251
            assert!(!config.signal_injection);
    252
        }
    253
    254
        #[test]
    255
        fn test_builder_pattern() {
    256
            let config = ChaosConfig::new()
    257
                .with_memory_limit(1024)
    258
                .with_cpu_limit(0.5)
    259
                .with_timeout(Duration::from_secs(30))
    260
                .with_signal_injection(true)
    261
                .build();
    262
    263
            assert_eq!(config.memory_limit, 1024);
    264
            assert_eq!(config.cpu_limit, 0.5);
    265
            assert_eq!(config.timeout, Duration::from_secs(30));
    266
            assert!(config.signal_injection);
    267
        }
    268
    269
        #[test]
    270
        fn test_cpu_limit_clamping() {
    271
            let too_high = ChaosConfig::new().with_cpu_limit(1.5);
    272
            assert_eq!(too_high.cpu_limit, 1.0);
    273
    274
            let too_low = ChaosConfig::new().with_cpu_limit(-0.5);
    275
            assert_eq!(too_low.cpu_limit, 0.0);
    276
    277
            let valid = ChaosConfig::new().with_cpu_limit(0.75);
    278
            assert_eq!(valid.cpu_limit, 0.75);
    279
        }
    280
    281
        #[test]
    282
        fn test_gentle_preset() {
    283
            let gentle = ChaosConfig::gentle();
    284
            assert_eq!(gentle.memory_limit, 512 * 1024 * 1024);
    285
            assert_eq!(gentle.cpu_limit, 0.8);
    286
            assert_eq!(gentle.timeout, Duration::from_secs(120));
    287
            assert!(!gentle.signal_injection);
    288
        }
    289
    290
        #[test]
    291
        fn test_aggressive_preset() {
    292
            let aggressive = ChaosConfig::aggressive();
    293
            assert_eq!(aggressive.memory_limit, 64 * 1024 * 1024);
    294
            assert_eq!(aggressive.cpu_limit, 0.25);
    295
            assert_eq!(aggressive.timeout, Duration::from_secs(10));
    296
            assert!(aggressive.signal_injection);
    297
        }
    298
    299
        #[test]
    300
        fn test_chaos_error_display() {
    301
            let mem_err = ChaosError::MemoryLimitExceeded {
    302
                limit: 1000,
    303
                used: 2000,
    304
            };
    305
            assert_eq!(
    306
                format!("{}", mem_err),
    307
                "Memory limit exceeded: 2000 > 1000 bytes"
    308
            );
    309
    310
            let timeout_err = ChaosError::Timeout {
    311
                elapsed: Duration::from_secs(5),
    312
                limit: Duration::from_secs(3),
    313
            };
    314
            assert!(format!("{}", timeout_err).contains("Timeout"));
    315
    316
            let signal_err = ChaosError::SignalInjectionFailed {
    317
                signal: 9,
    318
                reason: "test failure".to_string(),
    319
            };
    320
            assert_eq!(
    321
                format!("{}", signal_err),
    322
                "Signal injection failed (9): test failure"
    323
            );
    324
        }
    325
    }