Files
gaokao-volunteer-system/tests/test_t5_performance.py
Hermes Agent c03ed7a4ba
Some checks failed
CI / pytest (Python 3.10) (push) Has been cancelled
CI / pytest (Python 3.11) (push) Has been cancelled
CI / pytest (Python 3.12) (push) Has been cancelled
feat(web): tighten portal privacy and cleanup flows
2026-06-15 21:24:55 +08:00

169 lines
4.3 KiB
Python

from __future__ import annotations
import csv
import importlib.util
import os
import socket
import subprocess
import sys
import time
import urllib.error
import urllib.request
from pathlib import Path
from typing import Iterator
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
QUICK_SCRIPT = PROJECT_ROOT / "scripts" / "gaokao-quick-3min.py"
LOCUST_FILE = PROJECT_ROOT / "locustfile.py"
_SAMPLE_REPLY = """1. 李明
2. 浙江
3. 612
4. 15230
5. R
6. 物理、数学
7. C
8. ③
9. ①
10. ②
"""
def _load_quick_module():
spec = importlib.util.spec_from_file_location("gaokao_quick_3min", QUICK_SCRIPT)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _generate_100_plans() -> float:
module = _load_quick_module()
start = time.perf_counter()
for _ in range(100):
info = module.parse_quick_response(_SAMPLE_REPLY)
module.generate_quick_summary(info)
module.generate_quick_recommendation(info)
return time.perf_counter() - start
def _find_free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
return int(sock.getsockname()[1])
def _wait_for_health(base_url: str, timeout: float = 20.0) -> None:
deadline = time.time() + timeout
while time.time() < deadline:
try:
with urllib.request.urlopen(f"{base_url}/health", timeout=1.0) as resp:
if resp.status == 200:
return
except (urllib.error.URLError, TimeoutError):
time.sleep(0.2)
raise AssertionError(f"admin app 未在 {timeout}s 内就绪: {base_url}")
@pytest.fixture
def admin_server(tmp_path: Path) -> Iterator[str]:
port = _find_free_port()
env = os.environ.copy()
env.update(
{
"GAOKAO_ENV": "dev",
"GAOKAO_DB_PATH": str(tmp_path / "admin.db"),
"GAOKAO_ORDERS_DB_PATH": str(tmp_path / "orders.db"),
"GAOKAO_JWT_SECRET": "x" * 64,
"GAOKAO_ADMIN_USER": "admin",
"GAOKAO_ADMIN_PASS": "admin123",
}
)
process = subprocess.Popen(
[
sys.executable,
"-m",
"admin.app",
"--host",
"127.0.0.1",
"--port",
str(port),
"--log-format",
"plain",
],
cwd=PROJECT_ROOT,
env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)
try:
base_url = f"http://127.0.0.1:{port}"
_wait_for_health(base_url)
yield base_url
finally:
process.terminate()
try:
process.wait(timeout=10)
except subprocess.TimeoutExpired:
process.kill()
process.wait(timeout=10)
@pytest.mark.timeout(30)
def test_plan_generation_100_runs_under_5_seconds(benchmark) -> None:
elapsed = benchmark(_generate_100_plans)
assert elapsed < 5.0
@pytest.mark.timeout(90)
def test_admin_locust_10_concurrency_success_rate_above_95(
admin_server: str, tmp_path: Path
) -> None:
report_prefix = tmp_path / "t5_2"
command = [
sys.executable,
"-m",
"locust",
"-f",
str(LOCUST_FILE),
"--host",
admin_server,
"--headless",
"-u",
"10",
"-r",
"2",
"-t",
"15s",
"--csv",
str(report_prefix),
]
result = subprocess.run(
command,
cwd=PROJECT_ROOT,
capture_output=True,
text=True,
check=False,
)
assert result.returncode == 0, result.stdout + "\n" + result.stderr
stats_path = report_prefix.with_name(report_prefix.name + "_stats.csv")
with stats_path.open(newline="", encoding="utf-8") as handle:
rows = list(csv.DictReader(handle))
aggregate = next(
row for row in rows if row.get("Name") == "Aggregated" and not row.get("Type")
)
request_count = int(aggregate["Request Count"])
failure_count = int(aggregate["Failure Count"])
success_rate = ((request_count - failure_count) / request_count) * 100
assert request_count > 0
assert success_rate > 95.0