Wire the live-test gate and pin the toolchain to 3.14

README advertised `uv run pytest -m live --live`, but there was no --live
option and no `live` marker registered — the command errored out, so the
one workflow that catches an upstream renaming a series did not exist.

- conftest adds --live and skips `live`-marked tests without it, so the
  default run stays hermetic (258 passed, 6 skipped, no network).
- tests/test_live_fleet.py drives the real code paths (collectors.*,
  NutMonitor.collect) against the fleet, both engines, and upsd. Each
  skips when its source is unset, and none of them may write — a battery
  test on live hardware is not a unit test. The host test polls twice
  because a rate has no second point on the first scrape.
- The agent's real-/proc test stays in the default run and is explicitly
  not `live`: it touches only the box running pytest.
- dev-tunnels.sh grows DEV_FORWARDS for services already listening
  remotely, which is how upsd gets reachable without opening 3493;
  pidfiles are now host+port so one host can carry two tunnels.
- requires-python, ruff and pyright were still on 3.13 while the venv and
  Containerfile are 3.14, so the lock resolved for a stack nobody deploys.

LLM-Generated: true
This commit is contained in:
2026-10-16 18:55:02 -04:00
parent 87042f8855
commit b389bb4a94
6 changed files with 281 additions and 97 deletions
+23
View File
@@ -3,6 +3,11 @@
Anything that must match an upstream (an agent snapshot, an engine's /metrics text, the NUT
wire protocol) is asserted against a verbatim capture in tests/fixtures/. Everything that
needs a *failure* — a dead host, a refused command, a counter reset — is a fake here.
The `live` marker is the bridge to real hardware: those tests dial the fleet, the engines,
or upsd, so they SKIP unless you pass `--live` and have set the env vars they read (see
tests/test_live_fleet.py). That keeps `uv run pytest` hermetic and offline while still
letting `uv run pytest -m live --live` catch an upstream that renamed something.
"""
from __future__ import annotations
@@ -13,6 +18,24 @@ from typing import Any
import pytest
def pytest_addoption(parser: pytest.Parser) -> None:
parser.addoption(
"--live",
action="store_true",
default=False,
help="run tests marked `live` against the real fleet/engines/upsd (they skip otherwise)",
)
def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
if config.getoption("--live"):
return
skip = pytest.mark.skip(reason="needs --live and a reachable target (see tests/test_live_fleet.py)")
for item in items:
if "live" in item.keywords:
item.add_marker(skip)
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "src"
if str(SRC) not in sys.path: