Skip to content

Commit 71c4778

Browse files
committed
test: isolate state-dir probes from user state
1 parent deac138 commit 71c4778

1 file changed

Lines changed: 56 additions & 14 deletions

File tree

tests/test_issue4449_state_dir_contract.py

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,35 @@
1212

1313
from __future__ import annotations
1414

15+
import json
1516
import os
1617
import subprocess
1718
import sys
1819
from pathlib import Path
1920

2021
REPO_ROOT = Path(__file__).resolve().parents[1]
2122

22-
_PROBE = (
23-
"import api.config as c; "
24-
"print(c.STATE_DIR)"
25-
)
23+
_PROBE = "import api.config as c; print(c.STATE_DIR)"
2624

2725

28-
def _state_dir_for_env(**env_overrides) -> Path:
26+
def _state_dir_for_env(platform_home: Path, **env_overrides) -> Path:
2927
"""Import api.config in a fresh subprocess under the given env and return
3028
the resolved STATE_DIR it computes. None-valued overrides unset the var."""
3129
env = dict(os.environ)
32-
# Start from a clean slate for the two vars under test so the parent
33-
# process's pytest values don't bleed in.
30+
# Keep every probe inside fixture-owned platform paths. Inheriting the real
31+
# user home lets an import-only probe reconcile pytest workspace defaults
32+
# into the user's settings.json before it prints STATE_DIR.
33+
env["HOME"] = str(platform_home)
34+
env["USERPROFILE"] = str(platform_home)
35+
env["LOCALAPPDATA"] = str(platform_home / "AppData" / "Local")
36+
# Start from a clean slate for the vars that can redirect state or trigger
37+
# startup settings reconciliation in the child process.
3438
env.pop("HERMES_HOME", None)
39+
env.pop("HERMES_BASE_HOME", None)
3540
env.pop("HERMES_WEBUI_STATE_DIR", None)
41+
env.pop("HERMES_WEBUI_TEST_STATE_DIR", None)
42+
env.pop("HERMES_WEBUI_DEFAULT_WORKSPACE", None)
43+
env.pop("HERMES_CONFIG_PATH", None)
3644
for key, value in env_overrides.items():
3745
if value is None:
3846
env.pop(key, None)
@@ -50,33 +58,66 @@ def _state_dir_for_env(**env_overrides) -> Path:
5058
return Path(out.stdout.strip()).resolve()
5159

5260

53-
def _platform_default_state_dir() -> Path:
61+
def _platform_default_state_dir(platform_home: Path) -> Path:
5462
"""What STATE_DIR resolves to with HERMES_HOME + STATE_DIR both unset."""
55-
return _state_dir_for_env()
63+
return _state_dir_for_env(platform_home)
64+
65+
66+
def test_state_dir_probe_does_not_mutate_platform_default_settings(
67+
tmp_path, monkeypatch
68+
):
69+
"""The subprocess probe must not reconcile pytest defaults into user state."""
70+
platform_home = tmp_path / "platform-home"
71+
if os.name == "nt":
72+
settings_file = (
73+
platform_home / "AppData" / "Local" / "hermes" / "webui" / "settings.json"
74+
)
75+
else:
76+
settings_file = platform_home / ".hermes" / "webui" / "settings.json"
77+
settings_file.parent.mkdir(parents=True)
78+
persisted_workspace = tmp_path / "persisted-workspace"
79+
persisted_workspace.mkdir()
80+
original = (
81+
json.dumps({"default_workspace": str(persisted_workspace)}) + "\n"
82+
).encode()
83+
settings_file.write_bytes(original)
84+
85+
monkeypatch.setenv("HOME", str(platform_home))
86+
monkeypatch.setenv("USERPROFILE", str(platform_home))
87+
monkeypatch.setenv(
88+
"HERMES_WEBUI_DEFAULT_WORKSPACE", str(tmp_path / "pytest-workspace")
89+
)
90+
91+
state_dir = _platform_default_state_dir(platform_home)
92+
93+
assert settings_file.read_bytes() == original
94+
assert state_dir == settings_file.parent.resolve()
5695

5796

5897
def test_config_state_dir_defaults_to_hermes_home_webui(tmp_path):
5998
hermes_home = tmp_path / ".hermes" / "profiles" / "isolated"
6099
hermes_home.mkdir(parents=True)
61100

62-
state_dir = _state_dir_for_env(HERMES_HOME=hermes_home)
101+
state_dir = _state_dir_for_env(tmp_path / "platform-home", HERMES_HOME=hermes_home)
63102
assert state_dir == (hermes_home / "webui").resolve()
64103

65104

66-
def test_config_state_dir_unchanged_for_normal_install_hermes_home_unset():
105+
def test_config_state_dir_unchanged_for_normal_install_hermes_home_unset(tmp_path):
67106
"""Backward-compat: with HERMES_HOME unset, STATE_DIR stays at the platform
68107
default `<~/.hermes>/webui` — a normal install's state must NOT relocate
69108
(the #4449/#4454 state-dir move only affects an explicitly-set HERMES_HOME).
70109
71110
Cross-check: the unset-HERMES_HOME result must NOT equal the result of
72111
pointing HERMES_HOME at an arbitrary other base — i.e. the default is
73112
genuinely the platform home, not whatever the test environment injected."""
74-
default = _platform_default_state_dir()
113+
platform_home = tmp_path / "platform-home"
114+
default = _platform_default_state_dir(platform_home)
75115
assert default.name == "webui"
76116
# Pointing HERMES_HOME elsewhere produces a DIFFERENT dir, proving the unset
77117
# case resolves to the platform default rather than echoing an injected base.
78-
elsewhere = _state_dir_for_env(HERMES_HOME="/tmp/hermes-4449-elsewhere-base")
79-
assert elsewhere == Path("/tmp/hermes-4449-elsewhere-base/webui").resolve()
118+
elsewhere_base = tmp_path / "elsewhere-base"
119+
elsewhere = _state_dir_for_env(platform_home, HERMES_HOME=elsewhere_base)
120+
assert elsewhere == (elsewhere_base / "webui").resolve()
80121
assert default != elsewhere
81122

82123

@@ -88,6 +129,7 @@ def test_config_state_dir_explicit_override_takes_precedence(tmp_path):
88129
explicit = tmp_path / "custom-state"
89130

90131
state_dir = _state_dir_for_env(
132+
tmp_path / "platform-home",
91133
HERMES_HOME=hermes_home,
92134
HERMES_WEBUI_STATE_DIR=explicit,
93135
)

0 commit comments

Comments
 (0)