mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015q1TVSLNNsXAoyM7sJuVKP
100 lines
3.7 KiB
Python
100 lines
3.7 KiB
Python
"""The renderer half: a run that asked for a browser must never quietly proceed without one.
|
|
|
|
The Electron boot itself needs a Linux container and a real display, so what is pinned here is
|
|
the contract around it: the deep link the window opens on, the bundle check, and the three ways
|
|
"no window" is allowed to end (loudly, every time).
|
|
"""
|
|
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from runner.boot import renderer_process
|
|
from runner.boot.renderer_process import (
|
|
CONTAINER_CHROMIUM_FLAGS,
|
|
RendererUnavailable,
|
|
SANDBOX_FLAGS,
|
|
await_registration,
|
|
dashboard_url,
|
|
serve_frontend,
|
|
start_electron,
|
|
)
|
|
from runner.run_spec import CLOUD_RUN_DASHBOARD_ID
|
|
|
|
|
|
@pytest.fixture
|
|
def dead_electron():
|
|
"""A real Popen that has already exited; await_registration is typechecked on Popen."""
|
|
process = subprocess.Popen(["/bin/sh", "-c", "exit 9"])
|
|
process.wait()
|
|
return process
|
|
|
|
|
|
@pytest.fixture
|
|
def live_electron():
|
|
"""A real Popen that stays up long enough for a poll loop to run against it."""
|
|
process = subprocess.Popen(["/bin/sh", "-c", "sleep 30"])
|
|
yield process
|
|
process.kill()
|
|
process.wait()
|
|
|
|
|
|
def test_the_window_opens_on_the_run_dashboard_not_the_picker() -> None:
|
|
# HashRouter, so the route has to be a fragment or the static server 404s on it.
|
|
assert dashboard_url(4173, CLOUD_RUN_DASHBOARD_ID) == (
|
|
"http://127.0.0.1:4173/index.html#/dashboard/cloud-run"
|
|
)
|
|
|
|
|
|
def test_a_missing_bundle_says_so_instead_of_serving_an_empty_dir(tmp_path) -> None:
|
|
with pytest.raises(RendererUnavailable, match="no frontend bundle"):
|
|
serve_frontend(str(tmp_path))
|
|
|
|
|
|
def test_a_missing_electron_binary_fails_the_run_rather_than_the_workflow(tmp_path, monkeypatch) -> None:
|
|
monkeypatch.setenv("ELECTRON_BIN", str(tmp_path / "nope"))
|
|
with pytest.raises(RendererUnavailable, match="built without a renderer"):
|
|
start_electron(str(tmp_path), 8324, "http://127.0.0.1:4173/index.html")
|
|
|
|
|
|
def test_chromium_is_launched_unsandboxed_on_purpose_and_out_of_shared_memory() -> None:
|
|
# Dropping Chromium's own sandbox is a real tradeoff (the Firecracker VM is the wall that's
|
|
# left), so it lives in a named constant a reviewer trips over, not inside a launch string.
|
|
assert SANDBOX_FLAGS == ["--no-sandbox"]
|
|
assert "--disable-dev-shm-usage" in CONTAINER_CHROMIUM_FLAGS
|
|
|
|
|
|
def test_a_dead_electron_is_reported_as_dead_not_waited_out(monkeypatch, dead_electron) -> None:
|
|
monkeypatch.setattr(renderer_process, "RENDERER_TIMEOUT_SECONDS", 30.0)
|
|
with pytest.raises(RendererUnavailable, match="exited with code 9"):
|
|
await_registration("http://127.0.0.1:1", {}, dead_electron, deadline=1e9)
|
|
|
|
|
|
def test_a_window_that_never_registers_times_out_loudly(monkeypatch, live_electron) -> None:
|
|
monkeypatch.setattr(renderer_process, "RENDERER_TIMEOUT_SECONDS", 0.5)
|
|
with pytest.raises(RendererUnavailable, match="no renderer ever registered"):
|
|
await_registration("http://127.0.0.1:1", {}, live_electron, deadline=1e9)
|
|
|
|
|
|
def test_registration_is_believed_only_when_the_backend_says_a_socket_is_attached(monkeypatch, live_electron) -> None:
|
|
replies = [{"attached": False, "ever_attached": False, "connections": 0},
|
|
{"attached": True, "ever_attached": True, "connections": 1}]
|
|
|
|
class p_Response:
|
|
def json(self):
|
|
return replies.pop(0)
|
|
|
|
class p_Client:
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *exc):
|
|
return False
|
|
|
|
def get(self, url, headers=None):
|
|
return p_Response()
|
|
|
|
monkeypatch.setattr(renderer_process.httpx, "Client", lambda **kw: p_Client())
|
|
await_registration("http://127.0.0.1:1", {}, live_electron, deadline=1e9)
|
|
assert replies == []
|