# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# To run these tests:
# python -m unittest generate_test_report_lib_test.py
import unittest
from io import StringIO
from textwrap import dedent
import tempfile
import os
from junitparser import JUnitXml
import generate_test_report_lib
def junit_from_xml(xml):
return JUnitXml.fromfile(StringIO(xml))
class TestReports(unittest.TestCase):
def test_find_failure_ninja_logs(self):
failures = generate_test_report_lib.find_failure_in_ninja_logs(
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: touch test/4.stamp",
"Wow! This system is really broken!",
"[5/5] test/5.stamp",
],
]
)
self.assertEqual(len(failures), 1)
self.assertEqual(
failures[0],
(
"test/4.stamp",
dedent(
"""\
FAILED: touch test/4.stamp
Wow! This system is really broken!"""
),
),
)
def test_no_failure_ninja_log(self):
failures = generate_test_report_lib.find_failure_in_ninja_logs(
[
[
"[1/3] test/1.stamp",
"[2/3] test/2.stamp",
"[3/3] test/3.stamp",
]
]
)
self.assertEqual(failures, [])
def test_ninja_log_end(self):
failures = generate_test_report_lib.find_failure_in_ninja_logs(
[
[
"[1/3] test/1.stamp",
"[2/3] test/2.stamp",
"[3/3] test/3.stamp",
"FAILED: touch test/3.stamp",
"Wow! This system is really broken!",
"ninja: build stopped: subcommand failed.",
]
]
)
self.assertEqual(len(failures), 1)
self.assertEqual(
failures[0],
(
"test/3.stamp",
dedent(
"""\
FAILED: touch test/3.stamp
Wow! This system is really broken!"""
),
),
)
def test_ninja_log_multiple_failures(self):
failures = generate_test_report_lib.find_failure_in_ninja_logs(
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"FAILED: touch test/2.stamp",
"Wow! This system is really broken!",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: touch test/4.stamp",
"Wow! This system is maybe broken!",
"[5/5] test/5.stamp",
]
]
)
self.assertEqual(len(failures), 2)
self.assertEqual(
failures[0],
(
"test/2.stamp",
dedent(
"""\
FAILED: touch test/2.stamp
Wow! This system is really broken!"""
),
),
)
self.assertEqual(
failures[1],
(
"test/4.stamp",
dedent(
"""\
FAILED: touch test/4.stamp
Wow! This system is maybe broken!"""
),
),
)
def test_title_only(self):
self.assertEqual(
generate_test_report_lib.generate_report("Foo", 0, [], []),
dedent(
"""\
# Foo
The build succeeded and no tests ran. This is expected in some build configurations."""
),
)
def test_title_only_failure(self):
self.assertEqual(
generate_test_report_lib.generate_report("Foo", 1, [], []),
dedent(
"""\
# Foo
The build failed before running any tests. Detailed information about the build failure could not be automatically obtained.
Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
),
)
def test_title_only_failure_ninja_log(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[],
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: test/4.stamp",
"touch test/4.stamp",
"Wow! Risk!",
"[5/5] test/5.stamp",
]
],
),
dedent(
"""\
# Foo
The build failed before running any tests. Click on a failure below to see the details.
test/4.stamp
```
FAILED: test/4.stamp
touch test/4.stamp
Wow! Risk!
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
),
)
def test_no_tests_in_testsuite(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
),
dedent(
"""\
# Foo
The build failed before running any tests. Detailed information about the build failure could not be automatically obtained.
Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
),
)
def test_no_failures(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
0,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
),
(
dedent(
"""\
# Foo
* 1 test passed"""
)
),
)
def test_no_failures_build_failed(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
),
(
dedent(
"""\
# Foo
* 1 test passed
All tests passed but another part of the build **failed**. Information about the build failure could not be automatically obtained.
Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_no_failures_build_failed_ninja_log(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: test/4.stamp",
"touch test/4.stamp",
"Wow! Close To You!",
"[5/5] test/5.stamp",
]
],
),
(
dedent(
"""\
# Foo
* 1 test passed
All tests passed but another part of the build **failed**. Click on a failure below to see the details.
test/4.stamp
```
FAILED: test/4.stamp
touch test/4.stamp
Wow! Close To You!
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_no_failures_multiple_build_failed_ninja_log(self):
test = generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"FAILED: touch test/2.stamp",
"Wow! Be Kind!",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: touch test/4.stamp",
"Wow! I Dare You!",
"[5/5] test/5.stamp",
]
],
)
print(test)
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[
[
"[1/5] test/1.stamp",
"[2/5] test/2.stamp",
"FAILED: touch test/2.stamp",
"Wow! Be Kind!",
"[3/5] test/3.stamp",
"[4/5] test/4.stamp",
"FAILED: touch test/4.stamp",
"Wow! I Dare You!",
"[5/5] test/5.stamp",
]
],
),
(
dedent(
"""\
# Foo
* 1 test passed
All tests passed but another part of the build **failed**. Click on a failure below to see the details.
test/2.stamp
```
FAILED: touch test/2.stamp
Wow! Be Kind!
```
test/4.stamp
```
FAILED: touch test/4.stamp
Wow! I Dare You!
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_report_single_file_single_testsuite(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
),
(
dedent(
"""\
# Foo
* 1 test passed
* 1 test skipped
* 2 tests failed
## Failed Tests
(click on a test name to see its output)
### Bar
Bar/test_3/test_3
```
Output goes here
```
Bar/test_4/test_4
```
Other output goes here
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
MULTI_SUITE_OUTPUT = dedent(
"""\
# ABC and DEF
* 1 test passed
* 1 test skipped
* 2 tests failed
## Failed Tests
(click on a test name to see its output)
### ABC
ABC/test_2/test_2
```
ABC/test_2 output goes here
```
### DEF
DEF/test_2/test_2
```
DEF/test_2 output goes here
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
def test_report_single_file_multiple_testsuites(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"ABC and DEF",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
),
self.MULTI_SUITE_OUTPUT,
)
def test_report_multiple_files_multiple_testsuites(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"ABC and DEF",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
),
junit_from_xml(
dedent(
"""\
"""
)
),
],
[],
),
self.MULTI_SUITE_OUTPUT,
)
def test_report_dont_list_failures(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
list_failures=False,
),
(
dedent(
"""\
# Foo
* 1 test failed
Failed tests and their output was too large to report. Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_report_dont_list_failures_link_to_log(self):
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
"""
)
)
],
[],
list_failures=False,
),
(
dedent(
"""\
# Foo
* 1 test failed
Failed tests and their output was too large to report. Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_report_size_limit(self):
test_output = "f" * 1000
self.assertEqual(
generate_test_report_lib.generate_report(
"Foo",
1,
[
junit_from_xml(
dedent(
"""\
""".format(
output=test_output
)
)
)
],
[],
size_limit=512,
),
(
dedent(
"""\
# Foo
* 1 test failed
Failed tests and their output was too large to report. Download the build's log file to see the details.
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
)
),
)
def test_generate_report_end_to_end(self):
with tempfile.TemporaryDirectory() as temp_dir:
junit_xml_file = os.path.join(temp_dir, "junit.xml")
with open(junit_xml_file, "w") as junit_xml_handle:
junit_xml_handle.write(
dedent(
"""\
"""
)
)
ninja_log_file = os.path.join(temp_dir, "ninja.log")
with open(ninja_log_file, "w") as ninja_log_handle:
ninja_log_handle.write(
dedent(
"""\
[1/5] test/1.stamp
[2/5] test/2.stamp
[3/5] test/3.stamp
[4/5] test/4.stamp
FAILED: test/4.stamp
touch test/4.stamp
Wow! That's so True!
[5/5] test/5.stamp"""
)
)
self.assertEqual(
generate_test_report_lib.generate_report_from_files(
"Foo", 1, [junit_xml_file, ninja_log_file]
),
dedent(
"""\
# Foo
* 1 test passed
All tests passed but another part of the build **failed**. Click on a failure below to see the details.
test/4.stamp
```
FAILED: test/4.stamp
touch test/4.stamp
Wow! That's so True!
```
If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the `infrastructure` label."""
),
)