#!/usr/bin/env python3 """Run the Go native production acceptance smoke suite.""" from __future__ import annotations import argparse import json import subprocess import sys from dataclasses import asdict, dataclass from typing import Any DEFAULT_APP_HOST = "115.29.187.205" DEFAULT_KAFKA_HOST = "114.55.58.251" DEFAULT_USER = "root" DEFAULT_BASE_URL = "http://115.29.187.205:20210" @dataclass(frozen=True) class ChildCommand: name: str argv: list[str] @dataclass(frozen=True) class ChildResult: name: str status: str exit_code: int payload: dict[str, Any] def build_commands(args: argparse.Namespace) -> list[ChildCommand]: timeout = str(args.timeout) return [ ChildCommand("systemd", [ sys.executable, "tools/go_systemd_prod_smoke.py", "--host", args.app_host, "--user", args.ssh_user, "--timeout", timeout, ]), ChildCommand("kafka", [ sys.executable, "tools/go_kafka_prod_smoke.py", "--host", args.kafka_host, "--user", args.ssh_user, "--max-lag", str(args.max_lag), "--timeout", timeout, ]), ChildCommand("http", [ sys.executable, "tools/go_native_prod_smoke.py", "--base-url", args.base_url, "--timeout", timeout, ] + (["--date", args.date] if args.date else [])), ] def run_child(command: ChildCommand, timeout: float) -> ChildResult: completed = subprocess.run( command.argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=timeout, ) payload = parse_json_output(completed.stdout) if completed.stderr.strip(): payload.setdefault("stderr", completed.stderr.strip()) status = payload.get("status") if status not in {"pass", "fail"}: status = "pass" if completed.returncode == 0 else "fail" return ChildResult(command.name, status, completed.returncode, payload) def parse_json_output(output: str) -> dict[str, Any]: output = output.strip() if not output: return {} start = output.find("{") end = output.rfind("}") if start < 0 or end < start: return {"rawOutput": output} try: return json.loads(output[start:end + 1]) except json.JSONDecodeError: return {"rawOutput": output} def overall_status(results: list[ChildResult]) -> str: if not results: return "fail" return "fail" if any(result.status != "pass" or result.exit_code != 0 for result in results) else "pass" def parse_args(argv: list[str]) -> argparse.Namespace: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--app-host", default=DEFAULT_APP_HOST) parser.add_argument("--kafka-host", default=DEFAULT_KAFKA_HOST) parser.add_argument("--ssh-user", default=DEFAULT_USER) parser.add_argument("--base-url", default=DEFAULT_BASE_URL) parser.add_argument("--date", help="Shanghai local date, YYYY-MM-DD. Defaults to today in go_native_prod_smoke.py.") parser.add_argument("--timeout", type=float, default=20.0) parser.add_argument("--max-lag", type=int, default=100) return parser.parse_args(argv) def main(argv: list[str]) -> int: args = parse_args(argv) results: list[ChildResult] = [] for command in build_commands(args): try: results.append(run_child(command, args.timeout + 10)) except Exception as exc: results.append(ChildResult(command.name, "fail", 1, {"status": "fail", "error": str(exc)})) status = overall_status(results) print(json.dumps({ "status": status, "checks": [asdict(result) for result in results], }, ensure_ascii=False, indent=2)) return 0 if status == "pass" else 1 if __name__ == "__main__": raise SystemExit(main(sys.argv[1:]))