""" E2E connect tests for agents_dashboard against the live backend. Runs the deployed .exe with --connect-test, which exercises the SAME fn_http code path the GUI uses (curl spawn via CreateProcessW on Windows). Verifies: * /health → 200 sin auth * /agents → 401 sin Bearer * /agents → 200 + JSON array con Bearer Skips if: * AGENTS_API_KEY env var missing (run with `pass agentes/api-key`) * Deployed exe not found Run from repo root: AGENTS_API_KEY=$(pass agentes/api-key) \\ python3 -m pytest -x -q projects/element_agents/apps/agents_dashboard/tests/test_connect_e2e.py """ from __future__ import annotations import json import os import shutil import subprocess from pathlib import Path import pytest DEFAULT_EXE = Path("/mnt/c/Users/lucas/Desktop/apps/agents_dashboard/agents_dashboard.exe") DEFAULT_URL = "https://agents.organic-machine.com" def _exe() -> Path: p = Path(os.environ.get("AGENTS_DASHBOARD_EXE", DEFAULT_EXE)) if not p.exists(): pytest.skip(f"deployed exe not found: {p}") return p def _url() -> str: return os.environ.get("AGENTS_DASHBOARD_URL", DEFAULT_URL) def _apikey() -> str: k = os.environ.get("AGENTS_API_KEY", "").strip() if not k: pytest.skip("AGENTS_API_KEY env var missing (try `pass agentes/api-key`)") return k def _run_connect_test(url: str, env: dict | None = None) -> subprocess.CompletedProcess: """Invoke .exe --connect-test with WSLENV so env propagates to Windows binary.""" full_env = os.environ.copy() if env: full_env.update(env) # WSLENV: comma/colon-separated list of env names to forward to Win32 keep = full_env.get("WSLENV", "") add = "AGENTS_API_KEY" full_env["WSLENV"] = f"{keep}:{add}" if keep else add return subprocess.run( [str(_exe()), "--connect-test", url], capture_output=True, text=True, timeout=30, env=full_env, ) # --------------------------------------------------------------------------- # Tests # --------------------------------------------------------------------------- def test_connect_succeeds_with_valid_apikey(): """OK on stdout, exit 0, when env + URL + apikey are valid.""" _apikey() # skip if missing r = _run_connect_test(_url()) assert r.returncode == 0, f"exit={r.returncode}\nstdout={r.stdout}\nstderr={r.stderr}" assert r.stdout.startswith("OK "), f"stdout=[{r.stdout!r}]" n = int(r.stdout.strip().split()[1]) assert n > 0, f"expected at least 1 agent, got {n}" def test_connect_fails_without_apikey(): """FAIL on stderr, exit 1, when AGENTS_API_KEY is empty.""" # Force-empty AGENTS_API_KEY; bypass WSLENV by clearing it too. r = subprocess.run( [str(_exe()), "--connect-test", _url()], capture_output=True, text=True, timeout=30, env={**os.environ, "AGENTS_API_KEY": "", "WSLENV": "AGENTS_API_KEY"}, ) assert r.returncode != 0 assert "AGENTS_API_KEY" in r.stderr, f"stderr=[{r.stderr!r}]" def test_connect_fails_on_bad_host(): """Transport-level failure on unresolvable host.""" _apikey() r = _run_connect_test("https://this-host-does-not-exist-xyzzy.invalid") assert r.returncode != 0 assert "FAIL" in r.stderr, f"stderr=[{r.stderr!r}]" def test_count_matches_direct_curl(): """N agents returned by the .exe must equal what /agents returns via curl.""" apikey = _apikey() # Direct curl from WSL via Windows curl.exe (matches what fn_http uses). curl_bin = shutil.which("curl.exe") or "/mnt/c/Windows/System32/curl.exe" direct = subprocess.run( [ curl_bin, "-fsS", "-H", f"Authorization: Bearer {apikey}", f"{_url()}/agents", ], capture_output=True, text=True, timeout=15, ) assert direct.returncode == 0, f"direct curl failed: {direct.stderr}" expected = len(json.loads(direct.stdout)) r = _run_connect_test(_url()) assert r.returncode == 0 got = int(r.stdout.strip().split()[1]) assert got == expected, f"exe says {got} agents, curl says {expected}" def test_url_trim_robust_to_whitespace(): """URL with leading/trailing whitespace + CR/LF must still connect.""" _apikey() # Wrap URL with whitespace + CRLF; trim_url() in main.cpp must strip. url = " \r\n " + _url() + " \r\n\t" r = _run_connect_test(url) assert r.returncode == 0, f"trim failed: stderr={r.stderr!r}" assert r.stdout.startswith("OK ")