Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/panopticon/sessionservice/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,9 @@ def run_host(
HostDaemon(client, spawner, provisioner, interval=interval, sleep=sleep).run(until=until)


def main(
argv: list[str] | None = None, *, client: TaskServiceClient | None = None
) -> None: # pragma: no cover - thin wiring + endless loop
def build_arg_parser() -> argparse.ArgumentParser:
"""Build the ``host`` daemon's CLI parser — split out from :func:`main` so tests can inspect
argument defaults (e.g. ``--host``) without running the endless daemon loop."""
parser = argparse.ArgumentParser(
prog="python -m panopticon.sessionservice.host",
description="Per-host session service: spawn tasks + provision them (ADR 0008/0011).",
Expand Down Expand Up @@ -226,7 +226,13 @@ def main(
default=2.0,
help="change-feed long-poll wait, seconds (the keepalive ceiling between blocking calls)",
)
args = parser.parse_args(argv)
return parser


def main(
argv: list[str] | None = None, *, client: TaskServiceClient | None = None
) -> None: # pragma: no cover - thin wiring + endless loop
args = build_arg_parser().parse_args(argv)
logging.basicConfig(
level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s"
)
Expand Down
30 changes: 29 additions & 1 deletion tests/sessionservice/test_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@
from pathlib import Path

import httpx
import pytest
from fastapi.testclient import TestClient

from panopticon.client import JsonObj, TaskServiceClient
from panopticon.core.git import GitClones
from panopticon.core.models import Repo
from panopticon.sessionservice.clones import CloneCache
from panopticon.sessionservice.host import HostDaemon, hold_runner_liveness, run_host
from panopticon.sessionservice.host import (
HostDaemon,
build_arg_parser,
hold_runner_liveness,
run_host,
)
from panopticon.taskservice.api import create_app
from panopticon.taskservice.artifacts_fs import FilesystemArtifactStore
from panopticon.taskservice.service import TaskService
Expand Down Expand Up @@ -356,6 +362,28 @@ def gen() -> Generator[None, None, None]:
assert recorded == ["box.example.com"]


def test_build_arg_parser_host_defaults_to_empty_when_unset(
monkeypatch: pytest.MonkeyPatch,
) -> None:
# A local runner must not report a host at all — any truthy value makes the terminal
# supervisor wrap tmux attach in `ssh -t <host>`, which breaks a purely local session.
monkeypatch.delenv("PANOPTICON_RUNNER_HOST", raising=False)
args = build_arg_parser().parse_args([])
assert args.host == ""


def test_build_arg_parser_host_from_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("PANOPTICON_RUNNER_HOST", "box.example.com")
args = build_arg_parser().parse_args([])
assert args.host == "box.example.com"


def test_build_arg_parser_host_flag_overrides_env(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("PANOPTICON_RUNNER_HOST", "box.example.com")
args = build_arg_parser().parse_args(["--host", "other.example.com"])
assert args.host == "other.example.com"


def test_run_host_spawns_then_provisions_end_to_end(tmp_path: Path) -> None:
service = TaskService(SqlAlchemyStore(), {"spike": Spike()}, FilesystemArtifactStore(tmp_path))
asyncio.run(service.init())
Expand Down
Loading