Skip to content

Commit ac8a5b5

Browse files
committed
Separate test jobs by chapter. Also see if I can construct a test dashboard.
1 parent 8fcdb98 commit ac8a5b5

File tree

5 files changed

+166
-26
lines changed

5 files changed

+166
-26
lines changed
Lines changed: 166 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Run all book tests
1+
name: Run all book tests (matrix, per chapter)
22

33
on:
44
# Automatically run this action when a new push is made to repo
@@ -13,11 +13,54 @@ on:
1313
workflow_dispatch:
1414

1515
jobs:
16-
my-job:
17-
name: Run tests
16+
book-tests:
17+
name: Run ${{ matrix.chapter }} tests
1818
runs-on: ubuntu-latest
19+
20+
strategy:
21+
fail-fast: false # keep running other chapters if one fails
22+
matrix:
23+
include:
24+
- chapter: Chapter02
25+
test_folder: test/book/chapter02
26+
products: >
27+
Image_Processing_Toolbox
28+
MATLAB
29+
Navigation_Toolbox
30+
Symbolic_Math_Toolbox
31+
junit: test-results/Chapter02.xml
32+
cobertura: code-coverage/Chapter02.xml
33+
34+
- chapter: Chapter03
35+
test_folder: test/book/chapter03
36+
products: >
37+
MATLAB
38+
Robotics_System_Toolbox
39+
junit: test-results/Chapter03.xml
40+
cobertura: code-coverage/Chapter03.xml
41+
42+
# Automated_Driving_Toolbox
43+
# Computer_Vision_Toolbox
44+
# Control_System_Toolbox
45+
# Deep_Learning_Toolbox
46+
# Image_Processing_Toolbox
47+
# MATLAB
48+
# Model_Predictive_Control_Toolbox
49+
# Navigation_Toolbox
50+
# Optimization_Toolbox
51+
# Parallel_Computing_Toolbox
52+
# Simulink
53+
# Robotics_System_Toolbox
54+
# ROS_Toolbox
55+
# Signal_Processing_Toolbox
56+
# Statistics_and_Machine_Learning_Toolbox
57+
# Symbolic_Math_Toolbox
58+
# UAV_Toolbox
59+
# ...one row per tChapterXX.m
60+
61+
1962
steps:
20-
- name: Check out RVC3-MATLAB repository (for unit tests)
63+
- name: Check out RVC3-MATLAB repository
2164
uses: actions/checkout@v4
2265
- run: echo "The ${{ github.repository }} repository has been cloned to the runner."
2366

@@ -42,24 +85,9 @@ jobs:
4285
# Use v2 for Java Swing access
4386
uses: matlab-actions/setup-matlab@v2
4487
with:
45-
products: >
46-
Automated_Driving_Toolbox
47-
Computer_Vision_Toolbox
48-
Control_System_Toolbox
49-
Deep_Learning_Toolbox
50-
Image_Processing_Toolbox
51-
MATLAB
52-
Model_Predictive_Control_Toolbox
53-
Navigation_Toolbox
54-
Optimization_Toolbox
55-
Parallel_Computing_Toolbox
56-
Simulink
57-
Robotics_System_Toolbox
58-
ROS_Toolbox
59-
Signal_Processing_Toolbox
60-
Statistics_and_Machine_Learning_Toolbox
61-
Symbolic_Math_Toolbox
62-
UAV_Toolbox
88+
# Define products for each chapter in strategy matrix above
89+
products: ${{ matrix.products }}
90+
6391
# Run tests with prerelease as soon as available; switch to GR once it's live
6492
release: latest-including-prerelease
6593

@@ -68,12 +96,124 @@ jobs:
6896
with:
6997
command: ver; exit;
7098

71-
- name: Run MATLAB Tests
72-
# Only run tests in folder test/book
99+
- name: Run MATLAB Tests for ${{ matrix.chapter }}
73100
uses: matlab-actions/run-tests@v2
74101
with:
75-
select-by-folder: test/book
102+
# Only tests for this chapter
103+
select-by-folder: ${{ matrix.test_folder }}
104+
105+
# Per-chapter logs
106+
test-results-junit: ${{ matrix.junit }}
107+
code-coverage-cobertura: ${{ matrix.cobertura }}
108+
109+
source-folder: toolbox; toolbox/internal; test/book/base
76110
startup-options: -webfigures
77-
code-coverage-cobertura: code-coverage/coverage.xml
78111
# Run tests in parallel. Requires Parallel_Computing_Toolbox in "products" list above
79112
use-parallel: false
113+
114+
- name: Upload logs and coverage for ${{ matrix.chapter }}
115+
if: always()
116+
uses: actions/upload-artifact@v4
117+
with:
118+
name: book-${{ matrix.chapter }}
119+
path: |
120+
${{ matrix.junit }}
121+
${{ matrix.cobertura }}
122+
123+
test-dashboard:
124+
name: Book test dashboard
125+
needs: book-tests
126+
runs-on: ubuntu-latest
127+
if: always() # run even if some chapter jobs failed
128+
129+
steps:
130+
- name: Download all test artifacts
131+
uses: actions/download-artifact@v4
132+
with:
133+
path: artifacts # everything ends up under ./artifacts/
134+
135+
- name: Summarize JUnit failures into run summary
136+
run: |
137+
python - << 'PY'
138+
import os
139+
import pathlib
140+
import xml.etree.ElementTree as ET
141+
142+
artifacts_root = pathlib.Path("artifacts")
143+
144+
chapters = {} # chapter -> {"passed": bool, "failures": [..]}
145+
146+
# Look for JUnit XML files inside any artifact
147+
for junit in artifacts_root.rglob("test-results/*.xml"):
148+
chapter = junit.stem # e.g. "Chapter10"
149+
tree = ET.parse(junit)
150+
root = tree.getroot()
151+
152+
failures = []
153+
154+
# Handle both <testsuite> root and <testsuites> -> <testsuite>
155+
testsuites = []
156+
if root.tag == "testsuite":
157+
testsuites = [root]
158+
else:
159+
testsuites = list(root.iter("testsuite"))
160+
161+
for ts in testsuites:
162+
for case in ts.iter("testcase"):
163+
case_name = case.get("name", "")
164+
classname = case.get("classname", "")
165+
for failure in case.findall("failure"):
166+
msg = (failure.get("message") or "").strip()
167+
text = (failure.text or "").strip()
168+
detail = msg or text or "Test failed"
169+
failures.append({
170+
"classname": classname,
171+
"name": case_name,
172+
"detail": detail,
173+
})
174+
175+
chapters[chapter] = {
176+
"passed": len(failures) == 0,
177+
"failures": failures,
178+
}
179+
180+
lines = []
181+
lines.append("# Book Test Dashboard\n")
182+
183+
if not chapters:
184+
lines.append("_No JUnit result files found in artifacts. "
185+
"Check that the matrix jobs ran and uploaded artifacts._")
186+
else:
187+
# Sort chapters like Chapter01, Chapter02, ...
188+
for chapter in sorted(chapters.keys()):
189+
info = chapters[chapter]
190+
if info["passed"]:
191+
lines.append(f"- ✅ **{chapter}** – all tests passed")
192+
else:
193+
fails = info["failures"]
194+
lines.append(f"- ❌ **{chapter}** – {len(fails)} failing test(s)")
195+
for f in fails:
196+
name = f["name"] or "<unnamed>"
197+
cls = f["classname"] or "<no class>"
198+
detail = f["detail"].replace("\n", " ")
199+
# Keep detail short-ish
200+
if len(detail) > 160:
201+
detail = detail[:157] + "..."
202+
lines.append(
203+
f" - `{cls}.{name}` – {detail}"
204+
)
205+
206+
lines.append("\n---\n")
207+
lines.append(
208+
"🔎 For full logs and coverage for a chapter, open the "
209+
"_Run ChapterXX tests_ job and download the "
210+
"artifact named `book-ChapterXX`."
211+
)
212+
213+
summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
214+
if summary_path:
215+
with open(summary_path, "w", encoding="utf-8") as f:
216+
f.write("\n".join(lines))
217+
else:
218+
print("\\n".join(lines))
219+
PY

0 commit comments

Comments
 (0)