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