From dc424b09f6a5b7d912b037a59d201e86d4fcec3a Mon Sep 17 00:00:00 2001 From: Cédric Ollivier Date: Wed, 26 Dec 2018 11:23:02 +0100 Subject: Generate reports for unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It now leverages on subunit to generate html and xml reports. Change-Id: I3f5a4fe5547e743b122b63e0b8530c9d9677cdbd Signed-off-by: Cédric Ollivier (cherry picked from commit 07d8b10d394d1632742c16e4f1f45a29879cf7c1) --- xtesting/core/unit.py | 65 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 7 deletions(-) (limited to 'xtesting/core') diff --git a/xtesting/core/unit.py b/xtesting/core/unit.py index 27773679..f874d01f 100644 --- a/xtesting/core/unit.py +++ b/xtesting/core/unit.py @@ -12,9 +12,13 @@ from __future__ import division import logging +import os +import shutil +import subprocess import time import unittest +from subunit.run import SubunitTestRunner import six from xtesting.core import testcase @@ -30,8 +34,46 @@ class Suite(testcase.TestCase): def __init__(self, **kwargs): super(Suite, self).__init__(**kwargs) + self.res_dir = "/var/lib/xtesting/results/{}".format(self.case_name) self.suite = None + @classmethod + def generate_stats(cls, stream): + """Generate stats from subunit stream + + Raises: + Exception + """ + stream.seek(0) + stats = subprocess.Popen( + ['subunit-stats'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) + output, _ = stats.communicate(stream.read()) + cls.__logger.info("\n\n%s", output) + + def generate_xunit(self, stream): + """Generate junit report from subunit stream + + Raises: + Exception + """ + stream.seek(0) + with open("{}/results.xml".format(self.res_dir), "w") as xml: + stats = subprocess.Popen( + ['subunit2junitxml'], stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + output, _ = stats.communicate(stream.read()) + xml.write(output) + + def generate_html(self, stream): + """Generate html report from subunit stream + + Raises: + CalledProcessError + """ + cmd = ['subunit2html', stream, '{}/results.html'.format(self.res_dir)] + output = subprocess.check_output(cmd) + self.__logger.debug("\n%s\n\n%s", ' '.join(cmd), output) + def run(self, **kwargs): """Run the test suite. @@ -53,8 +95,8 @@ class Suite(testcase.TestCase): Args: kwargs: Arbitrary keyword arguments. - Returns: - TestCase.EX_OK if any TestSuite has been run, + Return: + TestCase.EX_OK if any TestSuite has been run TestCase.EX_RUN_ERROR otherwise. """ try: @@ -69,16 +111,22 @@ class Suite(testcase.TestCase): try: assert self.suite self.start_time = time.time() + if not os.path.isdir(self.res_dir): + os.makedirs(self.res_dir) stream = six.StringIO() - result = unittest.TextTestRunner( - stream=stream, verbosity=2).run(self.suite) - self.__logger.debug("\n\n%s", stream.getvalue()) + result = SubunitTestRunner( + stream=stream, verbosity=2).run(self.suite).decorated + self.generate_stats(stream) + self.generate_xunit(stream) + with open('{}/subunit_stream'.format(self.res_dir), 'w') as subfd: + stream.seek(0) + shutil.copyfileobj(stream, subfd) + self.generate_html('{}/subunit_stream'.format(self.res_dir)) self.stop_time = time.time() self.details = { "testsRun": result.testsRun, "failures": len(result.failures), - "errors": len(result.errors), - "stream": stream.getvalue()} + "errors": len(result.errors)} self.result = 100 * ( (result.testsRun - (len(result.failures) + len(result.errors))) / @@ -90,3 +138,6 @@ class Suite(testcase.TestCase): except ZeroDivisionError: self.__logger.error("No test has been run") return testcase.TestCase.EX_RUN_ERROR + except Exception: # pylint: disable=broad-except + self.__logger.exception("something wrong occurs") + return testcase.TestCase.EX_RUN_ERROR -- cgit 1.2.3-korg