Skip to content

Commit cac3994

Browse files
test(ci): polish Windows CI tests and matrix job names
1 parent 9f3b3c6 commit cac3994

3 files changed

Lines changed: 42 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
PY
4545
4646
pytest:
47+
name: pytest (${{ matrix.os }})
4748
runs-on: ${{ matrix.os }}
4849
strategy:
4950
fail-fast: false
@@ -97,7 +98,7 @@ jobs:
9798
run: mypy tests --config-file mypy-tests.ini --follow-imports skip
9899

99100
integration-tests:
100-
name: API integration tests + coverage
101+
name: API integration tests + coverage (${{ matrix.os }})
101102
runs-on: ${{ matrix.os }}
102103
strategy:
103104
fail-fast: false
@@ -132,7 +133,7 @@ jobs:
132133
path: coverage.xml
133134

134135
js-tests:
135-
name: Frontend unit tests (vitest)
136+
name: Frontend unit tests (vitest) (${{ matrix.os }})
136137
runs-on: ${{ matrix.os }}
137138
strategy:
138139
fail-fast: false

tests/test_export_state_store.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
from __future__ import annotations
44

55
import json
6+
import subprocess
67
import sys
8+
import time
79
from pathlib import Path
810

911
import pytest
1012

13+
REPO_ROOT = Path(__file__).resolve().parent.parent
14+
1115
from utils.export_state_store import (
1216
atomic_write_export_state,
1317
export_state_lock,
@@ -96,14 +100,41 @@ def test_export_state_lock_real_msvcrt_roundtrip(tmp_path: Path) -> None:
96100
state_file = tmp_path / "export_state.json"
97101
state_file.write_text("{}", encoding="utf-8")
98102
payload = {
99-
"sessions": {},
100-
"lastExportTime": "2026-01-01T00:00:00",
101-
"exportedCount": 0,
103+
"sessions": {"sess-msvcrt-roundtrip": 1740000123.5},
104+
"lastExportTime": "2026-06-04T18:30:00Z",
105+
"exportedCount": 42,
102106
}
103107

104108
with export_state_lock(str(state_file)):
105109
atomic_write_export_state(payload, str(state_file))
106110

107111
loaded = load_export_state_from_disk(str(state_file))
108-
assert loaded.get("exportedCount") == 0
109-
assert loaded.get("sessions") == {}
112+
assert loaded.get("exportedCount") == 42
113+
assert loaded.get("sessions") == {"sess-msvcrt-roundtrip": 1740000123.5}
114+
assert loaded.get("lastExportTime") == "2026-06-04T18:30:00Z"
115+
116+
117+
@pytest.mark.skipif(sys.platform != "win32", reason="requires Windows msvcrt")
118+
def test_export_state_lock_blocks_second_process(tmp_path: Path) -> None:
119+
"""While the parent holds ``msvcrt`` lock, a child process cannot acquire it."""
120+
state_file = tmp_path / "export_state.json"
121+
state_file.write_text("{}", encoding="utf-8")
122+
marker = tmp_path / "child_acquired.lock"
123+
child = (
124+
"import sys\n"
125+
"from pathlib import Path\n"
126+
f"sys.path.insert(0, {str(REPO_ROOT)!r})\n"
127+
"from utils.export_state_store import export_state_lock\n"
128+
"path, marker = sys.argv[1], sys.argv[2]\n"
129+
"with export_state_lock(path):\n"
130+
" Path(marker).write_text('ok', encoding='utf-8')\n"
131+
)
132+
with export_state_lock(str(state_file)):
133+
proc = subprocess.Popen(
134+
[sys.executable, "-c", child, str(state_file), str(marker)],
135+
cwd=str(REPO_ROOT),
136+
)
137+
time.sleep(0.5)
138+
assert not marker.is_file(), "child acquired lock while parent still holds it"
139+
assert proc.wait(timeout=10) == 0
140+
assert marker.read_text(encoding="utf-8") == "ok"

tests/test_session_path.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
def test_get_claude_projects_dir_uses_userprofile_on_windows(
1515
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
1616
) -> None:
17-
profile = tmp_path / "Users" / "chen"
18-
profile.mkdir(parents=True)
17+
profile = tmp_path / "Users" / "testuser"
1918
monkeypatch.setattr(session_path.platform, "system", lambda: "Windows")
2019
monkeypatch.setenv("USERPROFILE", str(profile))
21-
monkeypatch.delenv("HOME", raising=False)
2220

2321
got = session_path.get_claude_projects_dir()
2422
assert got == os.path.join(str(profile), ".claude", "projects")
@@ -29,9 +27,8 @@ def test_get_claude_projects_dir_on_windows_runner(
2927
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
3028
) -> None:
3129
profile = tmp_path / "profile"
32-
profile.mkdir()
3330
monkeypatch.setenv("USERPROFILE", str(profile))
3431

3532
got = session_path.get_claude_projects_dir()
36-
assert got.startswith(str(profile))
37-
assert got.endswith(os.path.join(".claude", "projects"))
33+
expected = os.path.join(str(profile), ".claude", "projects")
34+
assert got == expected

0 commit comments

Comments
 (0)