Newer
Older
"""
A class used for defining and running test suites
"""
import sys
import subprocess
from pavelib.utils.process import kill_process
try:
from pygments.console import colorize
except ImportError:
colorize = lambda color, text: text # pylint: disable-msg=invalid-name
__test__ = False # do not collect
class TestSuite(object):
"""
TestSuite is a class that defines how groups of tests run.
"""
def __init__(self, *args, **kwargs):
self.root = args[0]
self.subsuites = kwargs.get('subsuites', [])
self.failed_suites = []
self.verbosity = kwargs.get('verbosity', 1)
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def __enter__(self):
"""
This will run before the test suite is run with the run_suite_tests method.
If self.run_test is called directly, it should be run in a 'with' block to
ensure that the proper context is created.
Specific setup tasks should be defined in each subsuite.
i.e. Checking for and defining required directories.
"""
print("\nSetting up for {suite_name}".format(suite_name=self.root))
self.failed_suites = []
def __exit__(self, exc_type, exc_value, traceback):
"""
This is run after the tests run with the run_suite_tests method finish.
Specific clean up tasks should be defined in each subsuite.
If self.run_test is called directly, it should be run in a 'with' block
to ensure that clean up happens properly.
i.e. Cleaning mongo after the lms tests run.
"""
print("\nCleaning up after {suite_name}".format(suite_name=self.root))
@property
def cmd(self):
"""
The command to run tests (as a string). For this base class there is none.
"""
return None
def run_test(self):
"""
Runs a self.cmd in a subprocess and waits for it to finish.
It returns False if errors or failures occur. Otherwise, it
returns True.
"""
cmd = self.cmd
sys.stdout.write(cmd)
msg = colorize(
'green',
'\n{bar}\n Running tests for {suite_name} \n{bar}\n'.format(suite_name=self.root, bar='=' * 40),
)
sys.stdout.write(msg)
sys.stdout.flush()
kwargs = {'shell': True, 'cwd': None}
process = None
try:
process = subprocess.Popen(cmd, **kwargs)
process.communicate()
except KeyboardInterrupt:
kill_process(process)
sys.exit(1)
else:
return (process.returncode == 0)
def run_suite_tests(self):
"""
Runs each of the suites in self.subsuites while tracking failures
"""
# Uses __enter__ and __exit__ for context
with self:
# run the tests for this class, and for all subsuites
if self.cmd:
passed = self.run_test()
if not passed:
self.failed_suites.append(self)
for suite in self.subsuites:
suite.run_suite_tests()
if len(suite.failed_suites) > 0:
self.failed_suites.extend(suite.failed_suites)
def report_test_results(self):
"""
Writes a list of failed_suites to sys.stderr
"""
if len(self.failed_suites) > 0:
msg = colorize('red', "\n\n{bar}\nTests failed in the following suites:\n* ".format(bar="=" * 48))
msg += colorize('red', '\n* '.join([s.root for s in self.failed_suites]) + '\n\n')
else:
msg = colorize('green', "\n\n{bar}\nNo test failures ".format(bar="=" * 48))
print(msg)
def run(self):
"""
Runs the tests in the suite while tracking and reporting failures.
"""
self.run_suite_tests()
self.report_test_results()
if len(self.failed_suites) > 0:
sys.exit(1)