Skip to content

Commit c7eca03

Browse files
committed
add session clean up and tests
1 parent 584a9a4 commit c7eca03

2 files changed

Lines changed: 109 additions & 0 deletions

File tree

src/sessions.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ fn check_session_lock() {
8686
}
8787

8888
pub fn find_session_run_ancestor() -> Option<sysinfo::Pid> {
89+
static CACHED: std::sync::OnceLock<Option<sysinfo::Pid>> = std::sync::OnceLock::new();
90+
*CACHED.get_or_init(find_session_run_ancestor_inner)
91+
}
92+
93+
fn find_session_run_ancestor_inner() -> Option<sysinfo::Pid> {
8994
use sysinfo::{ProcessRefreshKind, RefreshKind, System, UpdateKind};
9095

9196
let sys = System::new_with_specifics(
@@ -174,6 +179,7 @@ pub fn update(workspace_id: &str, session_id: &str, name: Option<&str>, markdown
174179
}
175180

176181
pub fn run(session_id: Option<&str>, workspace_id: &str, name: Option<&str>, cmd: &[String]) {
182+
check_session_lock();
177183
let sid = match session_id {
178184
Some(id) => {
179185
// Verify the session exists
@@ -212,6 +218,23 @@ pub fn run(session_id: Option<&str>, workspace_id: &str, name: Option<&str>, cmd
212218
}
213219
}
214220

221+
#[cfg(test)]
222+
mod tests {
223+
use super::*;
224+
225+
#[test]
226+
fn find_session_run_ancestor_returns_none_in_test() {
227+
// No `hotdata sessions run` ancestor exists in the test runner
228+
assert!(find_session_run_ancestor_inner().is_none());
229+
}
230+
231+
#[test]
232+
fn find_session_run_ancestor_cached_matches_inner() {
233+
// The cached version should agree with the inner function
234+
assert_eq!(find_session_run_ancestor(), find_session_run_ancestor_inner());
235+
}
236+
}
237+
215238
pub fn set(session_id: Option<&str>, workspace_id: &str) {
216239
check_session_lock();
217240
match session_id {

tests/session_env.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::process::Command;
2+
3+
fn hotdata() -> Command {
4+
Command::new(env!("CARGO_BIN_EXE_hotdata"))
5+
}
6+
7+
// --- session lock tests ---
8+
9+
#[test]
10+
fn sessions_run_blocked_when_hotdata_session_set() {
11+
let output = hotdata()
12+
.args(["sessions", "run", "echo", "hi"])
13+
.env("HOTDATA_SESSION", "existing-session")
14+
.env("HOTDATA_WORKSPACE", "ws-1")
15+
.output()
16+
.unwrap();
17+
18+
assert!(!output.status.success());
19+
let stderr = String::from_utf8_lossy(&output.stderr);
20+
assert!(stderr.contains("session is locked"), "stderr: {stderr}");
21+
}
22+
23+
#[test]
24+
fn sessions_new_blocked_when_hotdata_session_set() {
25+
let output = hotdata()
26+
.args(["sessions", "new"])
27+
.env("HOTDATA_SESSION", "existing-session")
28+
.env("HOTDATA_WORKSPACE", "ws-1")
29+
.output()
30+
.unwrap();
31+
32+
assert!(!output.status.success());
33+
let stderr = String::from_utf8_lossy(&output.stderr);
34+
assert!(stderr.contains("session is locked"), "stderr: {stderr}");
35+
}
36+
37+
#[test]
38+
fn sessions_set_blocked_when_hotdata_session_set() {
39+
let output = hotdata()
40+
.args(["sessions", "set", "some-id"])
41+
.env("HOTDATA_SESSION", "existing-session")
42+
.env("HOTDATA_WORKSPACE", "ws-1")
43+
.output()
44+
.unwrap();
45+
46+
assert!(!output.status.success());
47+
let stderr = String::from_utf8_lossy(&output.stderr);
48+
assert!(stderr.contains("session is locked"), "stderr: {stderr}");
49+
}
50+
51+
// --- workspace env lock tests ---
52+
53+
#[test]
54+
fn workspace_env_blocks_conflicting_flag() {
55+
let output = hotdata()
56+
.args(["sessions", "-w", "other-ws", "list"])
57+
.env("HOTDATA_WORKSPACE", "locked-ws")
58+
.env_remove("HOTDATA_SESSION")
59+
.output()
60+
.unwrap();
61+
62+
assert!(!output.status.success());
63+
let stderr = String::from_utf8_lossy(&output.stderr);
64+
assert!(
65+
stderr.contains("locked by HOTDATA_WORKSPACE"),
66+
"stderr: {stderr}"
67+
);
68+
}
69+
70+
#[test]
71+
fn workspace_env_allows_matching_flag() {
72+
// When the flag matches the env var, no workspace conflict error.
73+
// Will fail later on auth, but should NOT fail on workspace lock.
74+
let output = hotdata()
75+
.args(["sessions", "-w", "ws-1", "list"])
76+
.env("HOTDATA_WORKSPACE", "ws-1")
77+
.env_remove("HOTDATA_SESSION")
78+
.output()
79+
.unwrap();
80+
81+
let stderr = String::from_utf8_lossy(&output.stderr);
82+
assert!(
83+
!stderr.contains("locked by HOTDATA_WORKSPACE"),
84+
"unexpected workspace lock error: {stderr}"
85+
);
86+
}

0 commit comments

Comments
 (0)