Package pysys
[hide private]
[frames] | no frames]

Source Code for Package pysys

  1  #!/usr/bin/env python 
  2  # PySys System Test Framework, Copyright (C) 2006-2013  M.B.Grieve 
  3   
  4  # This library is free software; you can redistribute it and/or 
  5  # modify it under the terms of the GNU Lesser General Public 
  6  # License as published by the Free Software Foundation; either 
  7  # version 2.1 of the License, or (at your option) any later version. 
  8   
  9  # This library is distributed in the hope that it will be useful, 
 10  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 12  # Lesser General Public License for more details. 
 13   
 14  # You should have received a copy of the GNU Lesser General Public 
 15  # License along with this library; if not, write to the Free Software 
 16  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 
 17   
 18  # Contact: moraygrieve@users.sourceforge.net 
 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__ = "0.9.2" 
 57  """The version of this release.""" 
 58   
 59  __date__ = "16-June-2013" 
 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  # Lock to be held when creating processes also while holding any resources 
 77  # we don't want being passed to child processes e.g. sockets, files 
 78  process_lock = threading.Lock() 
 79   
 80  # customize the default logging names for display 
 81  logging._levelNames[50] = 'CRIT' 
 82  logging._levelNames[30] = 'WARN' 
 83   
 84  # class extensions for supporting multi-threaded nature 
85 -class ThreadedStreamHandler(logging.StreamHandler):
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 """
93 - def __init__(self, strm):
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
104 -class ThreadedFileHandler(logging.FileHandler):
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 """
112 - def __init__(self, filename):
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
124 - def getBuffer(self):
125 """Return the unformatted messages called by the creating thread.""" 126 return self.buffer
127 128
129 -class ThreadFilter(logging.Filterer):
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 """
140 - def __init__(self):
141 """Overrides logging.Filterer.__init__""" 142 self.threadId = threadId() 143 logging.Filterer.__init__(self)
144
145 - def filter(self, record):
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 # configure the logger 161 stdoutHandler.setLevel(logging.INFO) 162 rootLogger.addHandler(stdoutHandler) 163 164 # global reference is using log 165 log = rootLogger 166