| # Copyright 2026 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import json |
| import os |
| import tempfile |
| import unittest |
| |
| from summary import BuildResult |
| from summary import parse_suggestions_from_output |
| from summary import RunSummary |
| from summary import Suggestion |
| from summary import TestResult |
| |
| |
| class TestSummary(unittest.TestCase): |
| def test_run_summary_passed(self) -> None: |
| summary = RunSummary() |
| summary.build = BuildResult(status="PASSED") |
| summary.add_test( |
| TestResult( |
| name="host_x64/test1", |
| type="host", |
| outcome="PASSED", |
| log_path="/tmp/logs/test1.stdout.log", |
| stdout_log_path="/tmp/logs/test1.stdout.log", |
| stderr_log_path="/tmp/logs/test1.stderr.log", |
| duration_seconds=1.5, |
| ) |
| ) |
| summary.finalize() |
| |
| self.assertEqual(summary.outcome, "PASSED") |
| self.assertEqual(summary.total_passed, 1) |
| self.assertEqual(summary.total_failed, 0) |
| self.assertEqual(summary.total_skipped, 0) |
| |
| data = summary.to_dict() |
| self.assertEqual(data["outcome"], "PASSED") |
| self.assertEqual(len(data["tests"]), 1) |
| self.assertEqual(data["tests"][0]["name"], "host_x64/test1") |
| self.assertEqual(data["tests"][0]["outcome"], "PASSED") |
| self.assertEqual( |
| data["tests"][0]["log_path"], "/tmp/logs/test1.stdout.log" |
| ) |
| self.assertEqual( |
| data["tests"][0]["stdout_log_path"], "/tmp/logs/test1.stdout.log" |
| ) |
| self.assertEqual( |
| data["tests"][0]["stderr_log_path"], "/tmp/logs/test1.stderr.log" |
| ) |
| |
| def test_run_summary_failed_test(self) -> None: |
| summary = RunSummary() |
| summary.build = BuildResult(status="PASSED") |
| summary.add_test( |
| TestResult( |
| name="host_x64/test1", |
| type="host", |
| outcome="PASSED", |
| log_path="/tmp/logs/test1.log", |
| ) |
| ) |
| summary.add_test( |
| TestResult( |
| name="fuchsia-pkg://fuchsia.com/test2#meta/test2.cm", |
| type="device", |
| outcome="FAILED", |
| log_path="/tmp/logs/test2.log", |
| message="Assertion failed", |
| ) |
| ) |
| summary.finalize() |
| |
| self.assertEqual(summary.outcome, "FAILED") |
| self.assertEqual(summary.total_passed, 1) |
| self.assertEqual(summary.total_failed, 1) |
| self.assertEqual(summary.total_skipped, 0) |
| |
| def test_run_summary_build_failed(self) -> None: |
| summary = RunSummary() |
| summary.build = BuildResult( |
| status="FAILED", |
| log_path="/tmp/logs/build.log", |
| error="Compiler error in file.cc", |
| ) |
| summary.finalize() |
| |
| self.assertEqual(summary.outcome, "BUILD_FAILED") |
| self.assertEqual(summary.total_passed, 0) |
| self.assertEqual(summary.total_failed, 0) |
| |
| data = summary.to_dict() |
| self.assertEqual(data["outcome"], "BUILD_FAILED") |
| self.assertIsNotNone(data.get("build")) |
| self.assertEqual(data["build"]["status"], "FAILED") |
| self.assertEqual(data["build"]["log_path"], "/tmp/logs/build.log") |
| |
| def test_write_to_file(self) -> None: |
| with tempfile.TemporaryDirectory() as td: |
| target_path = os.path.join(td, "sub", "summary.json") |
| summary = RunSummary() |
| summary.add_test( |
| TestResult( |
| name="host_x64/test1", |
| type="host", |
| outcome="PASSED", |
| ) |
| ) |
| summary.finalize() |
| summary.write_to_file(target_path) |
| |
| self.assertTrue(os.path.exists(target_path)) |
| with open(target_path, "r", encoding="utf-8") as f: |
| loaded = json.load(f) |
| self.assertEqual(loaded["outcome"], "PASSED") |
| self.assertEqual( |
| loaded["summary_path"], os.path.abspath(target_path) |
| ) |
| |
| def test_run_summary_with_structured_suggestions(self) -> None: |
| summary = RunSummary() |
| summary.suggestions = [ |
| Suggestion( |
| name="summary_test", |
| similarity=0.8889, |
| build_includes="host_x64/obj/scripts/fxtest/python/summary_test.sh", |
| ), |
| Suggestion( |
| name="system-updater-tests", |
| similarity=0.7698, |
| add_test_command="fx add-test //src/sys/pkg/bin/system-updater:system-updater-tests", |
| ), |
| ] |
| summary.finalize(error="No tests found matching criteria") |
| |
| self.assertEqual(summary.outcome, "ERROR") |
| data = summary.to_dict() |
| self.assertEqual(data["outcome"], "ERROR") |
| self.assertEqual(data["error"], "No tests found matching criteria") |
| self.assertIn("suggestions", data) |
| self.assertEqual(len(data["suggestions"]), 2) |
| self.assertEqual(data["suggestions"][0]["name"], "summary_test") |
| self.assertEqual(data["suggestions"][0]["similarity"], 0.8889) |
| self.assertEqual( |
| data["suggestions"][0]["build_includes"], |
| "host_x64/obj/scripts/fxtest/python/summary_test.sh", |
| ) |
| self.assertEqual( |
| data["suggestions"][1]["add_test_command"], |
| "fx add-test //src/sys/pkg/bin/system-updater:system-updater-tests", |
| ) |
| |
| def test_run_summary_hints(self) -> None: |
| summary = RunSummary() |
| summary.hints = [ |
| "To debug with fx debug cli: fx test --agent-debugging-mode host_x64/test1" |
| ] |
| summary.finalize() |
| |
| data = summary.to_dict() |
| self.assertIn("hints", data) |
| self.assertEqual(len(data["hints"]), 1) |
| self.assertEqual( |
| data["hints"][0], |
| "To debug with fx debug cli: fx test --agent-debugging-mode host_x64/test1", |
| ) |
| |
| md = summary.to_markdown() |
| self.assertIn("## Hints", md) |
| self.assertIn( |
| "- To debug with fx debug cli: fx test --agent-debugging-mode host_x64/test1", |
| md, |
| ) |
| |
| def test_parse_suggestions_from_output(self) -> None: |
| raw_output = """summary_test (88.89% similar) |
| Build includes: host_x64/obj/scripts/fxtest/python/summary_test.sh |
| system-update-committer-tests (77.66% similar) |
| fx add-test //src/sys/pkg/bin/system-update-committer:system-update-committer-tests |
| (6 more matches not shown)""" |
| |
| suggestions = parse_suggestions_from_output(raw_output) |
| self.assertEqual(len(suggestions), 2) |
| self.assertEqual(suggestions[0].name, "summary_test") |
| self.assertEqual(suggestions[0].similarity, 0.8889) |
| self.assertEqual( |
| suggestions[0].build_includes, |
| "host_x64/obj/scripts/fxtest/python/summary_test.sh", |
| ) |
| self.assertEqual(suggestions[1].name, "system-update-committer-tests") |
| self.assertEqual(suggestions[1].similarity, 0.7766) |
| self.assertEqual( |
| suggestions[1].add_test_command, |
| "fx add-test //src/sys/pkg/bin/system-update-committer:system-update-committer-tests", |
| ) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |