Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

root/trunk/cherrypy/test/logtest.py

Revision 1984 (checked in by fumanchu, 5 months ago)

Fix for #824 (_cplogging.LogManager?.access method not handling unicode in login names properly). While I was at it, I made the access log template configurable, moved the log tests from test_core into test_logging, and added a new logtest module.

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

Hosted by WebFaction

Log in as guest/cpguest to create tickets