Files
AstrBot/scripts/smoke_startup_check.py
Soulter afeda9b82a fix: downgrade python-ripgrep version to 0.0.8 in dependencies (#7514)
* fix: downgrade python-ripgrep version to 0.0.8 in dependencies

* fix: update smoke test workflow to support multiple OS and Python versions
2026-04-13 20:54:18 +08:00

117 lines
3.0 KiB
Python

"""Cross-platform startup smoke check for AstrBot."""
from __future__ import annotations
import os
import shutil
import subprocess
import sys
import tempfile
import time
import urllib.error
import urllib.request
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
HEALTH_URL = "http://127.0.0.1:6185"
STARTUP_TIMEOUT_SECONDS = 60
REQUEST_TIMEOUT_SECONDS = 2
def _tail(path: Path, lines: int = 80) -> str:
try:
content = path.read_text(encoding="utf-8", errors="replace").splitlines()
except OSError as exc:
return f"Unable to read smoke log: {exc}"
return "\n".join(content[-lines:])
def _is_ready() -> bool:
try:
with urllib.request.urlopen( # noqa: S310
HEALTH_URL,
timeout=REQUEST_TIMEOUT_SECONDS,
) as response:
return response.status < 400
except (OSError, urllib.error.URLError):
return False
def _stop_process(proc: subprocess.Popen[bytes]) -> None:
if proc.poll() is not None:
return
proc.terminate()
try:
proc.wait(timeout=10)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait(timeout=10)
def main() -> int:
env = os.environ.copy()
env.setdefault("PYTHONUTF8", "1")
env.setdefault("TESTING", "true")
smoke_root = Path(tempfile.mkdtemp(prefix="astrbot-smoke-root-"))
env["ASTRBOT_ROOT"] = str(smoke_root)
log_path = smoke_root / "smoke.log"
webui_dir = smoke_root / "webui"
webui_dir.mkdir()
(webui_dir / "index.html").write_text(
"<!doctype html><title>AstrBot</title>",
encoding="utf-8",
)
with log_path.open("wb") as log_file:
proc = subprocess.Popen(
[
sys.executable,
str(REPO_ROOT / "main.py"),
"--webui-dir",
str(webui_dir),
],
cwd=REPO_ROOT,
stdout=log_file,
stderr=subprocess.STDOUT,
env=env,
)
print(f"Starting smoke test on {HEALTH_URL}")
deadline = time.monotonic() + STARTUP_TIMEOUT_SECONDS
try:
while time.monotonic() < deadline:
if _is_ready():
print("Smoke test passed")
return 0
return_code = proc.poll()
if return_code is not None:
print(
f"AstrBot exited before becoming healthy. Exit code: {return_code}",
file=sys.stderr,
)
print(_tail(log_path), file=sys.stderr)
return 1
time.sleep(1)
print(
"Smoke test failed: health endpoint did not become ready in time.",
file=sys.stderr,
)
print(_tail(log_path), file=sys.stderr)
return 1
finally:
_stop_process(proc)
try:
log_path.unlink()
except OSError:
pass
shutil.rmtree(smoke_root, ignore_errors=True)
if __name__ == "__main__":
raise SystemExit(main())