1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 PySys System Test Framework.
21
22 PySys has been designed to provide a generic extensible multi-threaded framework for the organisation and execution of system
23 level testcases. It provides a clear model of what a testcases is, how it is structured on disk, how it is executed and validated,
24 and how the outcome is reported for test auditing purposes.
25
26 Testcases are instances of a base test class (L{pysys.basetest.BaseTest}) which provides core functionality for cross platform
27 process management, monitoring and manipulation; in this manner an application under test (AUT) can be started and interacted with
28 directly within a testcase. The base test class additionally provides a set of standard validation techniques based predominantly
29 on regular expression matching within text files (e.g. stdout, logfile of the AUT etc). Testcases are executed through a base
30 runner (L{pysys.baserunner.BaseRunner}) which provides the mechanism to control concurrent testcase flow and auditing. In both
31 cases the base test and runner classes have been designed to be extended for a particular AUT, e.g. to allow a higher level of
32 abstraction over the AUT, tear up and tear down prior to executing a set of testcases etc.
33
34 PySys allows automated regression testcases to be built rapidly. Where an AUT cannot be tested in an automated fashion, testcases
35 can be written to make use of a manual test user interface (L{pysys.manual.ui.ManualTester}) which allows the steps required to
36 execute the test to be presented to a tester in a concise and navigable manner. The tight integration of both manual and automated
37 testcases provides a single framework for all test organisation requirements.
38
39 """
40
41 import sys, logging, threading
42 if sys.version_info >= (3,):
43 from _thread import get_ident as threadId
44 else:
45 from thread import get_ident as threadId
46
47 __author__ = "Moray Grieve"
48 """The author of PySys."""
49
50 __author_email__ = "moraygrieve@users.sourceforge.net"
51 """The author's email address."""
52
53 __status__ = "beta"
54 """The status of this release."""
55
56 __version__ = "1.2.0"
57 """The version of this release."""
58
59 __date__ = "30-May-2016"
60 """The date of this release."""
61
62 __all__ = [ "constants",
63 "exceptions",
64 "baserunner",
65 "basetest",
66 "interfaces",
67 "launcher",
68 "manual",
69 "process",
70 "unit",
71 "utils",
72 "writer",
73 "xml"]
74 """The submodules of PySys."""
75
76
77
78 process_lock = threading.Lock()
79
80
81 logging._levelNames[50] = 'CRIT'
82 logging._levelNames[30] = 'WARN'
83
84
86 """Stream handler to only log from the creating thread.
87
88 Overrides logging.StreamHandler to only allow logging to a stream
89 from the thread that created the class instance and added to the root
90 logger via log.addHandler(ThreadedStreamHandler(stream)).
91
92 """
94 """Overrides logging.StreamHandler.__init__."""
95 self.threadId = threadId()
96 logging.StreamHandler.__init__(self, strm)
97
98 - def emit(self, record):
99 """Overrides logging.StreamHandler.emit."""
100 if self.threadId != threadId(): return
101 logging.StreamHandler.emit(self, record)
102
103
105 """File handler to only log from the creating thread.
106
107 Overrides logging.FileHandler to only allow logging to file from
108 the thread than created the class instance and added to the root
109 logger via log.addHandler(ThreadFileHandler(filename)).
110
111 """
113 """Overrides logging.ThreadedFileHandler.__init__"""
114 self.threadId = threadId()
115 self.buffer = []
116 logging.FileHandler.__init__(self, filename, "a")
117
118 - def emit(self, record):
119 """Overrides logging.ThreadedFileHandler.emit."""
120 if self.threadId != threadId(): return
121 self.buffer.append(record.getMessage())
122 logging.FileHandler.emit(self, record)
123
125 """Return the unformatted messages called by the creating thread."""
126 return self.buffer
127
128
130 """Filter to disallow log records from the current thread.
131
132 Within pysys, logging to standard output is only enabled from the main thread
133 of execution (that in which the test runner class executes). When running with
134 more than one test worker thread, logging to file of the test run log is
135 performed through a file handler, which only allows logging from that thread.
136 To disable either of these, use an instance of this class from the thread in
137 question, adding to the root logger via log.addFilter(ThreadFilter()).
138
139 """
141 """Overrides logging.Filterer.__init__"""
142 self.threadId = threadId()
143 logging.Filterer.__init__(self)
144
146 """Implementation of logging.Filterer.filter to block from the creating thread."""
147 if self.threadId != threadId(): return True
148 return False
149
150
151 rootLogger = logging.getLogger('pysys')
152 """The root logger for all logging within PySys."""
153
154 rootLogger.setLevel(logging.DEBUG)
155 """The root logger log level (set to DEBUG as all filtering is done by the handlers)."""
156
157 stdoutHandler = ThreadedStreamHandler(sys.stdout)
158 """The default stdout logging handler for all logging within PySys."""
159
160
161
162
163 log = rootLogger
164