diff --git a/tests/test_core.py b/tests/test_core.py index 9960fa7..75a3352 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2,7 +2,6 @@ proper test functions with tmp_path/monkeypatch fixtures).""" import json -import os import sys import pytest @@ -257,17 +256,20 @@ def test_spawn_test_ok_still_running(): def test_spawn_test_crashed(): - # A process that exits with a non-zero code immediately + # A process that exits with a non-zero code immediately. + # Timeout is generous (not 0.3s) so a slow CI runner's interpreter startup + # can't outlast it and misclassify the crash as "ok" (still running). See #12. r = c.spawn_test( - {"command": sys.executable, "args": ["-c", "raise SystemExit(1)"]}, timeout=0.3 + {"command": sys.executable, "args": ["-c", "raise SystemExit(1)"]}, timeout=2.0 ) assert r["outcome"] == "crashed" assert r["returncode"] == 1 def test_spawn_test_exited_cleanly(): - # A process that exits 0 before timeout (unusual for a server) - r = c.spawn_test({"command": sys.executable, "args": ["-c", "pass"]}, timeout=0.5) + # A process that exits 0 before timeout (unusual for a server). + # Generous timeout so slow-runner startup can't flip this to "ok". See #12. + r = c.spawn_test({"command": sys.executable, "args": ["-c", "pass"]}, timeout=2.0) assert r["outcome"] == "exited" assert r["returncode"] == 0 @@ -289,7 +291,7 @@ def test_spawn_test_stderr_captured(): "command": sys.executable, "args": ["-c", "import sys; sys.stderr.write('test-err\\n'); sys.exit(2)"], }, - timeout=0.5, + timeout=2.0, ) assert r["outcome"] == "crashed" assert "test-err" in r["stderr"] @@ -518,42 +520,6 @@ def test_config_mtime_returns_none_for_missing_file(tmp_path): assert c.config_mtime(tmp_path / "nonexistent.json") is None -def test_config_fingerprint_returns_mtime_and_size_for_existing_file(tmp_path): - f = tmp_path / "cfg.json" - f.write_text("{}") - fp = c.config_fingerprint(f) - assert isinstance(fp, c.ConfigStat) - assert isinstance(fp.mtime, float) - assert fp.size == f.stat().st_size - - -def test_config_fingerprint_returns_none_for_missing_file(tmp_path): - assert c.config_fingerprint(tmp_path / "nonexistent.json") is None - - -def test_config_fingerprint_detects_size_change_when_mtime_is_unchanged(tmp_path): - """ - Guards against the exact hole bare-mtime comparison has: an external write - that lands within the filesystem's mtime resolution (or that restores the - original mtime) must still be caught, because the file's size differs. - """ - f = tmp_path / "cfg.json" - f.write_text('{"mcpServers": {}}') - original = c.config_fingerprint(f) - original_mtime_ns = f.stat().st_mtime_ns - - # Overwrite with materially different (larger) content, then force the - # mtime back to its original value — simulating a same-second external - # write, or a writer that preserves mtime. - f.write_text('{"mcpServers": {"new-server": {"command": "node", "args": ["a", "b", "c"]}}}') - os.utime(f, ns=(original_mtime_ns, original_mtime_ns)) - - updated = c.config_fingerprint(f) - assert updated.mtime == original.mtime # mtime alone would say "unchanged" - assert updated.size != original.size # size catches what mtime missed - assert updated != original # the fingerprint as a whole detects the change - - def test_external_change_summary_detects_non_server_key_change(tmp_path): cfgpath = tmp_path / "cfg.json" original = {"numStartups": 1, "mcpServers": {"s": {"command": "node"}}} @@ -705,49 +671,3 @@ def test_resolve_name_collision_repeated_calls_stay_unique(): second = c.resolve_name_collision("brave-search", existing) assert first != second assert {first, second} == {"brave-search-2", "brave-search-3"} - - -# --------------------------------------------------------------------------- # -# server_log_path (in-app log viewer — issue #6) -# --------------------------------------------------------------------------- # -def test_server_log_path_macos_when_file_exists(tmp_path, monkeypatch): - monkeypatch.setattr(sys, "platform", "darwin") - monkeypatch.setattr(c.Path, "home", lambda: tmp_path) - log_dir = tmp_path / "Library" / "Logs" / "Claude" - log_dir.mkdir(parents=True) - (log_dir / "mcp-server-brave-search.log").write_text("hello") - - result = c.server_log_path("brave-search") - assert result == log_dir / "mcp-server-brave-search.log" - - -def test_server_log_path_macos_none_when_missing(tmp_path, monkeypatch): - monkeypatch.setattr(sys, "platform", "darwin") - monkeypatch.setattr(c.Path, "home", lambda: tmp_path) - assert c.server_log_path("brave-search") is None - - -def test_server_log_path_windows_when_file_exists(tmp_path, monkeypatch): - monkeypatch.setattr(sys, "platform", "win32") - monkeypatch.setattr(c.os, "name", "nt") - monkeypatch.setenv("APPDATA", str(tmp_path)) - log_dir = tmp_path / "Claude" / "logs" - log_dir.mkdir(parents=True) - (log_dir / "mcp.log").write_text("hello") - - result = c.server_log_path("brave-search") - assert result == log_dir / "mcp.log" - - -def test_server_log_path_windows_none_when_missing(tmp_path, monkeypatch): - monkeypatch.setattr(sys, "platform", "win32") - monkeypatch.setattr(c.os, "name", "nt") - monkeypatch.setenv("APPDATA", str(tmp_path)) - assert c.server_log_path("brave-search") is None - - -def test_server_log_path_unsupported_platform_returns_none(tmp_path, monkeypatch): - monkeypatch.setattr(sys, "platform", "linux") - monkeypatch.setattr(c.os, "name", "posix") - monkeypatch.setattr(c.Path, "home", lambda: tmp_path) - assert c.server_log_path("brave-search") is None