#!/usr/bin/env python3 """Read-only live acceptance for upload pagination and core API latency.""" from __future__ import annotations import argparse import json import statistics import sys import time from pathlib import Path from typing import Any import httpx def call(client: httpx.Client, path: str) -> tuple[Any, float]: started = time.perf_counter() response = client.get(path) elapsed_ms = (time.perf_counter() - started) * 1000 if response.is_error: raise RuntimeError(f"GET {path} -> {response.status_code}: {response.text[:500]}") return response.json(), elapsed_ms def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--base-url", required=True) auth = parser.add_mutually_exclusive_group(required=True) auth.add_argument("--token-file", type=Path) auth.add_argument("--password-stdin", action="store_true") parser.add_argument("--report", type=Path) args = parser.parse_args() headers: dict[str, str] = {} if args.token_file: headers["Authorization"] = f"Bearer {args.token_file.read_text(encoding='utf-8').strip()}" client = httpx.Client( base_url=args.base_url.rstrip("/"), headers=headers, timeout=httpx.Timeout(30, connect=10), ) if args.password_stdin: password = sys.stdin.readline().rstrip("\r\n") login = client.post( "/api/v1/auth/login", json={"password": password, "remember_device": False}, ) password = "" if login.is_error: raise RuntimeError(f"login -> {login.status_code}: {login.text[:500]}") status, status_ms = call(client, "/api/v1/status") if status.get("version") != "0.5.45" or not status.get("configured"): raise AssertionError(f"unexpected status: {status}") legacy, legacy_ms = call(client, "/api/v1/uploads?limit=4") if not isinstance(legacy, list) or len(legacy) > 4: raise AssertionError("legacy upload response is no longer a bounded array") first, first_ms = call(client, "/api/v1/uploads?page=1&page_size=10") required = { "items", "status_items", "active_count", "failed_count", "page", "page_size", "total", "pages", } if not isinstance(first, dict) or not required.issubset(first): actual = sorted(first) if isinstance(first, dict) else type(first) raise AssertionError(f"upload page contract mismatch: {actual}") if first["page"] != 1 or first["page_size"] != 10 or len(first["items"]) > 10: raise AssertionError("upload first page bounds are invalid") if first["pages"] < 1 or first["total"] < len(first["items"]): raise AssertionError("upload pagination totals are invalid") order = [(str(item.get("created_at") or ""), str(item["id"])) for item in first["items"]] if order != sorted(order, reverse=True): raise AssertionError("upload page ordering is unstable") allowed_statuses = {"receiving", "queued", "transferring", "indexing", "failed"} if any(item.get("status") not in allowed_statuses for item in first["status_items"]): raise AssertionError("upload status summary contains terminal history") active_visible = sum(item.get("status") != "failed" for item in first["status_items"]) failed_visible = sum(item.get("status") == "failed" for item in first["status_items"]) if first["active_count"] < active_visible or first["failed_count"] < failed_visible: raise AssertionError("upload status counters are smaller than their visible summaries") second_ids: list[str] = [] second_ms: float | None = None if first["pages"] > 1: second, second_ms = call(client, "/api/v1/uploads?page=2&page_size=10") second_ids = [str(item["id"]) for item in second["items"]] if set(second_ids) & {str(item["id"]) for item in first["items"]}: raise AssertionError("upload pages overlap") latency_paths = { "uploads": "/api/v1/uploads?page=1&page_size=10", "videos": "/api/v1/videos?limit=20", "profile": "/api/v1/profile", "resources": "/api/v1/system/resources", } latency: dict[str, dict[str, float]] = {} resource_state: dict[str, Any] = {} for name, path in latency_paths.items(): samples: list[float] = [] value: Any = None for _ in range(3): value, elapsed_ms = call(client, path) samples.append(elapsed_ms) latency[name] = { "median_ms": round(statistics.median(samples), 2), "max_ms": round(max(samples), 2), } if name == "resources" and isinstance(value, dict): database = value.get("database") or {} resource_state = { "cpu_percent": value.get("cpu_percent"), "memory_available_bytes": value.get("memory_available_bytes"), "running_jobs": value.get("running_jobs"), "paused_jobs": value.get("paused_jobs"), "database": { "engine": database.get("engine"), "pool_in_use": database.get("pool_in_use"), "pool_waiters": database.get("pool_waiters"), "slow_transaction_count": database.get("slow_transaction_count"), }, } report = { "status": status, "contract": { "legacy_count": len(legacy), "page": first["page"], "page_size": first["page_size"], "page_items": len(first["items"]), "total": first["total"], "pages": first["pages"], "second_page_items": len(second_ids), "status_items": len(first["status_items"]), "active_count": first["active_count"], "failed_count": first["failed_count"], }, "initial_latency_ms": { "status": round(status_ms, 2), "legacy_uploads": round(legacy_ms, 2), "first_page": round(first_ms, 2), "second_page": round(second_ms, 2) if second_ms is not None else None, }, "latency": latency, "resources": resource_state, } encoded = json.dumps(report, ensure_ascii=False, indent=2) + "\n" if args.report: args.report.parent.mkdir(parents=True, exist_ok=True) args.report.write_text(encoded, encoding="utf-8") print(encoded, end="") if __name__ == "__main__": main()