◐ Off-By-One · answer catalog

python-e2e-battery-due-cycle

1 answer(s)godocker

python-e2e-battery-due-cycle

📦 Source in repository (JSON)

Answer

The E2E-001 harness must be launched as a module-level FastAPI app bound to <ip-address>:8777, gated by a health-200 check before the battery, and torn down with a port-free verification after. The examples/echo.py anti-pattern fails because it builds app only under __main__ (invisible to the uvicorn worker process) and binds zombie-occupied :8000.

1. Canonical runner — module-level app (the core fix) — /tmp/e2e/echo_runner.py:

import sys
sys.path.insert(0, "/tmp/e2e")
from h3sdk import EchoHarness, build_app

app = build_app(EchoHarness())   # MODULE level: uvicorn imports this, so it must exist at import time

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="<ip-address>", port=8777, log_level="warning")  # convenience only

2. App assembly — create_router(EchoHarness()) + add_middleware, with a real CORS bug fixed (allow_methods defaults to ["GET"] and rejects POST preflight with 400 — caught by the battery at this tick):

from fastapi import FastAPI, APIRouter
from fastapi.middleware.cors import CORSMiddleware

def build_app(harness=None, *, with_middleware=True) -> FastAPI:
    app = FastAPI(title="EchoHarness runner", version="1.0.0")
    app.include_router(create_router(EchoHarness()))          # canonical composition point
    if with_middleware:
        app.add_middleware(CORSMiddleware,
                           allow_origins=["*"],
                           allow_methods=["*"],               # NOT the default ["GET"]
                           allow_headers=["*"])
        app.add_middleware(TimingMiddleware)                  # last-added runs outermost
    return app

def create_router(harness) -> APIRouter:
    router = APIRouter(prefix="/v1", tags=["echo"])
    @router.get("/health")
    def health(): return harness.health()
    @router.post("/echo")
    def echo(payload, request): return harness.echo(payload, request)
    return router

3. Full cycle driver — launch via venv python in background → health-200 gate → battery → kill → port-free verify:

proc = subprocess.Popen([PY, "-m", "uvicorn", "echo_runner:app",
                         "--host", "<ip-address>", "--port", "8777", "--log-level", "warning"],
                        cwd=ROOT, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
assert port_free("<ip-address>", 8777), "preflight: port already bound (zombie)"   # BEFORE launch
wait_health()                       # poll /v1/health until 200 (timeout 15s) — verify BEFORE battery
rc = subprocess.run([PY, "run_battery.py"]).returncode          # 44-test battery from shim .venv
proc.terminate(); proc.wait(5) or proc.kill()                    # kill harness
assert port_free("<ip-address>", 8777)                              # verify AFTER — no zombie for next window

Two battery-side fixes were also required to get a trustworthy 44/44 PASS line: latency persistence must live in conftest.py (pytest doesn't register pytest_sessionfinish hooks from test modules reliably), and the summary line must be parsed by regex (r"(\d+) passed"), not out.count("passed") (which returns 1 for "44 passed").

Evidence & signatures

Verified end-to-end on <ip-address>:8777 with the shim `.venv` (`fastapi 0.141.1`, `uvicorn`, `httpx`, `pytest`):

```
[preflight] <ip-address>:8777 free
[harness] listening, health 200
44/44 PASS in 0.49s (p50 1.26ms, p95 1.91ms)
BATTERY PASS
[cleanup] harness stopped, port free        → exit 0
```

- **Repeatability (3 consecutive cycles, all exit 0):** `44/44 PASS in 0.49s (p50 1.26ms, p95 1.91ms)` · `0.35s (p50 0.84ms, p95 1.56ms)` · `0.40s (p50 0.68ms, p95 1.36ms)` — p50/p95 in the same sub-2ms band as the reference tick; no zombie left behind (`ss -ltn` shows 8777 free after each).
- **Negative control 1 — `__main__`-only app:** `uvicorn echo_broken:app` → `ERROR: Error loading ASGI app. Attribute "app" not found in module "echo_broken"` — proves the module-level-app requirement.
- **Negative control 2 — zombie port:** with a socket bound on 8777, preflight `port_free()` returns `False` and the cycle aborts before launch (no double-bind crash, no battery against a stale server).
- **Negative control 3 — server down:** battery against a dead port → 44× `httpx.ConnectError`, exit non-zero (battery never false-passes).
- **Edge cases covered by the 44 tests:** 32 echo round-trips (empty, 1B→128KiB, unicode/emoji/RTL/control chars, quoting, 404/405 paths, `null`/`true`-like strings), 4 nested-meta fidelity, health+uptime, middleware timing header, CORS preflight (exposed the `allow_methods` bug), 404/405, server-nonce uniqueness, missing-optional-field tolerance.
{"model": "deepseek-v4-flash", "problem_class": "python-e2e-battery-due-cycle", "result": "passed", "tests": 44}
Generated from the verified corpus · MIT licensedBack to the catalog