Implemented qt port + e2e
This commit is contained in:
@@ -24,12 +24,14 @@ mkdir -p "${OUT_DIR}" "${WORK}"
|
||||
SKIP_BUILD=0
|
||||
ONLY=""
|
||||
PDF_ONLY=0
|
||||
CPP_COV=0
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--skip-build) SKIP_BUILD=1 ;;
|
||||
--only) shift; ONLY="$1" ;;
|
||||
--pdf-only) PDF_ONLY=1 ;;
|
||||
--help|-h) echo "Usage: $0 [--skip-build] [--only <id>] [--pdf-only]"; exit 0 ;;
|
||||
--cpp-coverage) CPP_COV=1 ;;
|
||||
--help|-h) echo "Usage: $0 [--skip-build] [--only <id>] [--pdf-only] [--cpp-coverage]"; exit 0 ;;
|
||||
*) echo "unknown arg $1" >&2; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
@@ -156,6 +158,9 @@ while IFS='|' read -r ID WSPORT UDPPORT NET ORACLE TRIG CHECKS; do
|
||||
timeout 120 "${MARTE_APP}" -l RealTimeLoader -f "${MCFG}" -s Running > "${APP_LOG}" 2>&1 &
|
||||
APP_PID=$!
|
||||
sleep 1
|
||||
# APP_PID is the `timeout` wrapper; perf must target the real MARTeApp child.
|
||||
APP_PERF_PID="$(pgrep -P "${APP_PID}" 2>/dev/null | head -1)"
|
||||
[ -z "${APP_PERF_PID}" ] && APP_PERF_PID="${APP_PID}"
|
||||
|
||||
TRIGARG=""
|
||||
[ -n "${TRIG}" ] && TRIGARG="-trigsig ${TRIG}"
|
||||
@@ -166,6 +171,11 @@ while IFS='|' read -r ID WSPORT UDPPORT NET ORACLE TRIG CHECKS; do
|
||||
echo " client FAILED (see client_${ID}.log)"
|
||||
tail -3 "${OUT_DIR}/client_${ID}.log" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
# Snapshot CPU/peak-RSS while the stack is still alive (peak RSS is only
|
||||
# legible before exit), then tear it down.
|
||||
[ -n "${HUB_PID}" ] && ${PY} "${SCRIPT_DIR}/proc_perf.py" "${HUB_PID}" streamhub "${WORK}/perf_${ID}_hub.json" || true
|
||||
[ -n "${APP_PERF_PID}" ] && ${PY} "${SCRIPT_DIR}/proc_perf.py" "${APP_PERF_PID}" marte "${WORK}/perf_${ID}_marte.json" || true
|
||||
cleanup
|
||||
|
||||
# validate + plot
|
||||
@@ -183,33 +193,99 @@ trap - EXIT
|
||||
cleanup
|
||||
|
||||
# ── Aggregate results.json ───────────────────────────────────────────────────
|
||||
WORK="${WORK}" OUT_DIR="${OUT_DIR}" SCEN_IDS="${SCEN_IDS}" ${PY} - <<'PY'
|
||||
import json, os
|
||||
# Scenarios carrying a `known_issue` marker exercise a documented, not-yet-fixed
|
||||
# chain gap: a raw FAIL is reclassified XFAIL (expected failure — does not break
|
||||
# the green baseline) and a raw PASS becomes XPASS (the bug was unexpectedly
|
||||
# fixed; the marker should be dropped). Overall is PASS when nothing FAILs and
|
||||
# nothing unexpectedly XPASSes.
|
||||
WORK="${WORK}" OUT_DIR="${OUT_DIR}" SCEN_IDS="${SCEN_IDS}" \
|
||||
SCRIPT_DIR="${SCRIPT_DIR}" ${PY} - <<'PY'
|
||||
import json, os, sys
|
||||
work = os.environ["WORK"]; out = os.environ["OUT_DIR"]
|
||||
ids = os.environ["SCEN_IDS"].split()
|
||||
sys.path.insert(0, os.environ["SCRIPT_DIR"])
|
||||
try:
|
||||
from scenarios import SCENARIOS
|
||||
known = {s["id"]: s.get("known_issue") for s in SCENARIOS}
|
||||
except Exception:
|
||||
known = {}
|
||||
results = []
|
||||
for sid in ids:
|
||||
rec = {"id": sid}
|
||||
st = os.path.join(work, f"status_{sid}.txt")
|
||||
rec["status"] = open(st).read().strip() if os.path.exists(st) else "UNKNOWN"
|
||||
raw = open(st).read().strip() if os.path.exists(st) else "UNKNOWN"
|
||||
ki = known.get(sid)
|
||||
if ki:
|
||||
rec["known_issue"] = ki
|
||||
if raw == "FAIL":
|
||||
raw = "XFAIL" # expected failure — documented chain gap
|
||||
elif raw == "PASS":
|
||||
raw = "XPASS" # unexpectedly fixed — drop the marker
|
||||
rec["status"] = raw
|
||||
mp = os.path.join(work, f"metrics_{sid}.json")
|
||||
if os.path.exists(mp):
|
||||
rec["metrics"] = json.load(open(mp))
|
||||
results.append(rec)
|
||||
overall = all(r["status"] in ("PASS", "SKIP") for r in results) and bool(results)
|
||||
# Green when no hard FAIL and no XPASS (an XPASS means a known_issue marker is
|
||||
# now stale and must be removed — surfaced as a failure to force the cleanup).
|
||||
overall = (bool(results)
|
||||
and all(r["status"] in ("PASS", "SKIP", "XFAIL") for r in results))
|
||||
doc = {"overall": "PASS" if overall else "FAIL", "scenarios": results}
|
||||
with open(os.path.join(out, "results.json"), "w") as f:
|
||||
json.dump(doc, f, indent=2)
|
||||
print(f"\nresults.json: {sum(r['status']=='PASS' for r in results)} pass, "
|
||||
f"{sum(r['status']=='FAIL' for r in results)} fail, "
|
||||
f"{sum(r['status']=='SKIP' for r in results)} skip → {doc['overall']}")
|
||||
c = lambda st: sum(r["status"] == st for r in results)
|
||||
print(f"\nresults.json: {c('PASS')} pass, {c('FAIL')} fail, {c('SKIP')} skip, "
|
||||
f"{c('XFAIL')} xfail, {c('XPASS')} xpass → {doc['overall']}")
|
||||
PY
|
||||
|
||||
# ── Optional PDF ─────────────────────────────────────────────────────────────
|
||||
# ── Unit tests + coverage ────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo "── Unit tests + coverage ──"
|
||||
|
||||
# Optional C++ line coverage: rebuild the project's libraries + GTest with gcov
|
||||
# instrumentation in place (OPTIM/LFLAGS are the MARTe2-sanctioned override
|
||||
# hooks), let collect.py run the instrumented GTest (emits .gcda) and lcov, then
|
||||
# restore a clean build so later --skip-build runs aren't left instrumented.
|
||||
CPP_COV_FLAG=""
|
||||
if [ "${CPP_COV}" -eq 1 ]; then
|
||||
echo " building instrumented (gcov) libraries + GTest ..."
|
||||
COV_O="--coverage"
|
||||
COV_L="-Wl,--no-as-needed -fPIC --coverage"
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc clean >/dev/null 2>&1 || true
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc core TARGET="${TARGET}" \
|
||||
OPTIM="${COV_O}" LFLAGS="${COV_L}" 2>&1 | tail -1
|
||||
for d in Test/Components/DataSources/UDPStreamer Test/Applications/StreamHub Test/GTest; do
|
||||
make -C "${REPO_ROOT}/${d}" -f Makefile.gcc TARGET="${TARGET}" \
|
||||
OPTIM="${COV_O}" LFLAGS="${COV_L}" 2>&1 | tail -1
|
||||
done
|
||||
CPP_COV_FLAG="--cpp-coverage"
|
||||
fi
|
||||
|
||||
${PY} "${SCRIPT_DIR}/collect.py" --repo "${REPO_ROOT}" --target "${TARGET}" \
|
||||
--out "${OUT_DIR}" --work "${WORK}" ${CPP_COV_FLAG} || true
|
||||
|
||||
if [ "${CPP_COV}" -eq 1 ]; then
|
||||
echo " restoring non-instrumented build ..."
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc clean >/dev/null 2>&1 || true
|
||||
make -C "${REPO_ROOT}" -f Makefile.gcc core apps TARGET="${TARGET}" 2>&1 | tail -1
|
||||
(cd "${SCRIPT_DIR}/client" && go build -o chain-client . >/dev/null 2>&1) || true
|
||||
fi
|
||||
|
||||
# ── Consolidated report data (+ history/regression + trend plots) ────────────
|
||||
${PY} "${SCRIPT_DIR}/report_build.py" --repo "${REPO_ROOT}" \
|
||||
--results "${OUT_DIR}/results.json" --work "${WORK}" --out "${OUT_DIR}" || true
|
||||
|
||||
# ── PDF ──────────────────────────────────────────────────────────────────────
|
||||
if command -v typst >/dev/null 2>&1 && [ -f "${SCRIPT_DIR}/E2E_Report.typ" ]; then
|
||||
cp "${SCRIPT_DIR}/E2E_Report.typ" "${OUT_DIR}/" 2>/dev/null || true
|
||||
(cd "${OUT_DIR}" && typst compile E2E_Report.typ E2E_Report.pdf 2>/dev/null) \
|
||||
&& echo "PDF: ${OUT_DIR}/E2E_Report.pdf"
|
||||
# Embedded waveform overviews live in WORK; the template references them by
|
||||
# bare name, so stage them next to report_data.json before compiling.
|
||||
cp "${WORK}"/wave_*.png "${OUT_DIR}/" 2>/dev/null || true
|
||||
if (cd "${OUT_DIR}" && typst compile E2E_Report.typ E2E_Report.pdf); then
|
||||
echo "PDF: ${OUT_DIR}/E2E_Report.pdf"
|
||||
else
|
||||
echo "typst compile failed (report_data.json present at ${OUT_DIR})"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Done — artifacts in ${OUT_DIR} and ${WORK}"
|
||||
|
||||
Reference in New Issue
Block a user