Package cherrypy :: Package test :: Module logtest
[hide private]
[frames] | no frames]

Source Code for Module cherrypy.test.logtest

  1  """logtest, a unittest.TestCase helper for testing log output.""" 
  2   
  3  import sys 
  4  import time 
  5   
  6  import cherrypy 
  7  from cherrypy._cpcompat import basestring, ntob, unicodestr 
  8   
  9   
 10  try: 
 11      # On Windows, msvcrt.getch reads a single char without output. 
 12      import msvcrt 
 13   
14 - def getchar():
15 return msvcrt.getch()
16 except ImportError: 17 # Unix getchr 18 import tty 19 import termios 20
21 - def getchar():
22 fd = sys.stdin.fileno() 23 old_settings = termios.tcgetattr(fd) 24 try: 25 tty.setraw(sys.stdin.fileno()) 26 ch = sys.stdin.read(1) 27 finally: 28 termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) 29 return ch
30 31
32 -class LogCase(object):
33 34 """unittest.TestCase mixin for testing log messages. 35 36 logfile: a filename for the desired log. Yes, I know modes are evil, 37 but it makes the test functions so much cleaner to set this once. 38 39 lastmarker: the last marker in the log. This can be used to search for 40 messages since the last marker. 41 42 markerPrefix: a string with which to prefix log markers. This should be 43 unique enough from normal log output to use for marker identification. 44 """ 45 46 logfile = None 47 lastmarker = None 48 markerPrefix = ntob("test suite marker: ") 49
50 - def _handleLogError(self, msg, data, marker, pattern):
51 print("") 52 print(" ERROR: %s" % msg) 53 54 if not self.interactive: 55 raise self.failureException(msg) 56 57 p = (" Show: " 58 "[L]og [M]arker [P]attern; " 59 "[I]gnore, [R]aise, or sys.e[X]it >> ") 60 sys.stdout.write(p + ' ') 61 # ARGH 62 sys.stdout.flush() 63 while True: 64 i = getchar().upper() 65 if i not in "MPLIRX": 66 continue 67 print(i.upper()) # Also prints new line 68 if i == "L": 69 for x, line in enumerate(data): 70 if (x + 1) % self.console_height == 0: 71 # The \r and comma should make the next line overwrite 72 sys.stdout.write("<-- More -->\r ") 73 m = getchar().lower() 74 # Erase our "More" prompt 75 sys.stdout.write(" \r ") 76 if m == "q": 77 break 78 print(line.rstrip()) 79 elif i == "M": 80 print(repr(marker or self.lastmarker)) 81 elif i == "P": 82 print(repr(pattern)) 83 elif i == "I": 84 # return without raising the normal exception 85 return 86 elif i == "R": 87 raise self.failureException(msg) 88 elif i == "X": 89 self.exit() 90 sys.stdout.write(p + ' ')
91
92 - def exit(self):
93 sys.exit()
94
95 - def emptyLog(self):
96 """Overwrite self.logfile with 0 bytes.""" 97 open(self.logfile, 'wb').write("")
98
99 - def markLog(self, key=None):
100 """Insert a marker line into the log and set self.lastmarker.""" 101 if key is None: 102 key = str(time.time()) 103 self.lastmarker = key 104 105 open(self.logfile, 'ab+').write( 106 ntob("%s%s\n" % (self.markerPrefix, key), "utf-8"))
107
108 - def _read_marked_region(self, marker=None):
109 """Return lines from self.logfile in the marked region. 110 111 If marker is None, self.lastmarker is used. If the log hasn't 112 been marked (using self.markLog), the entire log will be returned. 113 """ 114 # Give the logger time to finish writing? 115 # time.sleep(0.5) 116 117 logfile = self.logfile 118 marker = marker or self.lastmarker 119 if marker is None: 120 return open(logfile, 'rb').readlines() 121 122 if isinstance(marker, unicodestr): 123 marker = marker.encode('utf-8') 124 data = [] 125 in_region = False 126 for line in open(logfile, 'rb'): 127 if in_region: 128 if (line.startswith(self.markerPrefix) and not marker in line): 129 break 130 else: 131 data.append(line) 132 elif marker in line: 133 in_region = True 134 return data
135
136 - def assertInLog(self, line, marker=None):
137 """Fail if the given (partial) line is not in the log. 138 139 The log will be searched from the given marker to the next marker. 140 If marker is None, self.lastmarker is used. If the log hasn't 141 been marked (using self.markLog), the entire log will be searched. 142 """ 143 data = self._read_marked_region(marker) 144 for logline in data: 145 if line in logline: 146 return 147 msg = "%r not found in log" % line 148 self._handleLogError(msg, data, marker, line)
149
150 - def assertNotInLog(self, line, marker=None):
151 """Fail if the given (partial) line is in the log. 152 153 The log will be searched from the given marker to the next marker. 154 If marker is None, self.lastmarker is used. If the log hasn't 155 been marked (using self.markLog), the entire log will be searched. 156 """ 157 data = self._read_marked_region(marker) 158 for logline in data: 159 if line in logline: 160 msg = "%r found in log" % line 161 self._handleLogError(msg, data, marker, line)
162
163 - def assertLog(self, sliceargs, lines, marker=None):
164 """Fail if log.readlines()[sliceargs] is not contained in 'lines'. 165 166 The log will be searched from the given marker to the next marker. 167 If marker is None, self.lastmarker is used. If the log hasn't 168 been marked (using self.markLog), the entire log will be searched. 169 """ 170 data = self._read_marked_region(marker) 171 if isinstance(sliceargs, int): 172 # Single arg. Use __getitem__ and allow lines to be str or list. 173 if isinstance(lines, (tuple, list)): 174 lines = lines[0] 175 if isinstance(lines, unicodestr): 176 lines = lines.encode('utf-8') 177 if lines not in data[sliceargs]: 178 msg = "%r not found on log line %r" % (lines, sliceargs) 179 self._handleLogError( 180 msg, 181 [data[sliceargs], "--EXTRA CONTEXT--"] + data[ 182 sliceargs + 1:sliceargs + 6], 183 marker, 184 lines) 185 else: 186 # Multiple args. Use __getslice__ and require lines to be list. 187 if isinstance(lines, tuple): 188 lines = list(lines) 189 elif isinstance(lines, basestring): 190 raise TypeError("The 'lines' arg must be a list when " 191 "'sliceargs' is a tuple.") 192 193 start, stop = sliceargs 194 for line, logline in zip(lines, data[start:stop]): 195 if isinstance(line, unicodestr): 196 line = line.encode('utf-8') 197 if line not in logline: 198 msg = "%r not found in log" % line 199 self._handleLogError(msg, data[start:stop], marker, line)
200