test: add end-to-end agent deployment lifecycle test

This commit is contained in:
Fredrick Amnehagen 2026-02-06 00:51:51 +01:00
parent 2382e17830
commit cd505b9994

104
tests/test_e2e_flow.py Normal file
View file

@ -0,0 +1,104 @@
import pytest
import subprocess
import os
import uuid
import testinfra
import time
# Use the bin/infra wrapper for testing
CLI_BIN = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "bin", "infra"))
CONFIG_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "config.yaml"))
SSH_KEY = os.path.expanduser("~/.ssh/id_ed25519_no_pass")
ROUTER_PASS = "kpvoh58zhq2sq6ms"
def run_infra(cmd, env=None):
full_env = os.environ.copy()
if env:
full_env.update(env)
full_env["ROUTER_PASS"] = ROUTER_PASS
full_cmd = [CLI_BIN, "--config", CONFIG_PATH] + cmd
return subprocess.run(full_cmd, capture_output=True, text=True, env=full_env)
def get_testinfra_host(host_str):
return testinfra.get_host(
f"ssh://root@{host_str}",
ssh_identity_file=SSH_KEY,
ssh_extra_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
)
@pytest.fixture
def agent_context():
"""Provides a unique context for an agent service deployment"""
uid = str(uuid.uuid4())[:8]
return {
"id": uid,
"name": f"agent-svc-{uid}",
"domain": f"agent-{uid}.loopaware.com",
"mac": f"aa:bb:cc:ee:ff:{uid[:2]}",
"port": 8080
}
def test_e2e_agent_deployment_lifecycle(agent_context):
"""
Tests the complete flow:
IPAM -> DB -> DNS -> Ingress -> Cloudflare -> Decommission
"""
ctx = agent_context
print(f"\n[E2E] Starting deployment for {ctx['name']}")
# 1. IPAM: Find next free IP
res = run_infra(["ip", "next-free"])
assert res.returncode == 0
ip = res.stdout.strip()
print(f"[E2E] Allocated IP: {ip}")
# 2. Database: Provision PostgreSQL
res = run_infra(["db", "provision", ctx['name']])
assert res.returncode == 0
assert ctx['name'].replace("-", "_") in res.stdout
print("[E2E] Database provisioned")
# 3. DNS: Register DHCP Host
res = run_infra(["dns", "add-host", ctx['mac'], ip, ctx['name']])
assert res.returncode == 0
print("[E2E] DNS/DHCP host registered")
# 4. Ingress: Configure HAProxy
res = run_infra(["ingress", "add", ctx['domain'], ip, str(ctx['port'])])
assert res.returncode == 0
print(f"[E2E] Ingress configured for {ctx['domain']}")
# 5. Cloudflare: Add to DDNS list
res = run_infra(["cloudflare", "add-ddns", ctx['domain']])
assert res.returncode == 0
print("[E2E] Cloudflare DDNS registered")
# --- VERIFICATION PHASE ---
print("[E2E] Verifying infrastructure state...")
# Verify HAProxy points to the CORRECT allocated IP
pve = get_testinfra_host("10.32.2.1")
# Wrap in single quotes to protect from local shell, double for remote
be_name = f"be_{ctx['domain'].replace('.', '_')}"
res = pve.run(f"pct exec 11220 -- grep -A 5 '{be_name}' /etc/haproxy/conf.d/99-dynamic.cfg")
assert res.rc == 0
assert ip in res.stdout
assert str(ctx['port']) in res.stdout
# Verify Database exists
db_host = get_testinfra_host("10.32.70.54")
db_name = ctx['name'].lower().replace("-", "_")
# Safer check: use psql -t -c to get raw list
res = db_host.run(f"su - postgres -c \"psql -t -c '\\l' | grep -qw {db_name}\"")
assert res.rc == 0
# --- CLEANUP / DECOMMISSION PHASE ---
print("[E2E] Starting decommissioning...")
res = run_infra(["decommission", "--domain", ctx['domain'], "--mac", ctx['mac']])
assert res.returncode == 0
# Final state check: should be gone in sites.json
res = pve.run(f"pct exec 11220 -- grep '{ctx['domain']}' /etc/haproxy/dynamic/sites.json")
assert res.rc != 0
print("[E2E] Flow completed successfully.")