14 # Test Execution Implementation
16 class TestProvider(object):
17 def __init__(self, tests, max_time):
18 self.max_time = max_time
19 self.iter = iter(range(len(tests)))
20 self.lock = threading.Lock()
21 self.start_time = time.time()
30 # Check if we have run out of time.
31 if self.max_time is not None:
32 if time.time() - self.start_time > self.max_time:
35 # Otherwise take the next test.
40 for item in self.iter:
48 def __init__(self, run_instance, provider, consumer):
49 self.run_instance = run_instance
50 self.provider = provider
51 self.consumer = consumer
55 item = self.provider.get()
59 self.consumer.task_finished()
61 def run_test(self, test_index):
62 test = self.run_instance.tests[test_index]
64 self.run_instance.execute_test(test)
65 except KeyboardInterrupt:
66 # This is a sad hack. Unfortunately subprocess goes
67 # bonkers with ctrl-c and we start forking merrily.
68 print('\nCtrl-C detected, goodbye.')
70 self.consumer.update(test_index, test)
72 class ThreadResultsConsumer(object):
73 def __init__(self, display):
74 self.display = display
75 self.lock = threading.Lock()
77 def update(self, test_index, test):
80 self.display.update(test)
84 def task_finished(self):
87 def handle_results(self):
90 def run_one_tester(run, provider, display):
91 tester = Tester(run, provider, display)
98 This class represents a concrete, configured testing run.
101 def __init__(self, lit_config, tests):
102 self.lit_config = lit_config
105 def execute_test(self, test):
107 start_time = time.time()
109 result = test.config.test_format.execute(test, self.lit_config)
111 # Support deprecated result from execute() which returned the result
112 # code and additional output as a tuple.
113 if isinstance(result, tuple):
114 code, output = result
115 result = lit.Test.Result(code, output)
116 elif not isinstance(result, lit.Test.Result):
117 raise ValueError("unexpected result from test execution")
118 except KeyboardInterrupt:
121 if self.lit_config.debug:
123 output = 'Exception during script execution:\n'
124 output += traceback.format_exc()
126 result = lit.Test.Result(lit.Test.UNRESOLVED, output)
127 result.elapsed = time.time() - start_time
129 test.setResult(result)
131 def execute_tests(self, display, jobs, max_time=None):
133 execute_tests(display, jobs, [max_time])
135 Execute each of the tests in the run, using up to jobs number of
136 parallel tasks, and inform the display of each individual result. The
137 provided tests should be a subset of the tests available in this run
140 If max_time is non-None, it should be a time in seconds after which to
141 stop executing tests.
143 The display object will have its update method called with each test as
144 it is completed. The calls are guaranteed to be locked with respect to
145 one another, but are *not* guaranteed to be called on the same thread as
146 this method was invoked on.
148 Upon completion, each test in the run will have its result
149 computed. Tests which were not actually executed (for any reason) will
150 be given an UNRESOLVED result.
153 # Create the test provider object.
154 provider = TestProvider(self.tests, max_time)
156 # Install a console-control signal handler on Windows.
157 if win32api is not None:
158 def console_ctrl_handler(type):
161 win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
163 # Actually execute the tests.
164 self._execute_tests_with_provider(provider, display, jobs)
166 # Update results for any tests which weren't run.
167 for test in self.tests:
168 if test.result is None:
169 test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
171 def _execute_tests_with_provider(self, provider, display, jobs):
172 consumer = ThreadResultsConsumer(display)
174 # If only using one testing thread, don't use tasks at all; this lets us
175 # profile, among other things.
177 run_one_tester(self, provider, consumer)
180 # Start all of the tasks.
181 tasks = [threading.Thread(target=run_one_tester,
182 args=(self, provider, consumer))
183 for i in range(jobs)]
187 # Allow the consumer to handle results, if necessary.
188 consumer.handle_results()
190 # Wait for all the tasks to complete.