ace_sim/fault.rs
1// region: Imports
2
3use crate::clock::Duration;
4
5// endregion: Imports
6
7// region: Fault Config
8
9/// Controls which faults the simulation bus may inject and at what rates.
10///
11/// All probabilities are expressed as `(numerator, denominator)` pairs. For example `(1, 100)`
12/// means a 1% chance per eligible event.
13#[derive(Debug, Clone)]
14pub struct FaultConfig {
15 /// Probability a message is silently dropped.
16 pub message_loss: (u32, u32),
17
18 /// Probability two consecutive messages are reordered.
19 pub message_reorder: (u32, u32),
20
21 /// Probability a message is delayed. Delay duration is drawn uniformly from `0..max_delay_us`.
22 pub message_delay: (u32, u32),
23 pub max_delay: Duration,
24
25 /// Probability a message payload byte is corrupted. Applied per-byte independently.
26 pub corruption: (u32, u32),
27
28 /// Probability a respponse is replaced with a timeout (i.e suppressed entirely, forcing the
29 /// sender to timeout)
30 pub timeout: (u32, u32),
31}
32
33impl FaultConfig {
34 /// No faults - fully deterministic pass-through.
35 pub fn none() -> Self {
36 Self {
37 message_loss: (0, 1),
38 message_reorder: (0, 1),
39 message_delay: (0, 1),
40 max_delay: Duration::ZERO,
41 corruption: (0, 1),
42 timeout: (0, 1),
43 }
44 }
45
46 /// Light fault injection - suitable for initial CI runs.
47 pub fn light() -> Self {
48 Self {
49 message_loss: (1, 100),
50 message_reorder: (1, 50),
51 message_delay: (1, 20),
52 max_delay: Duration::from_millis(50),
53 corruption: (1, 500),
54 timeout: (1, 200),
55 }
56 }
57
58 /// Heavy fault injection - chaos mode for stress testing.
59 pub fn chaos() -> Self {
60 Self {
61 message_loss: (1, 10),
62 message_reorder: (1, 5),
63 message_delay: (1, 3),
64 max_delay: Duration::from_millis(500),
65 corruption: (1, 50),
66 timeout: (1, 20),
67 }
68 }
69}
70
71// endregion: Fault Config