diff --git a/.ci/generate_test_report_lib.py b/.ci/generate_test_report_lib.py
index 36c95852452ac..7820fbda803d7 100644
--- a/.ci/generate_test_report_lib.py
+++ b/.ci/generate_test_report_lib.py
@@ -41,10 +41,12 @@ def _parse_ninja_log(ninja_log: list[str]) -> list[tuple[str, str]]:
# touch test/4.stamp
#
# index will point to the line that starts with Failed:. The progress
- # indicator is the line before this ([4/5] test/4.stamp) and contains a pretty
- # printed version of the target being built (test/4.stamp). We use this line
- # and remove the progress information to get a succinct name for the target.
- failing_action = ninja_log[index - 1].split("] ")[1]
+ # indicator is sometimes the line before this ([4/5] test/4.stamp) and
+ # will contain a pretty printed version of the target being built
+ # (test/4.stamp) when accurate. We instead parse the failed line rather
+ # than the progress indicator as the progress indicator may not be
+ # aligned with the failure.
+ failing_action = ninja_log[index].split("FAILED: ")[1]
failure_log = []
while (
index < len(ninja_log)
diff --git a/.ci/generate_test_report_lib_test.py b/.ci/generate_test_report_lib_test.py
index a8659e1d6a3e3..a8991f139e055 100644
--- a/.ci/generate_test_report_lib_test.py
+++ b/.ci/generate_test_report_lib_test.py
@@ -39,7 +39,7 @@ def test_find_failure_ninja_logs(self):
self.assertEqual(
failures[0],
(
- "test/4.stamp",
+ "touch test/4.stamp",
dedent(
"""\
FAILED: touch test/4.stamp
@@ -77,7 +77,7 @@ def test_ninja_log_end(self):
self.assertEqual(
failures[0],
(
- "test/3.stamp",
+ "touch test/3.stamp",
dedent(
"""\
FAILED: touch test/3.stamp
@@ -106,7 +106,7 @@ def test_ninja_log_multiple_failures(self):
self.assertEqual(
failures[0],
(
- "test/2.stamp",
+ "touch test/2.stamp",
dedent(
"""\
FAILED: touch test/2.stamp
@@ -117,7 +117,7 @@ def test_ninja_log_multiple_failures(self):
self.assertEqual(
failures[1],
(
- "test/4.stamp",
+ "touch test/4.stamp",
dedent(
"""\
FAILED: touch test/4.stamp
@@ -150,7 +150,7 @@ def test_ninja_log_runtimes_failure(self):
self.assertEqual(
failures[0],
(
- "test/2.stamp",
+ "touch test/2.stamp",
dedent(
"""\
FAILED: touch test/2.stamp
@@ -159,6 +159,34 @@ def test_ninja_log_runtimes_failure(self):
),
)
+ # Test that we correctly handle cases where the FAILED: line does not
+ # match up with the progress indicator.
+ def test_ninja_log_mismatched_failed(self):
+ failures = generate_test_report_lib.find_failure_in_ninja_logs(
+ [
+ [
+ "[1/5] test/1.stamp",
+ "[2/5] test/2.stamp",
+ "ModuleNotFoundError: No module named 'mount_langley'",
+ "FAILED: tools/check-langley",
+ "Wow! This system is really broken!",
+ "[5/5] test/5.stamp",
+ ]
+ ]
+ )
+ self.assertEqual(len(failures), 1)
+ self.assertEqual(
+ failures[0],
+ (
+ "tools/check-langley",
+ dedent(
+ """\
+ FAILED: tools/check-langley
+ Wow! This system is really broken!"""
+ ),
+ ),
+ )
+
def test_title_only(self):
self.assertEqual(
generate_test_report_lib.generate_report("Foo", 0, [], []),
@@ -449,7 +477,7 @@ def test_no_failures_multiple_build_failed_ninja_log(self):
All tests passed but another part of the build **failed**. Click on a failure below to see the details.
- test/2.stamp
+ touch test/2.stamp
```
FAILED: touch test/2.stamp
@@ -457,7 +485,7 @@ def test_no_failures_multiple_build_failed_ninja_log(self):
```
- test/4.stamp
+ touch test/4.stamp
```
FAILED: touch test/4.stamp