Skip to content

Commit a744419

Browse files
committed
Fix parallel env-sensitive tests
1 parent f3c0ca2 commit a744419

3 files changed

Lines changed: 73 additions & 54 deletions

File tree

src/app/refresh.rs

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -284,16 +284,11 @@ mod tests {
284284

285285
#[test]
286286
fn refresh_tasks_reconcile_claude_host_active_account_before_fetching() {
287-
let _guard = test_support::env_lock();
287+
let mut env = test_support::test_env();
288288
let state_root = temp_state_root("claude-active");
289-
let prev_home = std::env::var_os("HOME");
290-
let prev_state = std::env::var_os("XDG_STATE_HOME");
291-
let prev_flatpak = std::env::var_os("FLATPAK_ID");
292-
unsafe {
293-
std::env::set_var("HOME", &state_root);
294-
std::env::set_var("XDG_STATE_HOME", &state_root);
295-
std::env::remove_var("FLATPAK_ID");
296-
}
289+
env.set("HOME", state_root.as_os_str());
290+
env.set("XDG_STATE_HOME", state_root.as_os_str());
291+
env.remove("FLATPAK_ID");
297292
let storage = ProviderAccountStorage::new(paths().claude_accounts_dir.clone());
298293
let account_a = stored_claude_account(&storage, "a@example.com", "acct-a");
299294
let account_b = stored_claude_account(&storage, "b@example.com", "acct-b");
@@ -312,23 +307,6 @@ mod tests {
312307

313308
let _tasks = refresh_provider_tasks(&config, &mut state);
314309

315-
unsafe {
316-
if let Some(value) = prev_home {
317-
std::env::set_var("HOME", value);
318-
} else {
319-
std::env::remove_var("HOME");
320-
}
321-
if let Some(value) = prev_state {
322-
std::env::set_var("XDG_STATE_HOME", value);
323-
} else {
324-
std::env::remove_var("XDG_STATE_HOME");
325-
}
326-
if let Some(value) = prev_flatpak {
327-
std::env::set_var("FLATPAK_ID", value);
328-
} else {
329-
std::env::remove_var("FLATPAK_ID");
330-
}
331-
}
332310
assert_eq!(
333311
state
334312
.provider(ProviderId::Claude)

src/config.rs

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -455,23 +455,9 @@ mod tests {
455455

456456
#[test]
457457
fn flatpak_paths_use_dot_var_layout() {
458-
use std::sync::Mutex;
459-
460-
static ENV_LOCK: Mutex<()> = Mutex::new(());
461-
462-
let _guard = ENV_LOCK.lock().expect("flatpak path test env lock");
463-
464-
let prev_id = std::env::var_os("FLATPAK_ID");
465-
466-
let p = unsafe {
467-
std::env::set_var("FLATPAK_ID", "com.example.YapCapTest");
468-
let p = paths();
469-
std::env::remove_var("FLATPAK_ID");
470-
if let Some(ref v) = prev_id {
471-
std::env::set_var("FLATPAK_ID", v);
472-
}
473-
p
474-
};
458+
let mut env = crate::test_support::test_env();
459+
env.set("FLATPAK_ID", "com.example.YapCapTest");
460+
let p = paths();
475461

476462
use std::path::Path;
477463
assert!(
@@ -497,16 +483,8 @@ mod tests {
497483

498484
#[test]
499485
fn host_user_home_dir_matches_dirs_home_without_flatpak() {
500-
let _guard = crate::test_support::env_lock();
501-
let prev = std::env::var_os("FLATPAK_ID");
502-
unsafe {
503-
std::env::remove_var("FLATPAK_ID");
504-
}
486+
let mut env = crate::test_support::test_env();
487+
env.remove("FLATPAK_ID");
505488
assert_eq!(host_user_home_dir(), dirs::home_dir());
506-
if let Some(v) = prev {
507-
unsafe {
508-
std::env::set_var("FLATPAK_ID", v);
509-
}
510-
}
511489
}
512490
}

src/test_support.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,71 @@
11
// SPDX-License-Identifier: MPL-2.0
22

3+
use std::ffi::{OsStr, OsString};
34
use std::sync::{Mutex, MutexGuard, OnceLock};
45

56
pub fn env_lock() -> MutexGuard<'static, ()> {
7+
lock_env()
8+
}
9+
10+
pub struct TestEnv {
11+
_guard: MutexGuard<'static, ()>,
12+
saved: Vec<(OsString, Option<OsString>)>,
13+
}
14+
15+
pub fn test_env() -> TestEnv {
16+
TestEnv {
17+
_guard: lock_env(),
18+
saved: Vec::new(),
19+
}
20+
}
21+
22+
impl TestEnv {
23+
pub fn set<K, V>(&mut self, key: K, value: V)
24+
where
25+
K: AsRef<OsStr>,
26+
V: AsRef<OsStr>,
27+
{
28+
self.save_once(key.as_ref());
29+
unsafe {
30+
std::env::set_var(key, value);
31+
}
32+
}
33+
34+
pub fn remove<K>(&mut self, key: K)
35+
where
36+
K: AsRef<OsStr>,
37+
{
38+
self.save_once(key.as_ref());
39+
unsafe {
40+
std::env::remove_var(key);
41+
}
42+
}
43+
44+
fn save_once(&mut self, key: &OsStr) {
45+
if self.saved.iter().any(|(saved, _)| saved == key) {
46+
return;
47+
}
48+
self.saved.push((key.to_os_string(), std::env::var_os(key)));
49+
}
50+
}
51+
52+
impl Drop for TestEnv {
53+
fn drop(&mut self) {
54+
for (key, value) in self.saved.iter().rev() {
55+
unsafe {
56+
if let Some(value) = value {
57+
std::env::set_var(key, value);
58+
} else {
59+
std::env::remove_var(key);
60+
}
61+
}
62+
}
63+
}
64+
}
65+
66+
fn lock_env() -> MutexGuard<'static, ()> {
667
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
7-
LOCK.get_or_init(|| Mutex::new(())).lock().unwrap()
68+
LOCK.get_or_init(|| Mutex::new(()))
69+
.lock()
70+
.unwrap_or_else(|poisoned| poisoned.into_inner())
871
}

0 commit comments

Comments
 (0)