""" Shared fixtures for live integration tests. Configure with environment variables: PIC_HOST API host (default: localhost) PIC_API_PORT API port (default: 3000) PIC_WEBUI_PORT WebUI port (default: 80) PIC_WG_CONTAINER WireGuard container name (default: cell-wireguard) """ import os import json import subprocess import pytest import requests PIC_HOST = os.environ.get('PIC_HOST', 'localhost') API_PORT = int(os.environ.get('PIC_API_PORT', '3000')) WEBUI_PORT = int(os.environ.get('PIC_WEBUI_PORT', '80')) WG_CONTAINER = os.environ.get('PIC_WG_CONTAINER', 'cell-wireguard') API_BASE = f"http://{PIC_HOST}:{API_PORT}" WEBUI_BASE = f"http://{PIC_HOST}:{WEBUI_PORT}" TEST_PEERS = ( 'integration-test-full', 'integration-test-restricted', 'integration-test-none', 'bad-svc-peer', # guard against validation-test leak ) @pytest.fixture(scope='session') def api(): s = requests.Session() s.headers['Content-Type'] = 'application/json' return s @pytest.fixture(scope='session') def api_base(): return API_BASE @pytest.fixture(scope='session') def webui_base(): return WEBUI_BASE @pytest.fixture(scope='session', autouse=True) def cleanup_test_peers(api): """Delete any leftover test peers before and after the entire session.""" for name in TEST_PEERS: api.delete(f"{API_BASE}/api/peers/{name}") yield for name in TEST_PEERS: api.delete(f"{API_BASE}/api/peers/{name}") def iptables_forward() -> str: """Return iptables-save output from the WireGuard container.""" result = subprocess.run( ['docker', 'exec', WG_CONTAINER, 'iptables-save'], capture_output=True, text=True, timeout=10, ) return result.stdout def peer_rules(peer_ip: str) -> list[str]: """Return FORWARD rule lines for a specific peer IP.""" comment = f'pic-peer-{peer_ip.replace(".", "-")}' return [line for line in iptables_forward().splitlines() if comment in line] def get_live_service_vips() -> dict: """ Read SERVICE_IPS directly from the running API container. More reliable than the config API since SERVICE_IPS may not match ip_range when the container was built before an ip_range change. """ import json result = subprocess.run( ['docker', 'exec', 'cell-api', 'python3', '-c', 'import sys; sys.path.insert(0,"/app/api");' ' from firewall_manager import SERVICE_IPS; import json; print(json.dumps(SERVICE_IPS))'], capture_output=True, text=True, timeout=10, ) if result.returncode == 0 and result.stdout.strip(): return json.loads(result.stdout) # Fallback: derive from config API cfg = requests.get(f"{API_BASE}/api/config").json() sips = cfg.get('service_ips', {}) return { 'calendar': sips.get('vip_calendar', ''), 'files': sips.get('vip_files', ''), 'mail': sips.get('vip_mail', ''), 'webdav': sips.get('vip_webdav', ''), }