Files
elmprodvpn/tests/vpn_login_flow.py

81 lines
2.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""VPN login session smoke: start -> state polling -> optional action -> stop."""
import json
import os
import sys
import time
from urllib import request
API_BASE = os.environ.get("API_URL", "http://127.0.0.1:8080")
TIMEOUT = int(os.environ.get("VPN_FLOW_TIMEOUT_SEC", "20"))
def call(method, path, data=None, timeout=10):
url = f"{API_BASE}{path}"
payload = json.dumps(data).encode("utf-8") if data is not None else None
req = request.Request(url, data=payload, method=method)
if payload is not None:
req.add_header("Content-Type", "application/json")
try:
with request.urlopen(req, timeout=timeout) as resp:
body = resp.read()
except Exception as err:
print(f"[vpn] request {path} failed: {err}", file=sys.stderr)
sys.exit(1)
try:
return json.loads(body)
except json.JSONDecodeError:
print(f"[vpn] non-json response for {path}: {body[:200]!r}", file=sys.stderr)
sys.exit(1)
def main():
print(f"[vpn] API_BASE={API_BASE}")
start = call("POST", "/api/v1/vpn/login/session/start")
if "ok" not in start or "phase" not in start or "level" not in start:
print(f"[vpn] invalid start payload: {start}", file=sys.stderr)
sys.exit(1)
print(f"[vpn] start phase={start.get('phase')} ok={start.get('ok')}")
cursor = 0
saw_state = False
tried_action = False
deadline = time.time() + TIMEOUT
while time.time() < deadline:
state = call("GET", f"/api/v1/vpn/login/session/state?since={cursor}")
saw_state = True
if "cursor" in state:
cursor = int(state["cursor"])
phase = state.get("phase")
alive = bool(state.get("alive"))
can_check = bool(state.get("can_check"))
print(f"[vpn] state phase={phase} alive={alive} cursor={cursor}")
if can_check and alive and not tried_action:
action = call("POST", "/api/v1/vpn/login/session/action", {"action": "check"})
if not action.get("ok", False):
print(f"[vpn] action check failed: {action}", file=sys.stderr)
sys.exit(1)
tried_action = True
print("[vpn] action=check sent")
if phase in ("success", "already_logged", "failed", "cancelled"):
break
time.sleep(1)
if not saw_state:
print("[vpn] no state response received", file=sys.stderr)
sys.exit(1)
stop = call("POST", "/api/v1/vpn/login/session/stop")
if not stop.get("ok", False):
print(f"[vpn] stop failed: {stop}", file=sys.stderr)
sys.exit(1)
print("[vpn] flow smoke passed")
if __name__ == "__main__":
main()