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