14 # Test Execution Implementation
16 class TestProvider(object):
17 def __init__(self, tests):
18 self.iter = iter(range(len(tests)))
19 self.lock = threading.Lock()
28 # Check if we are cancelled.
34 # Otherwise take the next test.
35 for item in self.iter:
43 def __init__(self, run_instance, provider, consumer):
44 self.run_instance = run_instance
45 self.provider = provider
46 self.consumer = consumer
50 item = self.provider.get()
54 self.consumer.task_finished()
56 def run_test(self, test_index):
57 test = self.run_instance.tests[test_index]
59 self.run_instance.execute_test(test)
60 except KeyboardInterrupt:
61 # This is a sad hack. Unfortunately subprocess goes
62 # bonkers with ctrl-c and we start forking merrily.
63 print('\nCtrl-C detected, goodbye.')
65 self.consumer.update(test_index, test)
67 class ThreadResultsConsumer(object):
68 def __init__(self, display):
69 self.display = display
70 self.lock = threading.Lock()
72 def update(self, test_index, test):
75 self.display.update(test)
79 def task_finished(self):
82 def handle_results(self):
85 def run_one_tester(run, provider, display):
86 tester = Tester(run, provider, display)
93 This class represents a concrete, configured testing run.
96 def __init__(self, lit_config, tests):
97 self.lit_config = lit_config
100 def execute_test(self, test):
102 start_time = time.time()
104 result = test.config.test_format.execute(test, self.lit_config)
106 # Support deprecated result from execute() which returned the result
107 # code and additional output as a tuple.
108 if isinstance(result, tuple):
109 code, output = result
110 result = lit.Test.Result(code, output)
111 elif not isinstance(result, lit.Test.Result):
112 raise ValueError("unexpected result from test execution")
113 except KeyboardInterrupt:
116 if self.lit_config.debug:
118 output = 'Exception during script execution:\n'
119 output += traceback.format_exc()
121 result = lit.Test.Result(lit.Test.UNRESOLVED, output)
122 result.elapsed = time.time() - start_time
124 test.setResult(result)
126 def execute_tests(self, display, jobs, max_time=None):
128 execute_tests(display, jobs, [max_time])
130 Execute each of the tests in the run, using up to jobs number of
131 parallel tasks, and inform the display of each individual result. The
132 provided tests should be a subset of the tests available in this run
135 If max_time is non-None, it should be a time in seconds after which to
136 stop executing tests.
138 The display object will have its update method called with each test as
139 it is completed. The calls are guaranteed to be locked with respect to
140 one another, but are *not* guaranteed to be called on the same thread as
141 this method was invoked on.
143 Upon completion, each test in the run will have its result
144 computed. Tests which were not actually executed (for any reason) will
145 be given an UNRESOLVED result.
148 # Create the test provider object.
149 provider = TestProvider(self.tests)
151 # Install a console-control signal handler on Windows.
152 if win32api is not None:
153 def console_ctrl_handler(type):
156 win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
158 # Install a timeout handler, if requested.
159 if max_time is not None:
160 def timeout_handler():
162 timeout_timer = threading.Timer(max_time, timeout_handler)
163 timeout_timer.start()
165 # Actually execute the tests.
166 self._execute_tests_with_provider(provider, display, jobs)
168 # Cancel the timeout handler.
169 if max_time is not None:
170 timeout_timer.cancel()
172 # Update results for any tests which weren't run.
173 for test in self.tests:
174 if test.result is None:
175 test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
177 def _execute_tests_with_provider(self, provider, display, jobs):
178 consumer = ThreadResultsConsumer(display)
180 # If only using one testing thread, don't use tasks at all; this lets us
181 # profile, among other things.
183 run_one_tester(self, provider, consumer)
186 # Start all of the tasks.
187 tasks = [threading.Thread(target=run_one_tester,
188 args=(self, provider, consumer))
189 for i in range(jobs)]
193 # Allow the consumer to handle results, if necessary.
194 consumer.handle_results()
196 # Wait for all the tasks to complete.