Skip to main content

opencode_ctl/testing/
mod.rs

1//! Test support shared with the front crates.
2
3use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5use std::sync::Mutex;
6
7use crate::liveness::ProcessProbe;
8
9pub mod fake;
10pub mod mock;
11
12pub struct TempHome {
13    path: PathBuf,
14}
15
16impl TempHome {
17    pub fn path(&self) -> &Path {
18        &self.path
19    }
20}
21
22impl Drop for TempHome {
23    fn drop(&mut self) {
24        let _ = std::fs::remove_dir_all(&self.path);
25    }
26}
27
28pub fn temp_home() -> TempHome {
29    let path = std::env::temp_dir().join(format!("opencode-ctl-test-{}", uuid::Uuid::new_v4()));
30    std::fs::create_dir_all(&path).expect("create temp home");
31    TempHome { path }
32}
33
34pub fn env_map(pairs: &[(&str, &str)]) -> impl Fn(&str) -> Option<String> {
35    let map: HashMap<String, String> = pairs
36        .iter()
37        .map(|(k, v)| (k.to_string(), v.to_string()))
38        .collect();
39    move |k| map.get(k).cloned()
40}
41
42#[cfg(unix)]
43pub fn exit_status(code: i32) -> std::process::ExitStatus {
44    use std::os::unix::process::ExitStatusExt;
45    std::process::ExitStatus::from_raw(code << 8)
46}
47
48#[cfg(windows)]
49pub fn exit_status(code: i32) -> std::process::ExitStatus {
50    use std::os::windows::process::ExitStatusExt;
51    std::process::ExitStatus::from_raw(code as u32)
52}
53
54/// In-memory `ProcessProbe`. Liveness can change between reads through a
55/// shared reference.
56pub struct FakeProbe {
57    pub alive: Mutex<HashMap<u32, String>>,
58    pub boot: String,
59    pub parents: Mutex<HashMap<u32, u32>>,
60}
61
62impl FakeProbe {
63    pub fn new(boot: &str) -> Self {
64        Self {
65            alive: Mutex::new(HashMap::new()),
66            boot: boot.to_string(),
67            parents: Mutex::new(HashMap::new()),
68        }
69    }
70
71    pub fn set_alive(&self, pid: u32, starttime: &str) {
72        self.alive
73            .lock()
74            .unwrap()
75            .insert(pid, starttime.to_string());
76    }
77
78    pub fn set_dead(&self, pid: u32) {
79        self.alive.lock().unwrap().remove(&pid);
80    }
81}
82
83impl ProcessProbe for FakeProbe {
84    fn is_alive(&self, pid: u32) -> bool {
85        self.alive.lock().unwrap().contains_key(&pid)
86    }
87
88    fn starttime(&self, pid: u32) -> Option<String> {
89        self.alive.lock().unwrap().get(&pid).cloned()
90    }
91
92    fn boot_id(&self) -> String {
93        self.boot.clone()
94    }
95
96    fn parent_pid(&self, pid: u32) -> Option<u32> {
97        self.parents.lock().unwrap().get(&pid).copied()
98    }
99}