def parse_xml(xmlpath: Path) -> (str, float, float): """ Load junit files from xmlpath, then parse them for point values and return simplified output. """ xml = JUnitXml.fromfile(str( xmlpath.absolute() / "TEST-junit-vintage.xml")) + JUnitXml.fromfile( str(xmlpath.absolute() / "TEST-junit-jupiter.xml")) earned_points = 0 total_points = 0 output = "" for suite in xml: for case in suite: point_str = points_regex.search(case.system_out) point_val = float(point_str.groups()[0]) point_out = "" if point_str: # add point attribute to case, then determine value of test case.points = FloatAttr("points") total_points += point_val if case.result is None: case.points = point_val earned_points += point_val else: case.points = 0 point_out = f"{case.points:1g} points"
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: if drop_testcases: builder = DropTestCaseBuilder() return JUnitXml.fromfile(path, parse_func=builder.parse) return JUnitXml.fromfile(path) except BaseException as e: return e
def generate_junitxml_merged_report(test_results_dir): """ Merge all junitxml generated reports in a single one. :param test_results_dir: output dir containing the junitxml reports to merge. """ merged_xml = None for dir, _, files in os.walk(test_results_dir): for file in files: if file.endswith("results.xml"): if not merged_xml: merged_xml = JUnitXml.fromfile(os.path.join(dir, file)) else: merged_xml += JUnitXml.fromfile(os.path.join(dir, file)) merged_xml.write("{0}/test_report.xml".format(test_results_dir), pretty=True)
def generate_junitxml_merged_report(test_results_dir): """ Merge all junitxml generated reports in a single one. :param test_results_dir: output dir containing the junitxml reports to merge. """ merged_xml = None for dir, _, files in os.walk(test_results_dir): for file in files: if file.endswith("results.xml"): if not merged_xml: merged_xml = JUnitXml.fromfile(os.path.join(dir, file)) else: merged_xml += JUnitXml.fromfile(os.path.join(dir, file)) merged_xml.write("{0}/test_report.xml".format(test_results_dir), pretty=True)
def subset(client, reports): for r in reports: suite = JUnitXml.fromfile(r, parse_func) for case in suite: cls_name = case._elem.attrib.get("classname") name = case._elem.attrib.get('name') if cls_name != '' and name != '': client.test_path([{ 'type': 'class', 'name': cls_name }, { 'type': 'testcase', 'name': name }]) def formatter(x: TestPath): cls_name = '' case = '' for path in x: t = path['type'] if t == 'class': cls_name = path['name'] if t == 'testcase': case = path['name'] if cls_name != '' and case != '': return "-s '{}' -t '{}'".format(cls_name, case) return ''
def parse_results(self, result_file): result_file = self._validate_path(result_file) try: xml = JUnitXml.fromfile(result_file) except TypeError as e: raise JUnitHandlerException(e) return self._transform_tests(xml)
def analysis(): skipped = SkippedElement() failure = FailureElement() newxml = JUnitXml() for filename in os.listdir('./test_results'): # Only get xml files if not filename.endswith('.xml'): continue fullname = os.path.join('./test_results', filename) xml = JUnitXml.fromfile(fullname) newxml += xml output = [] for suite in newxml: # handle suites for testcase in suite: testcase.append(failure) testcase.child(FailureElement) for fail in testcase.iterchildren(FailureElement): detail = { "test suite": testcase.classname, "test case": testcase.name, "failure message": html_decode(fail.message) } output.append(detail) return output
def test_write_results_vulns(): """Test parsing results and writing test-output.xml""" # Open the Veracode SCA JSON results with open("example-dotnet.json", "r") as sca_results: data = json.load(sca_results) # Include all CVSS in the output parsed_data = parse_sca_json(data, 0) # Create the test-output.xml write_output("dotnet vulns", parsed_data, 0) # Get test-output.xml xml = JUnitXml.fromfile("test-output.xml") # Assert there are 15 vulnerabilities in the output case_counter = 0 for suite in xml: for case in suite: case_counter += 1 assert case_counter == 15 # Assert there are 15 failures reported in the Test Suite assert xml.failures == 15
def pytest_collection_modifyitems(session, config, items): """ Add Polarion ID property to test cases that are marked with one. """ re_trigger_failed_tests = ocsci_config.RUN.get("re_trigger_failed_tests") if re_trigger_failed_tests: junit_report = JUnitXml.fromfile(re_trigger_failed_tests) cases_to_re_trigger = [] for suite in junit_report: cases_to_re_trigger += [_case.name for _case in suite if _case.result] for item in items[:]: if re_trigger_failed_tests and item.name not in cases_to_re_trigger: log.info( f"Test case: {item.name} will be removed from execution, " "because of you provided --re-trigger-failed-tests parameter " "and this test passed in previous execution from the report!" ) items.remove(item) try: marker = item.get_closest_marker(name="polarion_id") if marker: polarion_id = marker.args[0] if polarion_id: item.user_properties.append(("polarion-testcase-id", polarion_id)) except IndexError: log.warning( f"polarion_id marker found with no value for " f"{item.name} in {item.fspath}", exc_info=True, )
def process_xml(self, path: Path) -> None: print(f"Processing {str(path)!r}") suites = JUnitXml.fromfile(path) if isinstance(suites, TestSuite): suites = [suites] for suite in suites: self.add_tests(suite)
def testcases(reports: List[str]): exceptions = [] for report in reports: try: # To understand JUnit XML format, https://llg.cubic.org/docs/junit/ is helpful # TODO: robustness: what's the best way to deal with broken XML file, if any? xml = JUnitXml.fromfile( report, self.junitxml_parse_func) if isinstance(xml, JUnitXml): testsuites = [suite for suite in xml] elif isinstance(xml, TestSuite): testsuites = [xml] else: # TODO: what is a Pythonesque way to do this? assert False for suite in testsuites: for case in suite: yield json.dumps(CaseEvent.from_case_and_suite(self.path_builder, case, suite, report)) except Exception as e: exceptions.append(Exception( "Failed to process a report file: {}".format(report), e)) if len(exceptions) > 0: # defer XML persing exceptions raise Exception(exceptions)
def __init__(self, path): """Initiates JUniXML object. Args: path (str): Path to XML file """ self.junit_results = JUnitXml.fromfile(path)
def observe_tests(self): self.test_results = {} for report in self.get_xml_files(): try: suite = JUnitXml.fromfile(report) for case in suite: test = TestResult(case, suite.name, report) self.test_results[test.full_name.lower()] = test except Exception as e: print(e, report) pass with open(self.path_to_tests_results, "w") as f: json.dump( list(map(lambda x: x.as_dict(), self.test_results.values())), f) tests = list( set( map( lambda x: x.full_name, filter(lambda t: not t.is_passed(), self.test_results.values())))) with open(self.trigger_tests_path, 'w') as f: json.dump(tests, f) if not os.path.exists(self.tests_to_exclude_path): with open(self.tests_to_exclude_path, 'w') as f: json.dump(tests, f) return self.test_results
def test_fromfile_without_testsuites_tag(self): text = """<?xml version="1.0" encoding="UTF-8"?> <testsuite name="JUnitXmlReporter.constructor" errors="0" skipped="1" tests="3" failures="1" time="0.006" timestamp="2013-05-24T10:23:58"> <properties> <property name="java.vendor" value="Sun Microsystems Inc." /> <property name="compiler.debug" value="on" /> <property name="project.jdk.classpath" value="jdk.classpath.1.6" /> </properties> <testcase classname="JUnitXmlReporter.constructor" name="should default path to an empty string" time="0.006"> <failure message="test failure">Assertion failed</failure> </testcase> <testcase classname="JUnitXmlReporter.constructor" name="should default consolidate to true" time="0"> <skipped /> </testcase> <testcase classname="JUnitXmlReporter.constructor" name="should default useDotNotation to true" time="0" /> </testsuite>""" with open(self.tmp, 'w') as f: f.write(text) xml = JUnitXml.fromfile(self.tmp) cases = list(iter(xml)) properties = list(iter(xml.properties())) self.assertEqual(len(properties), 3) self.assertEqual(len(cases), 3) self.assertEqual(xml.name, 'JUnitXmlReporter.constructor') self.assertEqual(xml.tests, 3) case_results = [Failure, Skipped, type(None)] for case, result in zip(xml, case_results): self.assertIsInstance(case.result, result)
def parse(report: str) -> Generator[CaseEventType, None, None]: # To understand JUnit XML format, https://llg.cubic.org/docs/junit/ is helpful # TODO: robustness: what's the best way to deal with broken XML file, if any? try: xml = JUnitXml.fromfile(report, f) except Exception as e: click.echo(click.style( "Warning: error reading JUnitXml file {filename}: {error}" .format(filename=report, error=e), fg="yellow"), err=True) # `JUnitXml.fromfile()` will raise `JUnitXmlError` and other lxml related errors if the file has wrong format. # https://github.com/weiwei/junitparser/blob/master/junitparser/junitparser.py#L321 return if isinstance(xml, JUnitXml): testsuites = [suite for suite in xml] elif isinstance(xml, TestSuite): testsuites = [xml] else: raise InvalidJUnitXMLException(filename=report) for suite in testsuites: for case in suite: yield CaseEvent.from_case_and_suite( self.path_builder, case, suite, report)
def main(): tmpdir = tempfile.mkdtemp(prefix='test_reports') print(tmpdir) path = 'cases' cases = os.listdir(path) for case in cases: #print(case) if case != 'c.py': continue xml_file = os.path.join(tmpdir, f"{case}.xml") cmd_list = ['pytest', os.path.join(path, case), '--junitxml', xml_file] code, stdout, stderr = qxx(cmd_list) if code != 0: print(f"Execution failed with {code}") print(stdout) print(stderr) exit(1) with open(xml_file) as fh: print(fh.read()) return xml = JUnitXml.fromfile(xml_file) for suite in xml: #print(suite) for case in suite: #print(type(case)) print(case.name) if case.result: print(case.result) if isinstance(case.result, Failure): print(' failure ', case.result.message) if isinstance(case.result, Skipped): print(' skipped ', case.result.message)
def parse_tests(xml_file_object): xml = JUnitXml.fromfile(xml_file_object) tests = [] for testcase in xml: testcase_status = _get_status(testcase) if testcase.classname != "" and testcase_status != "skipped": tests.append({"name": _get_name(testcase), "status": testcase_status}) return tests
def parse_file(path: str) -> List[TestCase]: try: return convert_junit_to_testcases(JUnitXml.fromfile(path)) except Exception as err: rich.print( f":Warning: [yellow]Warning[/yellow]: Failed to read {path}: {err}" ) return []
def junit2tabulate(junit_xml): """convert junit xml junitparser.JUnitXml object or a Junit xml to tabulate string """ if not isinstance(junit_xml, JUnitXml): if os.path.exists(junit_xml): junit_xml = JUnitXml.fromfile(junit_xml) else: return tabulate.tabulate([[header]], headers='firstrow') data = junit2array(junit_xml) return tabulate.tabulate(data, headers='firstrow', tablefmt="grid")
def process_xml(self, path: Path) -> None: if not path.exists(): return print(f"Processing {path}") suites = JUnitXml.fromfile(path) if isinstance(suites, TestSuite): suites = [suites] for suite in suites: self.add_tests(suite)
def update_results(run_id, junit_file, dryrun=False): print("Parsing {}".format(junit_file)) junit_xml = JUnitXml.fromfile(junit_file) results_to_upload = [] tests = client.test.for_run(run_id) results_to_upload = [] for suite in junit_xml: for testcase in suite: ref = testcase.name tr_case = get_case_id(tests, ref) status = None if tr_case: #pprint(tr_case) tc = testcase cr = {} cr['test_id'] = tr_case['id'] comment = "" if tc.result: if tc.result._elem.text: comment = tc.result._elem.text if tc.result.type == 'error': test_status = BLOCKED elif tc.result.type == 'skipped': test_status = SKIPPED elif tc.result.type == 'failure': test_status = FAILED else: test_status = RETEST status = tc.result.type cr['status_id'] = test_status else: cr['status_id'] = PASSED status = 'passed' print("{} => {}".format(testcase.name, status)) cr['comment'] = comment results_to_upload.append(cr) else: print("{} not found in suite".format(testcase.name)) #pprint(results_to_upload) if not dryrun: client.result.add_multiple(run_id, results_to_upload)
def get_test_suite(filename): try: ts = JUnitXml.fromfile(filename) except IOError as e: sys.exit("Couldn't open %s: %s" % (filename, e[1])) if type(ts) != TestSuite: sys.exit('%s is not a xUnit report file' % filename) return ts
def parse(self, junit_xml, progress_cb=None): self.backend.configure() xml = JUnitXml.fromfile(junit_xml) # apparently junit.xml may contain either a <testsuites> tag, # e.g. Katalon Studio if xml._tag == "testsuites": # pylint: disable=protected-access cases = [] for suite in xml: for case in suite: cases.append(case) # or directly <testsuite> (only 1) tag - nose & py.test else: cases = list(xml) for xml_case in cases: summary = f"{xml_case.classname}.{xml_case.name}" test_case, _ = self.backend.test_case_get_or_create(summary) self.backend.add_test_case_to_plan(test_case['id'], self.backend.plan_id) comment = 'Result recorded via Kiwi TCMS junit.xml-plugin' if not xml_case.result: status_id = self.backend.get_status_id('PASSED') # note: since junitpartser v2.0 the result attribute holds # a list of values b/c pytest can produce files which contain # multiple results for the same test case. We take the first! for result in xml_case.result: if isinstance(result, Failure): status_id = self.backend.get_status_id('FAILED') comment = result.tostring() break if isinstance(result, Error): status_id = self.backend.get_status_id('ERROR') comment = result.tostring() break if isinstance(result, Skipped): status_id = self.backend.get_status_id('WAIVED') comment = result.message break for execution in self.backend.add_test_case_to_run( test_case['id'], self.backend.run_id, ): self.backend.update_test_execution(execution["id"], status_id, comment) if progress_cb: progress_cb() self.backend.finish_test_run()
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
def observe_tests(self): outcomes = {} for report in self.get_surefire_files(): try: for case in JUnitXml.fromfile(report): test = Test(case) outcomes[test.full_name] = test except: pass return outcomes
def _update_junit_report(destination, **kwargs): """Updates the junit reports to contain the names of the current Azdo Job.""" destination = os.path.abspath(destination) report_dir = os.path.join(destination, "reports") report_name = os.getenv("AgentJobName", "") for name in glob.glob(os.path.join(report_dir, "*.xml")): xml = JUnitXml.fromfile(name) xml.name = f"({report_name}): {xml.name}" for suite in xml: suite.classname = f"({report_name}): {suite.classname}" xml.write()
def get_tests_results(repo_dir): surefire_reports = get_surefire_files(repo_dir) outcomes = {} for report in surefire_reports: for case in JUnitXml.fromfile(report): result = 'pass' if type(case.result) is Error: result = 'error' if type(case.result) is Failure: result = 'failure' outcomes["{classname}@{name}".format(classname=case.classname, name=case.name)] = result
def test_fromfile_without_testsuites_tag(self): xml = JUnitXml.fromfile( os.path.join(os.path.dirname(__file__), "data/no_suites_tag.xml")) cases = list(iter(xml)) properties = list(iter(xml.properties())) self.assertEqual(len(properties), 3) self.assertEqual(len(cases), 3) self.assertEqual(xml.name, "JUnitXmlReporter.constructor") self.assertEqual(xml.tests, 3) self.assertIsInstance(cases[0].result[0], Failure) self.assertIsInstance(cases[1].result[0], Skipped) self.assertEqual(len(cases[2].result), 0)
def get_failures(junitfile): """Return a map of failures from a given junit report""" ts = JUnitXml.fromfile(junitfile) failures = {} for case in ts: failure_texts = [] for failure in case.iterchildren(Failure): failure_texts.append(failure._elem.text.strip()) if len(failure_texts) != 0: key = "{}.{}".format(case.name, case.classname) failures[key] = "\n".join(failure_texts)
def __init__(self, junit_xml_path): if os.path.isfile(junit_xml_path): self._junitfile = junit_xml_path elif os.path.isdir(junit_xml_path): raise Exception( "Generating Report for multiple xml is not currently Supported." ) else: raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), junit_xml_path) self._xml = JUnitXml.fromfile(self._junitfile)
def LoadXUnitFile(XUnitFilePath): """ Load an xUnit file and unmarshal it. :param XUnitFilePath: location of the ``*.xml`` file to be loaded. """ xml = JUnitXml.fromfile(XUnitFilePath) print(xml) for suite in xml: print(suite) for case in suite: print(case)