def test_parse_error_from_xml_parse_error(self):
     error = XmlParseError('xml parse error')
     error.code = 123
     error.position = (1, 2)
     actual = ParseError.from_exception('file', error)
     expected = ParseError('file', 'xml parse error', 1, 2)
     self.assertEqual(expected, actual)
 def test_parse_junit_xml_files_with_non_existing_file(self):
     self.assertEqual(
         parse_junit_xml_files(['files/does_not_exist.xml']),
         ParsedUnitTestResults(
             cases=[],
             files=1,
             errors=[ParseError('files/does_not_exist.xml', 'File does not exist.', None, None)],
             suite_errors=0,
             suite_failures=0,
             suite_skipped=0,
             suite_tests=0,
             suite_time=0,
             suites=0
         ))
 def test_parse_junit_xml_files_with_non_junit_file(self):
     self.assertEqual(
         parse_junit_xml_files(['files/non-junit.xml']),
         ParsedUnitTestResults(
             files=1,
             errors=[ParseError(file='files/non-junit.xml', message='Invalid format.', line=None, column=None)],
             suites=0,
             suite_tests=0,
             suite_skipped=0,
             suite_failures=0,
             suite_errors=0,
             suite_time=0,
             cases=[]
         ))
 def test_parse_junit_xml_files_with_corrupt_xml_file(self):
     self.assertEqual(
         parse_junit_xml_files(['files/corrupt-xml.xml']),
         ParsedUnitTestResults(
             files=1,
             errors=[ParseError(file='files/corrupt-xml.xml', message='File is not a valid XML file:\nno element found: line 11, column 21', line=11, column=21)],
             suites=0,
             suite_tests=0,
             suite_skipped=0,
             suite_failures=0,
             suite_errors=0,
             suite_time=0,
             cases=[]
         ))
 def test_parse_junit_xml_files_with_non_xml_file(self):
     self.assertEqual(
         parse_junit_xml_files(['files/non-xml.xml']),
         ParsedUnitTestResults(
             files=1,
             errors=[ParseError(file='files/non-xml.xml', message='File is not a valid XML file:\nsyntax error: line 1, column 0', line=1, column=0)],
             suites=0,
             suite_tests=0,
             suite_skipped=0,
             suite_failures=0,
             suite_errors=0,
             suite_time=0,
             cases=[]
         ))
 def test_parse_junit_xml_files_with_empty_file(self):
     self.assertEqual(
         parse_junit_xml_files(['files/empty.xml']),
         ParsedUnitTestResults(
             cases=[],
             files=1,
             errors=[ParseError('files/empty.xml', 'File is empty.', None, None)],
             suite_errors=0,
             suite_failures=0,
             suite_skipped=0,
             suite_tests=0,
             suite_time=0,
             suites=0
         ))
Пример #7
0
 def test_get_conclusion_parse_errors(self):
     for fail_on_errors in [True, False]:
         for fail_on_failures in [True, False]:
             with self.subTest(fail_on_errors=fail_on_errors, fail_on_failures=fail_on_failures):
                 actual = get_conclusion(ParsedUnitTestResults(
                     files=2,
                     errors=[ParseError(file='file', message='error', line=None, column=None)],
                     suites=1,
                     suite_tests=4,
                     suite_skipped=1,
                     suite_failures=0,
                     suite_errors=0,
                     suite_time=10,
                     cases=[]
                 ), fail_on_errors=fail_on_errors, fail_on_failures=fail_on_failures)
                 self.assertEqual('failure' if fail_on_errors else 'success', actual)
Пример #8
0
def parse_junit_xml_files(files: Iterable[str]) -> ParsedUnitTestResults:
    """Parses junit xml files and returns aggregated statistics as a ParsedUnitTestResults."""
    def parse(path: str) -> Union[str, Any]:
        if not os.path.exists(path):
            return FileNotFoundError(f'File does not exist.')
        if os.stat(path).st_size == 0:
            return Exception(f'File is empty.')

        try:
            return JUnitXml.fromfile(path)
        except BaseException as e:
            return e

    parsed_files = [(result_file, parse(result_file)) for result_file in files]
    junits = [(result_file, junit) for result_file, junit in parsed_files
              if not isinstance(junit, BaseException)]
    errors = [
        ParseError.from_exception(result_file, exception)
        for result_file, exception in parsed_files
        if isinstance(exception, BaseException)
    ]

    suites = [(result_file, suite) for result_file, junit in junits
              for suite in (junit if junit._tag == "testsuites" else [junit])]
    suite_tests = sum([suite.tests for result_file, suite in suites])
    suite_skipped = sum(
        [suite.skipped + suite.disabled for result_file, suite in suites])
    suite_failures = sum([suite.failures for result_file, suite in suites])
    suite_errors = sum([suite.errors for result_file, suite in suites])
    suite_time = int(sum([suite.time for result_file, suite in suites]))

    def int_opt(string: Optional[str]) -> Optional[int]:
        try:
            return int(string) if string else None
        except ValueError:
            return None

    def get_cases(suite: TestSuite) -> List[TestCase]:
        """
        JUnit seems to allow for testsuite tags inside testsuite tags, potentially at any depth.
        https://llg.cubic.org/docs/junit/

        This skips all inner testsuite tags and returns a list of all contained testcase tags.
        """
        suites = list(suite.iterchildren(TestSuite))
        cases = list(suite.iterchildren(TestCase))
        return [case for suite in suites for case in get_cases(suite)] + cases

    cases = [
        UnitTestCase(result_file=result_file,
                     test_file=case._elem.get('file'),
                     line=int_opt(case._elem.get('line')),
                     class_name=case.classname,
                     test_name=case.name,
                     result=get_result(results),
                     message=get_message(results),
                     content=get_content(results),
                     time=case.time) for result_file, suite in suites
        for case in get_cases(suite)
        if case.classname is not None or case.name is not None
        for results in [get_results(case.result, case.status)]
    ]

    return ParsedUnitTestResults(
        files=len(parsed_files),
        errors=errors,
        # test state counts from suites
        suites=len(suites),
        suite_tests=suite_tests,
        suite_skipped=suite_skipped,
        suite_failures=suite_failures,
        suite_errors=suite_errors,
        suite_time=suite_time,
        # test cases
        cases=cases)
    def test_get_stats_delta(self):
        self.assertEqual(get_stats_delta(UnitTestRunResults(
            files=1,
            errors=errors,
            suites=2,
            duration=3,

            tests=20,
            tests_succ=2,
            tests_skip=5,
            tests_fail=6,
            tests_error=7,

            runs=40,
            runs_succ=12,
            runs_skip=8,
            runs_fail=9,
            runs_error=10,

            commit='commit'
        ), UnitTestRunResults(
            files=3,
            errors=[ParseError('other file', 'other error', None, None)],
            suites=5,
            duration=7,

            tests=41,
            tests_succ=5,
            tests_skip=11,
            tests_fail=13,
            tests_error=15,

            runs=81,
            runs_succ=25,
            runs_skip=17,
            runs_fail=19,
            runs_error=21,

            commit='ref'
        ), 'type'), UnitTestRunDeltaResults(
            files=n(1, -2),
            errors=errors,
            suites=n(2, -3),
            duration=d(3, -4),

            tests=n(20, -21),
            tests_succ=n(2, -3),
            tests_skip=n(5, -6),
            tests_fail=n(6, -7),
            tests_error=n(7, -8),

            runs=n(40, -41),
            runs_succ=n(12, -13),
            runs_skip=n(8, -9),
            runs_fail=n(9, -10),
            runs_error=n(10, -11),

            commit='commit',
            reference_commit='ref',
            reference_type='type'
        ))
 def test_parse_error_from_error(self):
     actual = ParseError.from_exception('file', ValueError('error'))
     expected = ParseError('file', 'error', None, None)
     self.assertEqual(expected, actual)
 def test_parse_error_from_file_not_found(self):
     error = FileNotFoundError(2, 'No such file or directory')
     error.filename = 'some file path'
     actual = ParseError.from_exception('file', error)
     expected = ParseError('file', "[Errno 2] No such file or directory: 'some file path'", None, None)
     self.assertEqual(expected, actual)
import unittest
from xml.etree.ElementTree import ParseError as XmlParseError

from publish.unittestresults import get_test_results, get_stats, get_stats_delta, \
    ParsedUnitTestResults, ParsedUnitTestResultsWithCommit, \
    UnitTestCase, UnitTestResults, UnitTestCaseResults, \
    UnitTestRunResults, UnitTestRunDeltaResults, ParseError
from test import d, n

errors = [ParseError('file', 'error', None, None)]


class TestUnitTestResults(unittest.TestCase):

    def test_parse_error_from_xml_parse_error(self):
        error = XmlParseError('xml parse error')
        error.code = 123
        error.position = (1, 2)
        actual = ParseError.from_exception('file', error)
        expected = ParseError('file', 'xml parse error', 1, 2)
        self.assertEqual(expected, actual)

    def test_parse_error_from_file_not_found(self):
        error = FileNotFoundError(2, 'No such file or directory')
        error.filename = 'some file path'
        actual = ParseError.from_exception('file', error)
        expected = ParseError('file', "[Errno 2] No such file or directory: 'some file path'", None, None)
        self.assertEqual(expected, actual)

    def test_parse_error_from_error(self):
        actual = ParseError.from_exception('file', ValueError('error'))