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