Skip to main content

trusty_console/detect/
memory.rs

1//! `ServiceConnector` implementation for `trusty-memory`.
2//!
3//! Why: trusty-memory writes `http_addr` under its data root. The legacy
4//! dotfile path `~/.trusty-memory/http_addr` is always written regardless of
5//! platform and is the most reliable single location available without
6//! importing `trusty-memory`'s own path-resolution logic.
7//! What: `MemoryConnector` implements `detect()` using
8//! `~/.trusty-memory/http_addr`.
9//! Test: `test_memory_connector_*` in the module below. Run with
10//! `cargo test -p trusty-console`.
11
12use std::path::PathBuf;
13
14use crate::connector::{ServiceConnector, ServiceInfo};
15
16use super::helpers::detect_service;
17
18/// ServiceConnector for `trusty-memory`.
19///
20/// Why: trusty-memory writes `http_addr` under its data root. The legacy
21/// dotfile path is `~/.trusty-memory/http_addr`, which is the most reliable
22/// single location available without importing `trusty-memory`'s own
23/// path-resolution logic.
24/// What: Implements `detect()` using `~/.trusty-memory/http_addr`.
25/// Test: `test_memory_connector_with_stale_addr_file`,
26/// `test_memory_connector_no_addr_file` below.
27pub struct MemoryConnector {
28    home_dir: Option<PathBuf>,
29}
30
31impl MemoryConnector {
32    /// Create a new `MemoryConnector`.
33    ///
34    /// Why: Matches the SearchConnector pattern for consistency.
35    /// What: No-op constructor.
36    /// Test: Created in `all_connectors()`.
37    pub fn new() -> Self {
38        Self { home_dir: None }
39    }
40
41    /// Create a connector that uses `home_dir` instead of the real home.
42    ///
43    /// Why: Unit tests must not read or write the real user's `~/.trusty-*`
44    /// directories. Injecting a temp dir keeps tests hermetic.
45    /// What: Stores `home_dir` for use in `addr_file_path()`.
46    /// Test: `test_memory_connector_with_stale_addr_file`,
47    /// `test_memory_connector_no_addr_file`.
48    #[cfg(test)]
49    pub fn with_home(home_dir: PathBuf) -> Self {
50        Self {
51            home_dir: Some(home_dir),
52        }
53    }
54
55    fn addr_file_path(&self) -> PathBuf {
56        let home = self
57            .home_dir
58            .clone()
59            .or_else(dirs::home_dir)
60            .unwrap_or_else(|| PathBuf::from("/tmp"));
61        home.join(".trusty-memory").join("http_addr")
62    }
63}
64
65impl Default for MemoryConnector {
66    fn default() -> Self {
67        Self::new()
68    }
69}
70
71impl ServiceConnector for MemoryConnector {
72    fn id(&self) -> &'static str {
73        "trusty-memory"
74    }
75
76    fn display_name(&self) -> &'static str {
77        "Trusty Memory"
78    }
79
80    /// Detect trusty-memory status.
81    ///
82    /// Why: trusty-memory writes `~/.trusty-memory/http_addr` (the legacy
83    /// dotfile path) as well as the OS data-dir path; the dotfile is always
84    /// written regardless of platform.
85    /// What: Three-step sequence: binary check → addr file + TCP probe → status.
86    /// Test: `test_memory_connector_with_stale_addr_file`,
87    /// `test_memory_connector_no_addr_file`.
88    fn detect(&self) -> ServiceInfo {
89        detect_service(
90            self.id(),
91            self.display_name(),
92            "trusty-memory",
93            self.addr_file_path(),
94        )
95    }
96}
97
98// ─── tests ────────────────────────────────────────────────────────────────────
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::connector::ServiceStatus;
104    use std::fs;
105    use tempfile::TempDir;
106
107    fn make_home_with_addr(rel_path: &str, content: &str) -> TempDir {
108        let tmp = TempDir::new().expect("tempdir");
109        let path = tmp.path().join(rel_path);
110        fs::create_dir_all(path.parent().expect("parent")).expect("mkdir");
111        fs::write(&path, content).expect("write addr file");
112        tmp
113    }
114
115    /// Why: stale addr file must yield Available (not Running) because TCP fails.
116    /// What: creates `.trusty-memory/http_addr = 127.0.0.1:14997`.
117    /// Test: this test itself.
118    #[test]
119    fn test_memory_connector_with_stale_addr_file() {
120        let tmp = make_home_with_addr(".trusty-memory/http_addr", "127.0.0.1:14997");
121        let connector = MemoryConnector::with_home(tmp.path().to_path_buf());
122        let info = connector.detect();
123        assert!(
124            info.status == ServiceStatus::Absent || info.status == ServiceStatus::Available,
125            "expected Absent or Available, got {:?}",
126            info.status
127        );
128        assert_eq!(info.id, "trusty-memory");
129    }
130
131    /// Why: absent addr file with binary on PATH yields Available; without binary
132    /// yields Absent.
133    /// What: empty temp HOME.
134    /// Test: this test itself.
135    #[test]
136    fn test_memory_connector_no_addr_file() {
137        let tmp = TempDir::new().expect("tempdir");
138        let connector = MemoryConnector::with_home(tmp.path().to_path_buf());
139        let info = connector.detect();
140        assert!(
141            info.status == ServiceStatus::Absent || info.status == ServiceStatus::Available,
142            "expected Absent or Available without addr file, got {:?}",
143            info.status
144        );
145    }
146}