shin / tests /cli /test_desktop.py
LastNoob's picture
Add ChatGPT OAuth as an OpenAI Codex provider (#1279)
9fb95ba unverified
Raw
History Blame Contribute Delete
9.35 kB
"""Desktop shell lifecycle and singleton contracts."""
import threading
from pathlib import Path
from unittest.mock import MagicMock, patch
from free_claude_code.cli.commands import ServerStatus, ServerSupervisor
from free_claude_code.cli.desktop import DesktopController
from free_claude_code.config.settings import Settings
from free_claude_code.core.interprocess_lock import InterprocessFileLock
def _settings() -> Settings:
return Settings.model_construct(host="0.0.0.0", port=8082)
def test_desktop_instance_lock_is_exclusive_and_reusable(tmp_path: Path) -> None:
lock_path = tmp_path / "desktop.lock"
first = InterprocessFileLock(lock_path)
second = InterprocessFileLock(lock_path)
assert first.acquire() is True
assert first.acquire() is True
assert second.acquire() is False
first.release()
first.release()
assert second.acquire() is True
second.release()
def test_supervisor_accepts_restart_during_scheduled_startup() -> None:
supervisor = ServerSupervisor(console_logging=False)
settings = _settings()
with (
patch(
"free_claude_code.cli.commands.load_server_settings",
return_value=settings,
),
patch.object(supervisor, "_run_once", return_value=False) as run_once,
patch("free_claude_code.cli.commands.kill_all_best_effort"),
):
assert supervisor.schedule_run() is True
assert supervisor.status is ServerStatus.STARTING
assert supervisor.request_restart() is True
supervisor.run(open_admin_browser=False)
run_once.assert_called_once_with(
settings,
open_admin_browser=False,
restart_generation=1,
)
assert supervisor.status is ServerStatus.STOPPED
def test_desktop_controller_owns_server_thread_and_graceful_quit() -> None:
opened = threading.Event()
class FakeSupervisor:
def __init__(self) -> None:
self.status = ServerStatus.STARTING
self.started = threading.Event()
self.stopped = threading.Event()
self.run_arguments: list[bool | None] = []
self.schedule_count = 0
self.restart_count = 0
self.stop_count = 0
def schedule_run(self) -> bool:
self.schedule_count += 1
return True
def run(self, *, open_admin_browser: bool | None = None) -> None:
self.run_arguments.append(open_admin_browser)
self.status = ServerStatus.RUNNING
self.started.set()
assert self.stopped.wait(2)
self.status = ServerStatus.STOPPED
def request_restart(self) -> bool:
self.restart_count += 1
return True
def request_stop(self) -> None:
self.stop_count += 1
self.status = ServerStatus.STOPPING
self.stopped.set()
class FakeTray:
def __init__(self, controller: DesktopController) -> None:
self.controller = controller
self.run_thread_id: int | None = None
self.stop_count = 0
def run(self) -> None:
self.run_thread_id = threading.get_ident()
assert supervisor.started.wait(2)
self.controller.open_admin()
self.controller.restart_server()
self.controller.quit()
def stop(self) -> None:
self.stop_count += 1
supervisor = FakeSupervisor()
tray: FakeTray | None = None
def make_tray(controller: DesktopController) -> FakeTray:
nonlocal tray
tray = FakeTray(controller)
return tray
main_thread_id = threading.get_ident()
controller = DesktopController(supervisor, make_tray, opened.set)
controller.run()
assert tray is not None
assert tray.run_thread_id == main_thread_id
assert supervisor.run_arguments == [False]
assert supervisor.schedule_count == 1
assert supervisor.restart_count == 1
assert supervisor.stop_count >= 1
assert tray.stop_count >= 1
assert opened.is_set()
def test_restart_during_server_startup_is_accepted_without_waiting() -> None:
class StartupSupervisor:
def __init__(self) -> None:
self.status = ServerStatus.STARTING
self.run_called = threading.Event()
self.allow_run = threading.Event()
self.worker_started = threading.Event()
self.release_worker = threading.Event()
self.run_scheduled = False
self.restart_count = 0
self.accepted_restart_count = 0
def schedule_run(self) -> bool:
self.run_scheduled = True
return True
def run(self, *, open_admin_browser: bool | None = None) -> None:
assert open_admin_browser is False
self.run_called.set()
assert self.allow_run.wait(2)
self.run_scheduled = False
self.worker_started.set()
assert self.release_worker.wait(2)
self.status = ServerStatus.STOPPED
def request_restart(self) -> bool:
self.restart_count += 1
if self.run_scheduled:
self.accepted_restart_count += 1
return True
return False
def request_stop(self) -> None:
self.release_worker.set()
class WaitingTray:
def __init__(self, _controller: DesktopController) -> None:
self.started = threading.Event()
self.stopped = threading.Event()
def run(self) -> None:
self.started.set()
assert self.stopped.wait(2)
def stop(self) -> None:
self.stopped.set()
supervisor = StartupSupervisor()
tray: WaitingTray | None = None
def make_tray(controller: DesktopController) -> WaitingTray:
nonlocal tray
tray = WaitingTray(controller)
return tray
controller = DesktopController(supervisor, make_tray, MagicMock())
controller_thread = threading.Thread(target=controller.run)
controller_thread.start()
assert tray is not None
assert tray.started.wait(2)
assert supervisor.run_called.wait(2)
restart_thread = threading.Thread(target=controller.restart_server)
restart_thread.start()
restart_thread.join(0.5)
restart_blocked = restart_thread.is_alive()
supervisor.allow_run.set()
assert supervisor.worker_started.wait(2)
controller.quit()
supervisor.release_worker.set()
restart_thread.join(2)
controller_thread.join(2)
assert restart_blocked is False
assert supervisor.restart_count == 1
assert supervisor.accepted_restart_count == 1
assert not restart_thread.is_alive()
assert not controller_thread.is_alive()
def test_second_desktop_launch_opens_existing_admin_without_new_server() -> None:
from free_claude_code.cli import desktop
settings = _settings()
instance_lock = MagicMock()
instance_lock.acquire.return_value = False
with (
patch.object(desktop, "load_server_settings", return_value=settings),
patch.object(desktop, "InterprocessFileLock", return_value=instance_lock),
patch.object(desktop, "open_admin_when_ready", return_value=True) as open_admin,
patch.object(desktop, "ServerSupervisor") as supervisor,
):
desktop.launch_desktop(MagicMock())
open_admin.assert_called_once_with(settings)
supervisor.assert_not_called()
instance_lock.release.assert_not_called()
def test_desktop_attaches_to_terminal_server_instead_of_binding_twice() -> None:
from free_claude_code.cli import desktop
settings = _settings()
instance_lock = MagicMock()
instance_lock.acquire.return_value = True
with (
patch.object(desktop, "load_server_settings", return_value=settings),
patch.object(desktop, "InterprocessFileLock", return_value=instance_lock),
patch.object(desktop, "preflight_proxy", return_value=None),
patch.object(desktop, "open_admin_when_ready", return_value=True) as open_admin,
patch.object(desktop, "ServerSupervisor") as supervisor,
):
desktop.launch_desktop(MagicMock())
open_admin.assert_called_once_with(settings)
supervisor.assert_not_called()
instance_lock.release.assert_called_once_with()
def test_fresh_desktop_launch_disables_console_and_automatic_browser() -> None:
from free_claude_code.cli import desktop
settings = _settings()
instance_lock = MagicMock()
instance_lock.acquire.return_value = True
supervisor = MagicMock()
controller = MagicMock()
with (
patch.object(desktop, "load_server_settings", return_value=settings),
patch.object(desktop, "InterprocessFileLock", return_value=instance_lock),
patch.object(desktop, "preflight_proxy", return_value="connection refused"),
patch.object(desktop, "ServerSupervisor", return_value=supervisor) as owner,
patch.object(desktop, "DesktopController", return_value=controller) as shell,
):
tray_factory = MagicMock()
desktop.launch_desktop(tray_factory)
owner.assert_called_once_with(console_logging=False)
assert shell.call_args.args[:2] == (supervisor, tray_factory)
controller.run.assert_called_once_with()
instance_lock.release.assert_called_once_with()