1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17   
 18   
 19   
 20   
 21   
 22   
 23  """Module containing the status singleton object.""" 
 24   
 25   
 26  from os import F_OK, access, getcwd 
 27  from os.path import sep 
 28  import platform 
 29  from re import search 
 30  import sys 
 31  from time import time 
 32  from threading import Lock, RLock 
 33   
 34   
 35  from lib.compat import Queue 
 36  from lib.errors import RelaxError 
 37   
 38   
 40      """The relax status singleton class.""" 
 41   
 42       
 43      _instance = None 
 44   
 72   
 73   
 75          """Determine, with a bit of magic, the relax installation path. 
 76   
 77          @return:    The relax installation path.  With a Mac OS X app, this will be the path to the 'Resources'. 
 78          @rtype:     str 
 79          """ 
 80   
 81           
 82          file_to_find = 'dep_check.py' 
 83   
 84           
 85          for path in sys.path: 
 86               
 87              if access(path + sep + file_to_find, F_OK): 
 88                  return path 
 89   
 90           
 91          for path in sys.path: 
 92               
 93              if search('Resources', path): 
 94                   
 95                  bits = path.split('Resources') 
 96                  mac_path = bits[0] + 'Resources' 
 97   
 98                   
 99                  return mac_path 
100   
101           
102          if access(getcwd() + sep + file_to_find, F_OK): 
103              return getcwd() 
104   
105           
106          return sys.path[0] 
 107   
108   
110          """Initialise all the status data structures.""" 
111   
112           
113          self.exec_lock = Exec_lock() 
114   
115           
116          self.pipe_lock = Relax_lock(name='pipe_lock') 
117   
118           
119          self.spin_lock = Relax_lock(name='spin_lock') 
120   
121           
122          self.exception_queue = Queue() 
123   
124           
125          self.auto_analysis = {} 
126          self.current_analysis = None 
127   
128           
129          self.controller_max_entries = 100000     
130   
131           
132          self.skipped_tests = [] 
133          """The skipped tests list.  Each element should be a list of the test case name, the missing Python module, and the name of the test suite category (i.e. 'system' or 'unit').""" 
134   
135           
136          self._setup_observers() 
137   
138           
139          if platform.uname()[0] in ['Windows', 'Microsoft']: 
140              self.text_width = 79 
141          else: 
142              self.text_width = 100 
 143   
144   
146          """Set up all the observer objects.""" 
147   
148           
149          self.observers = Observer_container() 
150   
151           
152          self.observers.auto_analyses = Observer('auto_analyses') 
153   
154           
155          self.observers.pipe_alteration = Observer('pipe_alteration') 
156   
157           
158          self.observers.gui_uf = Observer('gui_uf') 
159   
160           
161          self.observers.gui_analysis = Observer('gui_analysis') 
162   
163           
164          self.observers.reset = Observer('reset') 
165   
166           
167          self.observers.exec_lock = Observer('exec_lock') 
168   
169           
170          self.observers.result_file = Observer('result_file') 
171   
172           
173          self.observers.state_load = Observer('state_load') 
174   
175           
176          self.observers.system_cwd_path = Observer('system_cwd_path') 
 177   
178   
180          """Initialise a status container for an auto-analysis. 
181   
182          @param name:    The unique name of the auto-analysis.  This will act as a key. 
183          @type name:     str. 
184          @param type:    The type of auto-analysis. 
185          @type type:     str 
186          """ 
187   
188           
189          self.auto_analysis[name] = Auto_analysis(name, type) 
 190   
191   
193          """Reset the status object to its initial state.""" 
194   
195           
196          self._setup() 
  197   
198   
199   
201      """The auto-analysis status container.""" 
202   
204          """Initialise the auto-analysis status object. 
205   
206          @param name:    The unique name of the auto-analysis.  This will act as a key. 
207          @type name:     str. 
208          @param type:    The type of auto-analysis. 
209          @type type:     str 
210          """ 
211   
212           
213          self._status = Status() 
214   
215           
216          self.__dict__['type'] = type 
217   
218           
219          self.__dict__['fin'] = False 
220   
221           
222          self.__dict__['mc_number'] = None 
 223   
224   
226          """Replacement __setattr__() method. 
227   
228          @param name:    The name of the attribute. 
229          @type name:     str 
230          @param value:   The value of the attribute. 
231          @type value:    anything 
232          """ 
233   
234           
235          self.__dict__[name] = value 
236   
237           
238          self._status.observers.auto_analyses.notify() 
  239   
240   
241   
243      """A type of locking object for locking execution of relax.""" 
244   
246          """Set up the lock-like object. 
247   
248          @keyword fake_lock: A flag which is True will allow this object to be debugged as the locking mechanism is turned off. 
249          @type fake_lock:    bool 
250          """ 
251   
252           
253          self._fake_lock = fake_lock 
254   
255           
256          self._lock = Lock() 
257   
258           
259          self._status = Status() 
260   
261           
262          self._name = [] 
263          self._mode = [] 
264   
265           
266          self._nest = 0 
267   
268           
269          self._auto_from_script = False 
270   
271           
272          if self._fake_lock: 
273              self.log = open('lock.log', 'w') 
 274   
275   
276 -    def acquire(self, name, mode='script'): 
 277          """Simulate the Lock.acquire() mechanism. 
278   
279          @param name:    The name of the locking code. 
280          @type name:     str 
281          @keyword mode:  The mode of the code trying to obtain the lock.  This can be one of 'script' for the scripting interface or 'auto-analysis' for the auto-analyses. 
282          @type mode:     str 
283          """ 
284   
285           
286          if self._status.debug: 
287              sys.stdout.write("debug> Execution lock:  Acquisition by '%s' ('%s' mode).\n" % (name, mode)) 
288   
289           
290          self._name.append(name) 
291          self._mode.append(mode) 
292   
293           
294          if self.locked(): 
295               
296              self._nest += 1 
297   
298               
299              if self._fake_lock: 
300                  self.log.write("Nested by %s (to level %s)\n" % (name, self._nest)) 
301                  self.log.flush() 
302   
303               
304              return 
305   
306           
307          if self._fake_lock: 
308              self.log.write("Acquired by %s\n" % self._name[-1]) 
309              self.log.flush() 
310              return 
311   
312           
313          lock = self._lock.acquire() 
314   
315           
316          status = Status() 
317          status.observers.exec_lock.notify() 
318   
319           
320          return lock 
 321   
322   
324          """Simulate the Lock.locked() mechanism.""" 
325   
326           
327          if self._fake_lock: 
328              if len(self._name): 
329                  return True 
330              else: 
331                  return False 
332   
333           
334          return self._lock.locked() 
 335   
336   
338          """Simulate the Lock.release() mechanism.""" 
339   
340           
341          if self._status.debug: 
342              sys.stdout.write("debug> Execution lock:  Release by '%s' ('%s' mode).\n" % (self._name[-1], self._mode[-1])) 
343   
344           
345          self._name.pop(-1) 
346          self._mode.pop(-1) 
347   
348           
349          if self._nest: 
350               
351              if self._fake_lock: 
352                  self.log.write("Nested locking decrement (%s -> %s)\n" % (self._nest, self._nest-1)) 
353                  self.log.flush() 
354   
355               
356              self._nest -= 1 
357   
358               
359              return 
360   
361           
362          if self._fake_lock: 
363               
364              text = 'Release' 
365   
366               
367              if hasattr(self, 'test_name'): 
368                  text = text + 'd by %s' % self.test_name 
369   
370               
371              self.log.write("%s\n\n" % text) 
372              self.log.flush() 
373              return 
374   
375           
376          release = self._lock.release() 
377   
378           
379          status = Status() 
380          status.observers.exec_lock.notify() 
381   
382           
383          return release 
  384   
385   
386   
388      """The observer design pattern base class.""" 
389   
391          """Set up the object. 
392   
393          @keyword name:      The special name for the observer object, used in debugging. 
394          @type name:         str 
395          """ 
396   
397           
398          self._name = name 
399   
400           
401          self._callback = {} 
402          self._method_names = {} 
403   
404           
405          self._keys = [] 
406   
407           
408          self._status = Status() 
 409   
410   
412          """Notify all observers of the state change.""" 
413   
414           
415          for key in self._keys: 
416               
417              if self._status.debug: 
418                  if self._method_names[key]: 
419                      sys.stdout.write("debug> Observer: '%s' notifying the '%s' method %s().\n" % (self._name, key, self._method_names[key])) 
420                  else: 
421                      sys.stdout.write("debug> Observer: '%s' notifying '%s'.\n" % (self._name, key)) 
422   
423               
424              self._callback[key]() 
 425   
426   
427 -    def register(self, key, method, method_name=None): 
 428          """Register a method to be called when the state changes. 
429   
430          @param key:             The key to identify the observer's method. 
431          @type key:              str 
432          @param method:          The observer's method to be called after a state change. 
433          @type method:           method 
434          @keyword method_name:   The optional method name used in debugging printouts. 
435          @type method_name:      str or None 
436          """ 
437   
438           
439          if key in self._keys: 
440              raise RelaxError("The observer '%s' already exists." % key) 
441   
442           
443          if key == None: 
444              raise RelaxError("The observer key must be supplied.") 
445   
446           
447          if self._status.debug: 
448              if method_name: 
449                  sys.stdout.write("debug> Observer: '%s' registering the '%s' method %s().\n" % (self._name, key, method_name)) 
450              else: 
451                  sys.stdout.write("debug> Observer: '%s' registering '%s'.\n" % (self._name, key)) 
452   
453           
454          self._callback[key] = method 
455   
456           
457          self._method_names[key] = method_name 
458   
459           
460          self._keys.append(key) 
 461   
462   
464          """Reset the object.""" 
465   
466           
467          if self._status.debug: 
468              sys.stdout.write("debug> Resetting observer '%s'.\n" % self._name) 
469   
470           
471          self._callback = {} 
472   
473           
474          self._keys = [] 
 475   
476   
478          """Unregister the method corresponding to the key. 
479   
480          @param key:     The key to identify the observer's method. 
481          @type key:      str 
482          """ 
483   
484           
485          if self._status.debug: 
486              sys.stdout.write("debug> Observer: '%s' unregistering '%s'.\n" % (self._name, key)) 
487   
488           
489          if key not in self._keys: 
490              if self._status.debug: 
491                  sys.stdout.write("debug> The key '%s' does not exist.\n" % key) 
492              return 
493   
494           
495          self._callback.pop(key) 
496   
497           
498          self._method_names.pop(key) 
499   
500           
501          self._keys.remove(key) 
  502   
503   
504   
506      """A type of locking object for relax.""" 
507   
508 -    def __init__(self, name='unknown', fake_lock=False): 
 509          """Set up the lock-like object. 
510   
511          @keyword name:      The special name for the lock, used in debugging. 
512          @type name:         str 
513          @keyword fake_lock: A flag which is True will allow this object to be debugged as the locking mechanism is turned off. 
514          @type fake_lock:    bool 
515          """ 
516   
517           
518          self.name = name 
519          self._fake_lock = fake_lock 
520   
521           
522          self._lock = RLock() 
523   
524           
525          self._status = Status() 
526   
527           
528          if self._fake_lock: 
529               
530              self._lock_level = 0 
 531   
532   
533 -    def acquire(self, acquirer='unknown'): 
 534          """Simulate the RLock.acquire() mechanism. 
535   
536          @keyword acquirer:  The optional name of the acquirer. 
537          @type acquirer:     str 
538          """ 
539   
540           
541          if self._status.debug: 
542              sys.stdout.write("debug> Lock '%s':  Acquisition by '%s'.\n" % (self.name, acquirer)) 
543   
544           
545          if self._fake_lock: 
546               
547              self._lock_level += 1 
548   
549               
550              if self._lock_level > 1: 
551                  raise 
552   
553               
554              return 
555   
556           
557          lock = self._lock.acquire() 
558   
559           
560          return lock 
 561   
562   
564          """Simulate the RLock.locked() mechanism.""" 
565   
566           
567          return self._lock.locked() 
 568   
569   
570 -    def release(self, acquirer='unknown'): 
 571          """Simulate the RLock.release() mechanism. 
572   
573          @keyword acquirer:  The optional name of the acquirer. 
574          @type acquirer:     str 
575          """ 
576   
577           
578          if self._status.debug: 
579              sys.stdout.write("debug> Lock '%s':  Release by '%s'.\n" % (self.name, acquirer)) 
580   
581           
582          if self._fake_lock: 
583               
584              self._lock_level -= 1 
585   
586               
587              return 
588   
589           
590          release = self._lock.release() 
591   
592           
593          return release 
  594   
595   
596   
598      """The container for holding all the observer objects.""" 
599   
601          """Print out info about all the status objects.""" 
602   
603           
604          blacklist = list(self.__class__.__dict__.keys()) + list(dict.__dict__.keys()) 
605   
606           
607          for name in dir(self): 
608               
609              if name in blacklist: 
610                  continue 
611   
612               
613              obj = getattr(self, name) 
614   
615               
616              print("Observer '%s' keys: %s" % (obj._name, obj._keys)) 
  617