Skip to content

Commit 71c3635

Browse files
committed
Add unit tests for the macOS fallback guard and the cli pre-spawn helper
Covers the load-bearing behaviors introduced by the prior commits: - _maybe_fallback_start re-raises on darwin (commit 1) - _maybe_fallback_start still re-raises non-fds_to_keep errors verbatim - _open_worker_log honors $SQLIT_WORKER_LOG and survives an unwritable path - _prewarm_process_worker respects runtime.process_worker, runtime.mock, and swallows spawn exceptions so startup never crashes (commit 3) - SSMSTUI(process_worker_client=client) stashes the client on self._process_worker_client, which is what ProcessWorkerLifecycleMixin consults first
1 parent 5e21d22 commit 71c3635

2 files changed

Lines changed: 132 additions & 0 deletions

File tree

tests/unit/test_cli_prewarm.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Tests for the pre-spawn helper in cli.py and the SSMSTUI kwarg plumbing."""
2+
3+
from __future__ import annotations
4+
5+
from unittest.mock import MagicMock, patch
6+
7+
from sqlit.cli import _prewarm_process_worker
8+
from sqlit.shared.app.runtime import MockConfig, RuntimeConfig
9+
10+
11+
def test_prewarm_skipped_when_worker_disabled() -> None:
12+
runtime = RuntimeConfig(process_worker=False)
13+
with patch("sqlit.domains.process_worker.app.process_worker_client.ProcessWorkerClient") as klass:
14+
result = _prewarm_process_worker(runtime)
15+
assert result is None
16+
klass.assert_not_called()
17+
18+
19+
def test_prewarm_skipped_when_mock_enabled() -> None:
20+
runtime = RuntimeConfig(process_worker=True, mock=MockConfig(enabled=True))
21+
with patch("sqlit.domains.process_worker.app.process_worker_client.ProcessWorkerClient") as klass:
22+
result = _prewarm_process_worker(runtime)
23+
assert result is None
24+
klass.assert_not_called()
25+
26+
27+
def test_prewarm_returns_client_when_enabled() -> None:
28+
runtime = RuntimeConfig(process_worker=True)
29+
sentinel = MagicMock(name="process-worker-client")
30+
with patch(
31+
"sqlit.domains.process_worker.app.process_worker_client.ProcessWorkerClient",
32+
return_value=sentinel,
33+
):
34+
result = _prewarm_process_worker(runtime)
35+
assert result is sentinel
36+
37+
38+
def test_prewarm_swallows_spawn_errors() -> None:
39+
"""A failing pre-spawn must not break startup; lazy path handles fallback."""
40+
runtime = RuntimeConfig(process_worker=True)
41+
with patch(
42+
"sqlit.domains.process_worker.app.process_worker_client.ProcessWorkerClient",
43+
side_effect=ValueError("bad value(s) in fds_to_keep"),
44+
):
45+
result = _prewarm_process_worker(runtime)
46+
assert result is None
47+
48+
49+
def test_ssmstui_stashes_prewarmed_worker() -> None:
50+
"""A client passed via the kwarg should land on self._process_worker_client.
51+
52+
ProcessWorkerLifecycleMixin returns that attribute first, so this is
53+
what makes the pre-spawn actually short-circuit the lazy path.
54+
"""
55+
from sqlit.domains.shell.app.main import SSMSTUI
56+
from tests.ui.mocks import MockConnectionStore, MockSettingsStore, build_test_services, create_test_connection
57+
58+
services = build_test_services(
59+
connection_store=MockConnectionStore([create_test_connection("test-db", "sqlite")]),
60+
settings_store=MockSettingsStore({}),
61+
)
62+
sentinel = MagicMock(name="process-worker-client")
63+
app = SSMSTUI(services=services, process_worker_client=sentinel)
64+
assert app._process_worker_client is sentinel
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""Tests for the macOS fork-fallback guard and the worker log redirect."""
2+
3+
from __future__ import annotations
4+
5+
from pathlib import Path
6+
7+
import pytest
8+
9+
from sqlit.domains.process_worker.app.process_worker import _open_worker_log
10+
from sqlit.domains.process_worker.app.process_worker_client import ProcessWorkerClient
11+
12+
13+
def _make_client_without_init() -> ProcessWorkerClient:
14+
"""Build a bare ProcessWorkerClient instance without running __init__.
15+
16+
__init__ spawns a real subprocess; we only want to exercise the
17+
in-process branching logic in _maybe_fallback_start.
18+
"""
19+
return ProcessWorkerClient.__new__(ProcessWorkerClient)
20+
21+
22+
def test_fork_fallback_disabled_on_darwin(monkeypatch: pytest.MonkeyPatch) -> None:
23+
"""On macOS the fallback path must re-raise instead of forking."""
24+
monkeypatch.setattr("sys.platform", "darwin")
25+
client = _make_client_without_init()
26+
27+
error = ValueError("bad value(s) in fds_to_keep")
28+
with pytest.raises(ValueError, match="fds_to_keep"):
29+
client._maybe_fallback_start(error)
30+
31+
32+
def test_fork_fallback_skips_non_fds_errors(monkeypatch: pytest.MonkeyPatch) -> None:
33+
"""Errors unrelated to fds_to_keep should always re-raise verbatim."""
34+
monkeypatch.setattr("sys.platform", "linux")
35+
client = _make_client_without_init()
36+
37+
error = ValueError("totally unrelated message")
38+
with pytest.raises(ValueError, match="totally unrelated"):
39+
client._maybe_fallback_start(error)
40+
41+
42+
def test_worker_log_honors_env_override(
43+
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
44+
) -> None:
45+
"""SQLIT_WORKER_LOG should redirect the worker log to a custom path."""
46+
target = tmp_path / "subdir" / "worker.log"
47+
monkeypatch.setenv("SQLIT_WORKER_LOG", str(target))
48+
49+
log_file = _open_worker_log()
50+
assert log_file is not None
51+
try:
52+
log_file.write("hello\n")
53+
finally:
54+
log_file.close()
55+
56+
assert target.exists()
57+
assert "hello" in target.read_text()
58+
59+
60+
def test_worker_log_returns_none_on_unwritable_path(
61+
monkeypatch: pytest.MonkeyPatch,
62+
) -> None:
63+
"""If the log path can't be opened, the worker should still boot."""
64+
# A path whose parent can't be created (root-owned, non-existent).
65+
monkeypatch.setenv("SQLIT_WORKER_LOG", "/proc/definitely/not/writable/here.log")
66+
67+
log_file = _open_worker_log()
68+
assert log_file is None

0 commit comments

Comments
 (0)