acex_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)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct FaultConfig {
16 /// Probability a message is silently dropped.
17 pub message_loss: (u32, u32),
18
19 /// Probability two consecutive messages are reordered.
20 pub message_reorder: (u32, u32),
21
22 /// Probability a message is delayed. Delay duration is drawn uniformly from `0..max_delay_us`.
23 pub message_delay: (u32, u32),
24 pub max_delay: Duration,
25
26 /// Probability a message payload byte is corrupted. Applied per-byte independently.
27 pub corruption: (u32, u32),
28
29 /// Probability a respponse is replaced with a timeout (i.e suppressed entirely, forcing the
30 /// sender to timeout)
31 pub timeout: (u32, u32),
32}
33
34impl FaultConfig {
35 /// No faults - fully deterministic pass-through.
36 pub fn none() -> Self {
37 Self {
38 message_loss: (0, 1),
39 message_reorder: (0, 1),
40 message_delay: (0, 1),
41 max_delay: Duration::ZERO,
42 corruption: (0, 1),
43 timeout: (0, 1),
44 }
45 }
46
47 /// Light fault injection - suitable for initial CI runs.
48 pub fn light() -> Self {
49 Self {
50 message_loss: (1, 100),
51 message_reorder: (1, 50),
52 message_delay: (1, 20),
53 max_delay: Duration::from_millis(50),
54 corruption: (1, 500),
55 timeout: (1, 200),
56 }
57 }
58
59 /// Heavy fault injection - chaos mode for stress testing.
60 pub fn chaos() -> Self {
61 Self {
62 message_loss: (1, 10),
63 message_reorder: (1, 5),
64 message_delay: (1, 3),
65 max_delay: Duration::from_millis(500),
66 corruption: (1, 50),
67 timeout: (1, 20),
68 }
69 }
70}
71
72// endregion: Fault Config