3 # Copyright (c) 2016 Cable Television Laboratories, Inc. and others.
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 """Define the parent class to run unittest.TestSuite as TestCase."""
12 from __future__ import division
21 from subunit.run import SubunitTestRunner
24 from xtesting.core import testcase
26 __author__ = ("Steven Pisarski <s.pisarski@cablelabs.com>, "
27 "Cedric Ollivier <cedric.ollivier@orange.com>")
30 class Suite(testcase.TestCase):
31 """Base model for running unittest.TestSuite."""
33 __logger = logging.getLogger(__name__)
35 def __init__(self, **kwargs):
36 super(Suite, self).__init__(**kwargs)
40 def generate_stats(cls, stream):
41 """Generate stats from subunit stream
47 stats = subprocess.Popen(
48 ['subunit-stats'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
49 output, _ = stats.communicate(stream.read())
50 cls.__logger.info("\n\n%s", output.decode("utf-8"))
52 def generate_xunit(self, stream):
53 """Generate junit report from subunit stream
59 with open("{}/results.xml".format(self.res_dir), "w") as xml:
60 stats = subprocess.Popen(
61 ['subunit2junitxml'], stdin=subprocess.PIPE,
62 stdout=subprocess.PIPE)
63 output, _ = stats.communicate(stream.read())
64 xml.write(output.decode("utf-8"))
66 def generate_html(self, stream):
67 """Generate html report from subunit stream
72 cmd = ['subunit2html', stream, '{}/results.html'.format(self.res_dir)]
73 output = subprocess.check_output(cmd)
74 self.__logger.debug("\n%s\n\n%s", ' '.join(cmd), output)
76 def run(self, **kwargs):
77 """Run the test suite.
79 It allows running any unittest.TestSuite and getting its
82 By default, it runs the suite defined as instance attribute.
83 It can be overriden by passing name as arg. It must
84 conform with TestLoader.loadTestsFromName().
86 It sets the following attributes required to push the results
95 kwargs: Arbitrary keyword arguments.
98 TestCase.EX_OK if any TestSuite has been run
99 TestCase.EX_RUN_ERROR otherwise.
102 name = kwargs["name"]
104 self.suite = unittest.TestLoader().loadTestsFromName(name)
106 self.__logger.error("Can not import %s", name)
107 return testcase.TestCase.EX_RUN_ERROR
112 self.start_time = time.time()
113 if not os.path.isdir(self.res_dir):
114 os.makedirs(self.res_dir)
115 stream = six.BytesIO()
116 result = SubunitTestRunner(
117 stream=stream, verbosity=2).run(self.suite).decorated
118 self.generate_stats(stream)
119 self.generate_xunit(stream)
120 with open('{}/subunit_stream'.format(self.res_dir), 'wb') as subfd:
122 shutil.copyfileobj(stream, subfd)
123 self.generate_html('{}/subunit_stream'.format(self.res_dir))
124 self.stop_time = time.time()
126 "testsRun": result.testsRun,
127 "failures": len(result.failures),
128 "errors": len(result.errors)}
129 self.result = 100 * (
130 (result.testsRun - (len(result.failures) +
131 len(result.errors))) /
133 return testcase.TestCase.EX_OK
134 except AssertionError:
135 self.__logger.error("No suite is defined")
136 return testcase.TestCase.EX_RUN_ERROR
137 except ZeroDivisionError:
138 self.__logger.error("No test has been run")
139 return testcase.TestCase.EX_RUN_ERROR
140 except Exception: # pylint: disable=broad-except
141 self.__logger.exception("something wrong occurs")
142 return testcase.TestCase.EX_RUN_ERROR