Implemented better testing and fixed skipepd frames
This commit is contained in:
+90
-17
@@ -21,6 +21,7 @@ import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
@@ -60,18 +61,88 @@ def gtest_suite(gtest_bin, work):
|
||||
return s
|
||||
|
||||
|
||||
# ── Go ────────────────────────────────────────────────────────────────────────
|
||||
# ── C++ Integration (DebugService runtime, non-GTest) ─────────────────────────
|
||||
|
||||
def go_suite(client_dir, work):
|
||||
s = {"name": "Go (chain-client)", "lang": "go", "total": 0, "passed": 0,
|
||||
def integration_suite(int_bin, work, timeout=220):
|
||||
"""Run the printf-narrated IntegrationTests.ex binary and heuristically
|
||||
derive per-test pass/fail from its stdout.
|
||||
|
||||
This binary predates GTest adoption and always ``return 0`` from main()
|
||||
(only an internal 180s SIGALRM timeout or an OS-level crash produce a
|
||||
non-zero exit), so exit code alone is not a reliable signal. Each of its
|
||||
7 "--- Test N: ..." blocks prints "SUCCESS:"/"VALIDATION SUCCESSFUL:" on
|
||||
success or "ERROR:"/"FAILURE:" on failure, so split stdout by those
|
||||
headers and flag a block failed if it contains an ERROR/FAILURE marker.
|
||||
Exercises DebugServiceBase.cpp/DebugService.cpp runtime logic that the
|
||||
header-only DebugServiceGTest suite deliberately does not touch, so it is
|
||||
the only source of real coverage for those files.
|
||||
"""
|
||||
s = {"name": "C++ Integration", "lang": "cpp", "total": 0, "passed": 0,
|
||||
"failed": 0, "skipped": 0, "time_s": 0.0, "ok": False, "avail": False}
|
||||
cov_p = os.path.join(work, "go_cover.out")
|
||||
rc, out, err = _run(["go", "test", "-json", f"-coverprofile={cov_p}", "./..."],
|
||||
cwd=client_dir)
|
||||
if rc == 127:
|
||||
s["detail"] = "go toolchain not found"
|
||||
if not int_bin or not os.path.exists(int_bin):
|
||||
s["detail"] = "IntegrationTests binary not found"
|
||||
return s
|
||||
s["avail"] = True
|
||||
t0 = time.time()
|
||||
rc, out, err = _run([int_bin], timeout=timeout)
|
||||
s["time_s"] = round(time.time() - t0, 1)
|
||||
text = out + "\n" + err
|
||||
blocks = re.split(r"\n(?=--- Test \d+:)", text)
|
||||
test_blocks = [b for b in blocks if b.lstrip().startswith("--- Test")]
|
||||
finished = "All Integration Tests Finished." in text
|
||||
s["total"] = len(test_blocks)
|
||||
s["failed"] = sum(1 for b in test_blocks if re.search(r"\b(ERROR|FAILURE):", b))
|
||||
if not finished and s["total"] == 0:
|
||||
# Crashed/timed out before printing anything useful.
|
||||
s["total"] = 1
|
||||
s["failed"] = 1
|
||||
s["detail"] = f"binary did not complete (rc={rc}): {(err or out)[-200:]}"
|
||||
elif not finished:
|
||||
s["detail"] = f"binary exited rc={rc} before finishing all tests"
|
||||
s["passed"] = s["total"] - s["failed"]
|
||||
s["ok"] = finished and s["failed"] == 0 and s["total"] > 0
|
||||
return s
|
||||
|
||||
|
||||
# ── Go ────────────────────────────────────────────────────────────────────────
|
||||
|
||||
def go_all_suites(repo, work):
|
||||
"""Run Go test suites across all project modules and aggregate results."""
|
||||
modules = [
|
||||
(os.path.join(repo, "Test/E2E/chain/client"),
|
||||
"Go (chain-client)"),
|
||||
(os.path.join(repo, "Common/Client/go"),
|
||||
"Go (common udpsprotocol + wshub)"),
|
||||
(os.path.join(repo, "Client/debugger"),
|
||||
"Go (debugger)"),
|
||||
]
|
||||
total_pct = 0.0
|
||||
pct_count = 0
|
||||
suites = []
|
||||
for mod_dir, name in modules:
|
||||
s = {"name": name, "lang": "go", "total": 0, "passed": 0,
|
||||
"failed": 0, "skipped": 0, "time_s": 0.0, "ok": False, "avail": False}
|
||||
cov_p = os.path.join(work, f"go_cover_{name.replace(' ', '_')}.out")
|
||||
rc, out, err = _run(
|
||||
["go", "test", "-json", f"-coverprofile={cov_p}", "./..."],
|
||||
cwd=mod_dir)
|
||||
if rc == 127:
|
||||
s["detail"] = "go toolchain not found"
|
||||
suites.append(s)
|
||||
continue
|
||||
s["avail"] = True
|
||||
cov_pct = _parse_go_json(out, s)
|
||||
if cov_pct is not None:
|
||||
s["cov_pct"] = cov_pct
|
||||
total_pct += cov_pct
|
||||
pct_count += 1
|
||||
suites.append(s)
|
||||
return suites, (round(total_pct / pct_count, 1) if pct_count else None)
|
||||
|
||||
|
||||
def _parse_go_json(out, s):
|
||||
"""Parse Go test -json output into passed/failed/skipped counts.
|
||||
Returns coverage percentage (float or None)."""
|
||||
cov_pct = None
|
||||
for line in out.splitlines():
|
||||
try:
|
||||
@@ -93,8 +164,7 @@ def go_suite(client_dir, work):
|
||||
if m:
|
||||
cov_pct = float(m.group(1))
|
||||
s["ok"] = s["failed"] == 0 and s["total"] > 0
|
||||
s["cov_pct"] = cov_pct
|
||||
return s
|
||||
return cov_pct
|
||||
|
||||
|
||||
# ── Python ──────────────────────────────────────────────────────────────────
|
||||
@@ -250,12 +320,16 @@ def main():
|
||||
work = args.work or args.out
|
||||
os.makedirs(work, exist_ok=True)
|
||||
chain_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
client_dir = os.path.join(chain_dir, "client")
|
||||
gtest_bin = os.path.join(args.repo, "Build", args.target, "GTest", "MainGTest.ex")
|
||||
# BUILD_DIR for Test/Integration doubles the last path component
|
||||
# ($(PACKAGE)/$(lastword of CURDIR)) — see MakeStdLibDefs.gcc.
|
||||
integration_bin = os.path.join(args.repo, "Build", args.target,
|
||||
"Test", "Integration", "Integration",
|
||||
"IntegrationTests.ex")
|
||||
|
||||
suites = [gtest_suite(gtest_bin, work),
|
||||
go_suite(client_dir, work),
|
||||
py_suite(chain_dir, work)]
|
||||
go_suites, go_avg_cov = go_all_suites(args.repo, work)
|
||||
suites = ([gtest_suite(gtest_bin, work), integration_suite(integration_bin, work)]
|
||||
+ go_suites + [py_suite(chain_dir, work)])
|
||||
totals = {k: sum(s.get(k, 0) for s in suites)
|
||||
for k in ("total", "passed", "failed", "skipped")}
|
||||
ut = {"suites": suites, "totals": totals,
|
||||
@@ -265,11 +339,10 @@ def main():
|
||||
|
||||
langs = []
|
||||
py = next(s for s in suites if s["lang"] == "python")
|
||||
go = next(s for s in suites if s["lang"] == "go")
|
||||
langs.append({"name": "Python", "avail": py.get("cov_pct") is not None,
|
||||
"pct": py.get("cov_pct"), "note": "coverage.py"})
|
||||
langs.append({"name": "Go", "avail": go.get("cov_pct") is not None,
|
||||
"pct": go.get("cov_pct"), "note": "go test -cover"})
|
||||
langs.append({"name": "Go", "avail": go_avg_cov is not None,
|
||||
"pct": go_avg_cov, "note": "go test -cover (avg across modules)"})
|
||||
cpp = cpp_coverage(args.repo, args.target) if args.cpp_coverage else \
|
||||
{"name": "C++", "avail": False, "pct": None, "note": "skipped (use --cpp-coverage)"}
|
||||
langs.append(cpp)
|
||||
|
||||
Reference in New Issue
Block a user