109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
# coding: utf-8
|
|
"""Run the full test suite from a single entry point.
|
|
|
|
Groups tests by area and prints a clear per-group + total report. Optional
|
|
live/API tests (need a running QMT + redis) are skipped by default.
|
|
|
|
Usage:
|
|
python run_all_tests.py # all offline tests (default)
|
|
python run_all_tests.py -v # verbose
|
|
python run_all_tests.py --live # also run live RPC tests (needs QMT running)
|
|
python run_all_tests.py --group signal_trader # only one group
|
|
python run_all_tests.py --group backtest
|
|
"""
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
ROOT = os.path.dirname(os.path.abspath(__file__))
|
|
SRC = os.path.join(ROOT, "src")
|
|
|
|
# Test groups: (name, paths, requires_live)
|
|
GROUPS = [
|
|
("signal_trader", [os.path.join("tests", "bigqmt_signal_trader")], False),
|
|
("backtest", [os.path.join("tests", "bigqmt_backtest")], False),
|
|
]
|
|
LIVE_GROUP = ("live_api", ["test_all_apis.py"], True)
|
|
|
|
|
|
def run_group(name, paths, verbose):
|
|
"""Run a pytest group, return (passed, failed, skipped, seconds)."""
|
|
cmd = [sys.executable, "-m", "pytest"] + paths + ["-q" if not verbose else "-v"]
|
|
t0 = time.time()
|
|
proc = subprocess.run(cmd, cwd=ROOT, capture_output=True, text=True)
|
|
elapsed = time.time() - t0
|
|
out = (proc.stdout or "") + (proc.stderr or "")
|
|
# Parse pytest summary like "290 passed in 8.5s" / "1 failed, 289 passed, 3 skipped"
|
|
passed = failed = skipped = 0
|
|
for line in out.splitlines():
|
|
line = line.strip()
|
|
if not any(tok in line for tok in ("passed", "failed", "skipped", "error")):
|
|
continue
|
|
for part in line.split(","):
|
|
words = part.strip().split()
|
|
if len(words) >= 2 and words[0].isdigit():
|
|
num = int(words[0])
|
|
if words[1].startswith("passed"):
|
|
passed += num
|
|
elif words[1].startswith("failed") or words[1].startswith("error"):
|
|
failed += num
|
|
elif words[1].startswith("skipped"):
|
|
skipped += num
|
|
return passed, failed, skipped, elapsed, out, proc.returncode
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Run all bigqmt tests")
|
|
parser.add_argument("-v", "--verbose", action="store_true")
|
|
parser.add_argument("--live", action="store_true", help="also run live RPC tests (needs QMT)")
|
|
parser.add_argument("--group", help="run only this group (signal_trader/backtest/live_api)")
|
|
args = parser.parse_args()
|
|
|
|
groups = list(GROUPS)
|
|
if args.live:
|
|
groups.append(LIVE_GROUP)
|
|
if args.group:
|
|
groups = [g for g in groups if g[0] == args.group]
|
|
if not groups:
|
|
print("Unknown group: %s (available: %s)" % (args.group, ", ".join(g[0] for g in GROUPS + [LIVE_GROUP])))
|
|
return 1
|
|
|
|
print("=" * 70)
|
|
print("Big QMT Bridge - 全量测试")
|
|
print("=" * 70)
|
|
|
|
total_passed = total_failed = total_skipped = 0
|
|
total_time = 0.0
|
|
failed_groups = []
|
|
for name, paths, needs_live in groups:
|
|
print("\n--- %s ---" % name)
|
|
passed, failed, skipped, elapsed, out, rc = run_group(name, paths, args.verbose)
|
|
total_passed += passed
|
|
total_failed += failed
|
|
total_skipped += skipped
|
|
total_time += elapsed
|
|
status = "PASS" if failed == 0 and rc == 0 else "FAIL"
|
|
print(" %s: %d passed, %d failed, %d skipped (%.1fs)" % (status, passed, failed, skipped, elapsed))
|
|
if failed or rc != 0:
|
|
failed_groups.append(name)
|
|
if not args.verbose:
|
|
# print the failing part of the output for visibility
|
|
tail = "\n".join(out.splitlines()[-20:])
|
|
print(tail)
|
|
|
|
print("\n" + "=" * 70)
|
|
print("=== 汇总 ===")
|
|
print("通过 %d / 失败 %d / 跳过 %d / 总计 %d" % (total_passed, total_failed, total_skipped, total_passed + total_failed + total_skipped))
|
|
print("总耗时 %.1fs" % total_time)
|
|
if failed_groups:
|
|
print("失败分组: %s" % ", ".join(failed_groups))
|
|
return 1
|
|
print("全部通过 ✅")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|