1
# Copyright (c) 2009 Jonathan M. Lange. See LICENSE for details.
3
"""Test suites and related things."""
17
class ConcurrentTestSuite(unittest.TestSuite):
18
"""A TestSuite whose run() calls out to a concurrency strategy."""
20
def __init__(self, suite, make_tests):
21
"""Create a ConcurrentTestSuite to execute suite.
23
:param suite: A suite to run concurrently.
24
:param make_tests: A helper function to split the tests in the
25
ConcurrentTestSuite into some number of concurrently executing
26
sub-suites. make_tests must take a suite, and return an iterable
27
of TestCase-like object, each of which must have a run(result)
30
super(ConcurrentTestSuite, self).__init__([suite])
31
self.make_tests = make_tests
33
def run(self, result):
34
"""Run the tests concurrently.
36
This calls out to the provided make_tests helper, and then serialises
37
the results so that result only sees activity from one TestCase at
40
ConcurrentTestSuite provides no special mechanism to stop the tests
41
returned by make_tests, it is up to the make_tests to honour the
42
shouldStop attribute on the result object they are run with, which will
43
be set if an exception is raised in the thread which
44
ConcurrentTestSuite.run is called in.
46
tests = self.make_tests(self)
50
result_semaphore = threading.Semaphore(1)
52
process_result = testtools.ThreadsafeForwardingResult(result,
54
reader_thread = threading.Thread(target=self._run_test, args=(test,
55
process_result, queue))
56
threads[test] = reader_thread, process_result
59
finished_test = queue.get()
60
threads[finished_test][0].join()
61
del threads[finished_test]
63
for thread, process_result in threads.itervalues():
67
def _run_test(self, test, process_result, queue):
69
test.run(process_result)