rust_supervisor/test_support/factory.rs
1//! Deterministic helpers for supervisor tests.
2//!
3//! The module provides small reusable fixtures for event collection, paused
4//! time, and deterministic jitter.
5
6use crate::event::payload::{SupervisorEvent, What, Where};
7use crate::event::time::{CorrelationId, EventSequence, EventSequenceSource, EventTime, When};
8use crate::id::types::{Attempt, ChildId, Generation, SupervisorPath};
9use serde::{Deserialize, Serialize};
10use uuid::Uuid;
11
12/// Paused time source for deterministic tests.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub struct PausedTime {
15 /// Wall-clock time in nanoseconds since the Unix epoch.
16 pub unix_nanos: u128,
17 /// Monotonic time in nanoseconds.
18 pub monotonic_nanos: u128,
19 /// Supervisor uptime in milliseconds.
20 pub uptime_ms: u64,
21}
22
23impl PausedTime {
24 /// Creates a paused time source.
25 ///
26 /// # Arguments
27 ///
28 /// - `unix_nanos`: Wall-clock timestamp in nanoseconds.
29 /// - `monotonic_nanos`: Monotonic timestamp in nanoseconds.
30 /// - `uptime_ms`: Supervisor uptime in milliseconds.
31 ///
32 /// # Returns
33 ///
34 /// Returns a [`PausedTime`] value.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// let time = rust_supervisor::test_support::factory::PausedTime::new(1, 2, 3);
40 /// assert_eq!(time.uptime_ms, 3);
41 /// ```
42 pub fn new(unix_nanos: u128, monotonic_nanos: u128, uptime_ms: u64) -> Self {
43 Self {
44 unix_nanos,
45 monotonic_nanos,
46 uptime_ms,
47 }
48 }
49
50 /// Creates deterministic event time.
51 ///
52 /// # Arguments
53 ///
54 /// - `generation`: Child generation for the event.
55 /// - `attempt`: Child attempt for the event.
56 ///
57 /// # Returns
58 ///
59 /// Returns an [`EventTime`] value.
60 pub fn event_time(&self, generation: Generation, attempt: Attempt) -> EventTime {
61 EventTime::deterministic(
62 self.unix_nanos,
63 self.monotonic_nanos,
64 self.uptime_ms,
65 generation,
66 attempt,
67 )
68 }
69}
70
71/// Deterministic jitter helper for backoff tests.
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
73pub struct DeterministicJitter {
74 /// Percentage points applied to the base delay.
75 pub percent: i64,
76}
77
78impl DeterministicJitter {
79 /// Creates a deterministic jitter source.
80 ///
81 /// # Arguments
82 ///
83 /// - `percent`: Signed percentage applied to the base delay.
84 ///
85 /// # Returns
86 ///
87 /// Returns a [`DeterministicJitter`] value.
88 pub fn new(percent: i64) -> Self {
89 Self { percent }
90 }
91
92 /// Applies jitter to a millisecond delay.
93 ///
94 /// # Arguments
95 ///
96 /// - `base_ms`: Base delay in milliseconds.
97 ///
98 /// # Returns
99 ///
100 /// Returns the adjusted delay in milliseconds.
101 ///
102 /// # Examples
103 ///
104 /// ```
105 /// let jitter = rust_supervisor::test_support::factory::DeterministicJitter::new(10);
106 /// assert_eq!(jitter.apply_ms(100), 110);
107 /// ```
108 pub fn apply_ms(&self, base_ms: u64) -> u64 {
109 let base = i128::from(base_ms);
110 let delta = base.saturating_mul(i128::from(self.percent)) / 100;
111 base.saturating_add(delta).max(0) as u64
112 }
113}
114
115/// Collector that stores supervisor events in memory.
116#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
117pub struct EventCollector {
118 /// Events collected in receive order.
119 pub events: Vec<SupervisorEvent>,
120}
121
122impl EventCollector {
123 /// Creates an empty collector.
124 ///
125 /// # Arguments
126 ///
127 /// This function has no arguments.
128 ///
129 /// # Returns
130 ///
131 /// Returns a new [`EventCollector`].
132 pub fn new() -> Self {
133 Self::default()
134 }
135
136 /// Pushes one event into the collector.
137 ///
138 /// # Arguments
139 ///
140 /// - `event`: Event to store.
141 ///
142 /// # Returns
143 ///
144 /// This function does not return a value.
145 pub fn push(&mut self, event: SupervisorEvent) {
146 self.events.push(event);
147 }
148
149 /// Returns collected event names.
150 ///
151 /// # Arguments
152 ///
153 /// This function has no arguments.
154 ///
155 /// # Returns
156 ///
157 /// Returns event names in receive order.
158 pub fn event_names(&self) -> Vec<&'static str> {
159 self.events.iter().map(|event| event.what.name()).collect()
160 }
161}
162
163/// Fixture that builds deterministic lifecycle events.
164#[derive(Debug)]
165pub struct EventFixture {
166 /// Paused time used for every event.
167 pub paused_time: PausedTime,
168 /// Sequence source used by the fixture.
169 pub sequences: EventSequenceSource,
170 /// Correlation identifier used by the fixture.
171 pub correlation_id: CorrelationId,
172 /// Configuration version attached to events.
173 pub config_version: u64,
174}
175
176impl EventFixture {
177 /// Creates an event fixture.
178 ///
179 /// # Arguments
180 ///
181 /// - `paused_time`: Time source for deterministic events.
182 /// - `config_version`: Configuration version attached to events.
183 ///
184 /// # Returns
185 ///
186 /// Returns an [`EventFixture`].
187 pub fn new(paused_time: PausedTime, config_version: u64) -> Self {
188 Self {
189 paused_time,
190 sequences: EventSequenceSource::new(),
191 correlation_id: CorrelationId::from_uuid(Uuid::nil()),
192 config_version,
193 }
194 }
195
196 /// Builds a deterministic event for a child.
197 ///
198 /// # Arguments
199 ///
200 /// - `child_id`: Child identifier attached to the event.
201 /// - `child_name`: Child name attached to the event.
202 /// - `what`: Event payload.
203 ///
204 /// # Returns
205 ///
206 /// Returns a [`SupervisorEvent`].
207 pub fn child_event(
208 &self,
209 child_id: ChildId,
210 child_name: impl Into<String>,
211 what: What,
212 ) -> SupervisorEvent {
213 let path = SupervisorPath::root().join(child_id.to_string());
214 let location = Where::new(path.clone()).with_child(child_id, child_name);
215 SupervisorEvent::new(
216 When::new(
217 self.paused_time
218 .event_time(Generation::initial(), Attempt::first()),
219 ),
220 location,
221 what,
222 self.sequences.next(),
223 self.correlation_id,
224 self.config_version,
225 )
226 }
227
228 /// Builds an event sequence value.
229 ///
230 /// # Arguments
231 ///
232 /// - `value`: Sequence value.
233 ///
234 /// # Returns
235 ///
236 /// Returns an [`EventSequence`].
237 pub fn sequence(value: u64) -> EventSequence {
238 EventSequence::new(value)
239 }
240}