confluence_web/tests/integration/test_browser_backend.py
Artur Mukhamadiev d77b52ae86 integration: contract checks, error mapping, deployment entry points
- tests/integration: frontend served by backend, runtime error mapping,
  backend + real pi image with scripted model/Confluence (shared example,
  variants, failure paths, cancellation/busy gate, isolation canaries,
  HTTP download ownership, 16 MiB prompt round trip), real OpenAI-compatible
  adapter + real image over a scripted transport, real Chrome against the
  real backend with a scripted runtime peer, backend crash/restart
  reconciliation, and an opt-in live model check (marker: live).
- backend: map runtime terminal codes (model_output_limit,
  model_context_exceeded, query_timeout, connectivity_failed) to the
  contract's HTTP statuses; make the artifact 404 body identical for
  no-session, wrong-session, unknown and expired IDs.
- Makefile, scripts/run-backend.sh, deploy/confluence-web.env.example,
  root README for the integrated application; integration pytest marker.
2026-09-14 22:20:34 +03:00

78 lines
2.4 KiB
Python

"""Browser <-> backend pair: real Chrome (CDP) against the real backend HTTP server.
Requires Node and a Chrome instance exposing the DevTools protocol on
127.0.0.1:9444 (see frontend/README.md). Skips otherwise.
"""
from __future__ import annotations
import os
import shutil
import socket
import subprocess
import sys
import time
import urllib.request
from pathlib import Path
import pytest
from tests.integration.conftest import REPO_ROOT
pytestmark = pytest.mark.integration
CHROME_PORT = int(os.getenv("CW_CHROME_CDP_PORT", "9444"))
def chrome_available() -> bool:
try:
with urllib.request.urlopen(f"http://127.0.0.1:{CHROME_PORT}/json/version", timeout=2) as r:
return r.status == 200
except Exception:
return False
def free_port() -> int:
with socket.socket() as s:
s.bind(("127.0.0.1", 0))
return s.getsockname()[1]
@pytest.mark.skipif(shutil.which("node") is None or not chrome_available(), reason="node and Chrome CDP on 9444 required")
def test_browser_against_real_backend(tmp_path: Path):
port = free_port()
control = tmp_path / "scenario"
control.write_text("standard\n")
env = {
"PATH": os.environ["PATH"],
"CW_PEER_CONTROL_FILE": str(control),
"CW_ARTIFACT_DIR": str(tmp_path / "artifacts"),
"CW_DEV_PORT": str(port),
"PYTHONPATH": str(REPO_ROOT),
}
server = subprocess.Popen([sys.executable, str(REPO_ROOT / "tests/integration/dev_server.py")], env=env, cwd=REPO_ROOT)
try:
deadline = time.time() + 30
while time.time() < deadline:
try:
with urllib.request.urlopen(f"http://127.0.0.1:{port}/", timeout=1) as r:
if r.status == 200:
break
except Exception:
time.sleep(0.2)
else:
raise AssertionError("dev server did not start")
res = subprocess.run(
["node", str(REPO_ROOT / "tests/integration/browser_backend.mjs"), "--app", f"http://127.0.0.1:{port}", "--control", str(control), "--chrome", str(CHROME_PORT)],
capture_output=True, text=True, timeout=300, cwd=REPO_ROOT,
)
print(res.stdout)
print(res.stderr, file=sys.stderr)
assert res.returncode == 0, res.stdout + res.stderr
finally:
server.terminate()
try:
server.wait(timeout=10)
except subprocess.TimeoutExpired:
server.kill()