1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from qm.temporary_directory import TemporaryDirectory
21 from qm.test.base import *
22 import qm.test.cmdline
23 from qm.test.command_thread import *
24 from qm.test.target import *
25 import Queue
26 from threading import *
27
28
29
30
31
33 """A 'LocalThread' executes commands locally."""
34
39
40
41 - def _RunTest(self, descriptor, context):
42 """Run the test given by 'descriptor'.
43
44 'descriptor' -- The name of the test to be run.
45
46 'context' -- The 'Context' in which to run the test."""
47
48 self.GetTarget()._RunTest(descriptor, context)
49
50
52 """Return the path to the temporary directory for this thread.
53
54 returns -- The path to the temporary directory associated with
55 this thread."""
56
57 return self.__temporary_directory.GetPath()
58
59
60
62 """A target implementation that runs tests in local threads.
63
64 Each thread executes one test or resource at a time."""
65
66 arguments = [
67 qm.fields.IntegerField(
68 name="threads",
69 title="Number of Threads",
70 description="""The number of threads to devote to running tests.
71
72 A positive integer that indicates the number of threads to
73 use when running tests. Larger numbers will allow more
74 tests to be run at once. You can experiment with this
75 value to find the number that results in the fastest
76 execution.""",
77 default_value=1),
78 ]
79
80 - def __init__(self, database, properties):
81 """Construct a 'ThreadTarget'.
82
83 'database' -- The 'Database' containing the tests that will be
84 run.
85
86 'properties' -- A dictionary mapping strings (property names)
87 to strings (property values)."""
88
89
90 Target.__init__(self, database, properties)
91
92
93 self.__ready_threads_lock = Lock()
94
95
96 self.__resources_condition = Condition()
97
98
100 """Return true if the target is idle.
101
102 returns -- True if the target is idle. If the target is idle,
103 additional tasks may be assigned to it."""
104
105
106
107
108 self.__ready_threads_lock.acquire()
109
110
111 if self.__ready_threads:
112 idle=1
113 else:
114 idle=0
115
116
117 self.__ready_threads_lock.release()
118
119 return idle
120
121
122 - def Start(self, response_queue, engine=None):
123 """Start the target.
124
125 'response_queue' -- The 'Queue' in which the results of test
126 executions are placed.
127
128 'engine' -- The 'ExecutionEngine' that is starting the target,
129 or 'None' if this target is being started without an
130 'ExecutionEngine'."""
131
132 Target.Start(self, response_queue, engine)
133
134
135 self.__threads = []
136 for i in xrange(0, self.threads):
137
138 thread = LocalThread(self)
139
140 thread.start()
141
142 self.__threads.append(thread)
143
144
145 self.__ready_threads = self.__threads[:]
146
147
149 """Stop the target.
150
151 postconditions -- The target may no longer be used."""
152
153 Target.Stop(self)
154
155
156 for thread in self.__threads:
157 thread.Stop()
158
159 for thread in self.__threads:
160 thread.join()
161
162
163 - def RunTest(self, descriptor, context):
164 """Run the test given by 'descriptor'.
165
166 'descriptor' -- The 'TestDescriptor' for the test.
167
168 'context' -- The 'Context' in which to run the test.
169
170 Derived classes may override this method."""
171
172 self._Trace("About to dispatch test " + descriptor.GetId())
173
174 self.__ready_threads_lock.acquire()
175
176
177
178 assert self.__ready_threads
179
180 thread = self.__ready_threads.pop(0)
181
182 self.__ready_threads_lock.release()
183
184 thread.RunTest(descriptor, context)
185
186 self._Trace("Finished dispatching test " + descriptor.GetId())
187
188
189 - def _RunTest(self, descriptor, context):
190 """Run the test given by 'descriptor'.
191
192 'descriptor' -- The 'TestDescriptor' for the test.
193
194 'context' -- The 'Context' in which to run the test.
195
196 This method will be called from the thread that has been
197 assigned the test."""
198
199 Target.RunTest(self, descriptor, context)
200
201
213
214
216 """Begin setting up the indicated resource.
217
218 'resource_name' -- A string naming a resource.
219
220 returns -- If the resource has already been set up, returns a
221 tuple '(outcome, map)'. The 'outcome' indicates the outcome
222 that resulted when the resource was set up; the 'map' is a map
223 from strings to strings indicating properties added by this
224 resource. Otherwise, returns 'None', but marks the resource
225 as in the process of being set up; it is the caller's
226 responsibility to finish setting it up by calling
227 '_FinishResourceSetUp'."""
228
229
230 self.__resources_condition.acquire()
231 try:
232
233
234 while 1:
235 rop = Target._BeginResourceSetUp(self, resource_name)
236
237
238 if not rop:
239 return rop
240
241
242 if rop[1]:
243 return rop
244
245
246
247 self.__resources_condition.wait()
248 finally:
249
250 self.__resources_condition.release()
251
252
254
255
256 self.__resources_condition.acquire()
257
258 rop = Target._FinishResourceSetUp(self, resource, result, properties)
259
260
261 self.__resources_condition.notifyAll()
262
263 self.__resources_condition.release()
264
265 return rop
266
267
269 """Note that the current thread.
270
271 This method is called by the thread when it has completed a
272 task."""
273
274
275
276 self.__ready_threads_lock.acquire()
277
278
279
280 try:
281 thread = currentThread()
282 assert thread not in self.__ready_threads
283 self.__ready_threads.append(thread)
284 finally:
285
286 self.__ready_threads_lock.release()
287
288
297
298
302