1use std::sync::Arc;
4use std::sync::atomic::{AtomicU32, Ordering};
5use std::time::{Duration, Instant};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum MockProcessError {
9 LaunchFailed,
10 Timeout,
11}
12
13#[derive(Debug, Clone)]
14enum MockBehavior {
15 FailThenSucceed { failures_before_success: u32 },
16 NeverResponds,
17}
18
19#[derive(Debug, Clone)]
20pub struct MockModuleProcess {
21 behavior: MockBehavior,
22 attempts: Arc<AtomicU32>,
23}
24
25impl MockModuleProcess {
26 pub fn fail_then_succeed(failures_before_success: u32) -> Self {
27 Self {
28 behavior: MockBehavior::FailThenSucceed {
29 failures_before_success,
30 },
31 attempts: Arc::new(AtomicU32::new(0)),
32 }
33 }
34
35 pub fn never_responds() -> Self {
36 Self {
37 behavior: MockBehavior::NeverResponds,
38 attempts: Arc::new(AtomicU32::new(0)),
39 }
40 }
41
42 pub fn invoke_json_line_with_timeout(
43 &self,
44 timeout: Duration,
45 success_line: &str,
46 ) -> Result<String, MockProcessError> {
47 match self.behavior {
48 MockBehavior::FailThenSucceed {
49 failures_before_success,
50 } => {
51 let attempt = self.attempts.fetch_add(1, Ordering::SeqCst);
52 if attempt < failures_before_success {
53 return Err(MockProcessError::LaunchFailed);
54 }
55 Ok(success_line.to_string())
56 }
57 MockBehavior::NeverResponds => {
58 let started = Instant::now();
59 while started.elapsed() < timeout {
60 std::thread::yield_now();
61 }
62 Err(MockProcessError::Timeout)
63 }
64 }
65 }
66
67 pub fn attempts(&self) -> u32 {
68 self.attempts.load(Ordering::SeqCst)
69 }
70}