Implemented better testing and fixed skipepd frames

This commit is contained in:
Martino Ferrari
2026-07-01 16:39:34 +02:00
parent 7a326c5d78
commit 0bea41f866
46 changed files with 4358 additions and 1739 deletions
+90 -17
View File
@@ -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)