Skip to content

Commit 87375aa

Browse files
committed
Refactor test_logging to use pytest
1 parent 5466c11 commit 87375aa

1 file changed

Lines changed: 191 additions & 114 deletions

File tree

cherrypy/test/test_logging.py

Lines changed: 191 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
11
"""Basic tests for the CherryPy core: request handling."""
22

33
import logging
4-
import os
5-
from unittest import mock
64

5+
from cheroot.test import webtest
76
import pytest
87
import requests # FIXME: Temporary using it directly, better switch
98

109
import cherrypy
11-
from cherrypy._cpcompat import ntou
12-
from cherrypy.test import helper, logtest
10+
from cherrypy.test.logtest import LogCase
1311

14-
localDir = os.path.dirname(__file__)
15-
access_log = os.path.join(localDir, 'access.log')
16-
error_log = os.path.join(localDir, 'error.log')
1712

1813
# Some unicode strings.
19-
tartaros = ntou('\u03a4\u1f71\u03c1\u03c4\u03b1\u03c1\u03bf\u03c2', 'escape')
20-
erebos = ntou('\u0388\u03c1\u03b5\u03b2\u03bf\u03c2.com', 'escape')
14+
tartaros = u'\u03a4\u1f71\u03c1\u03c4\u03b1\u03c1\u03bf\u03c2'
15+
erebos = u'\u0388\u03c1\u03b5\u03b2\u03bf\u03c2.com'
2116

2217

2318
@pytest.fixture
24-
def server():
25-
setup_server()
19+
def access_log_file(tmp_path_factory):
20+
return tmp_path_factory.mktemp('logs') / 'access.log'
21+
22+
23+
@pytest.fixture
24+
def error_log_file(tmp_path_factory):
25+
return tmp_path_factory.mktemp('logs') / 'access.log'
26+
27+
28+
@pytest.fixture
29+
def server(configure_server):
2630
cherrypy.engine.start()
31+
cherrypy.engine.wait(cherrypy.engine.states.STARTED)
2732

2833
yield
2934

@@ -32,14 +37,16 @@ def server():
3237

3338
def shutdown_server():
3439
cherrypy.engine.exit()
40+
cherrypy.engine.block()
3541

3642
servers_copy = list(getattr(cherrypy, 'servers', {}).items())
3743
for name, server in servers_copy:
3844
server.unsubscribe()
3945
del cherrypy.servers[name]
4046

4147

42-
def setup_server():
48+
@pytest.fixture
49+
def configure_server(access_log_file, error_log_file):
4350
class Root:
4451

4552
@cherrypy.expose
@@ -79,130 +86,200 @@ def error(self):
7986

8087
root = Root()
8188

89+
cherrypy.config.reset()
90+
cherrypy.config.update({
91+
'server.socket_host': webtest.WebCase.HOST,
92+
'server.socket_port': webtest.WebCase.PORT,
93+
'server.protocol_version': webtest.WebCase.PROTOCOL,
94+
'environment': 'test_suite',
95+
})
8296
cherrypy.config.update({
83-
'log.error_file': error_log,
84-
'log.access_file': access_log,
97+
'log.error_file': str(error_log_file),
98+
'log.access_file': str(access_log_file),
8599
})
86100
cherrypy.tree.mount(root)
87101

88102

89-
class AccessLogTests(helper.CPWebCase, logtest.LogCase):
90-
setup_server = staticmethod(setup_server)
91-
92-
logfile = access_log
93-
94-
def testNormalReturn(self):
95-
self.markLog()
96-
self.getPage('/as_string',
97-
headers=[('Referer', 'http://www.cherrypy.org/'),
98-
('User-Agent', 'Mozilla/5.0')])
99-
self.assertBody('content')
100-
self.assertStatus(200)
101-
102-
intro = '%s - - [' % self.interface()
103-
104-
self.assertLog(-1, intro)
105-
106-
if [k for k, v in self.headers if k.lower() == 'content-length']:
107-
self.assertLog(-1, '] "GET %s/as_string HTTP/1.1" 200 7 '
108-
'"http://www.cherrypy.org/" "Mozilla/5.0"'
109-
% self.prefix())
110-
else:
111-
self.assertLog(-1, '] "GET %s/as_string HTTP/1.1" 200 - '
112-
'"http://www.cherrypy.org/" "Mozilla/5.0"'
113-
% self.prefix())
103+
@pytest.fixture
104+
def log_tracker(access_log_file):
105+
class LogTracker(LogCase):
106+
logfile = str(access_log_file)
107+
return LogTracker()
108+
109+
110+
def test_normal_return(log_tracker, server):
111+
log_tracker.markLog()
112+
host = webtest.interface(webtest.WebCase.HOST)
113+
port = webtest.WebCase.PORT
114+
resp = requests.get(
115+
'http://%s:%s/as_string' % (host, port),
116+
headers={
117+
'Referer': 'http://www.cherrypy.org/',
118+
'User-Agent': 'Mozilla/5.0',
119+
},
120+
)
121+
expected_body = 'content'
122+
assert resp.text == expected_body
123+
assert resp.status_code == 200
124+
125+
intro = '%s - - [' % host
126+
127+
log_tracker.assertLog(-1, intro)
128+
129+
content_length = len(expected_body)
130+
if not any(
131+
k for k, v in resp.headers.items()
132+
if k.lower() == 'content-length'
133+
):
134+
content_length = '-'
135+
136+
log_tracker.assertLog(
137+
-1,
138+
'] "GET /as_string HTTP/1.1" 200 %s '
139+
'"http://www.cherrypy.org/" "Mozilla/5.0"'
140+
% content_length,
141+
)
114142

115-
def testNormalYield(self):
116-
self.markLog()
117-
self.getPage('/as_yield')
118-
self.assertBody('content')
119-
self.assertStatus(200)
120143

121-
intro = '%s - - [' % self.interface()
144+
def test_normal_yield(log_tracker, server):
145+
log_tracker.markLog()
146+
host = webtest.interface(webtest.WebCase.HOST)
147+
port = webtest.WebCase.PORT
148+
resp = requests.get(
149+
'http://%s:%s/as_yield' % (host, port),
150+
headers={
151+
'User-Agent': '',
152+
},
153+
)
154+
expected_body = 'content'
155+
assert resp.text == expected_body
156+
assert resp.status_code == 200
157+
158+
intro = '%s - - [' % host
159+
160+
log_tracker.assertLog(-1, intro)
161+
content_length = len(expected_body)
162+
if not any(
163+
k for k, v in resp.headers.items()
164+
if k.lower() == 'content-length'
165+
):
166+
content_length = '-'
167+
168+
log_tracker.assertLog(
169+
-1,
170+
'] "GET /as_yield HTTP/1.1" 200 %s "" ""'
171+
% content_length,
172+
)
122173

123-
self.assertLog(-1, intro)
124-
if [k for k, v in self.headers if k.lower() == 'content-length']:
125-
self.assertLog(-1, '] "GET %s/as_yield HTTP/1.1" 200 7 "" ""' %
126-
self.prefix())
127-
else:
128-
self.assertLog(-1, '] "GET %s/as_yield HTTP/1.1" 200 - "" ""'
129-
% self.prefix())
130174

131-
@mock.patch(
175+
def test_custom_log_format(log_tracker, monkeypatch, server):
176+
"""Test a customized access_log_format string, which is a
177+
feature of _cplogging.LogManager.access()."""
178+
monkeypatch.setattr(
132179
'cherrypy._cplogging.LogManager.access_log_format',
133180
'{h} {l} {u} {t} "{r}" {s} {b} "{f}" "{a}" {o}',
134181
)
135-
def testCustomLogFormat(self):
136-
"""Test a customized access_log_format string, which is a
137-
feature of _cplogging.LogManager.access()."""
138-
self.markLog()
139-
self.getPage('/as_string', headers=[('Referer', 'REFERER'),
140-
('User-Agent', 'USERAGENT'),
141-
('Host', 'HOST')])
142-
self.assertLog(-1, '%s - - [' % self.interface())
143-
self.assertLog(-1, '] "GET /as_string HTTP/1.1" '
144-
'200 7 "REFERER" "USERAGENT" HOST')
145-
146-
@mock.patch(
182+
log_tracker.markLog()
183+
host = webtest.interface(webtest.WebCase.HOST)
184+
port = webtest.WebCase.PORT
185+
requests.get(
186+
'http://%s:%s/as_string' % (host, port),
187+
headers={
188+
'Referer': 'REFERER',
189+
'User-Agent': 'USERAGENT',
190+
'Host': 'HOST',
191+
},
192+
)
193+
log_tracker.assertLog(-1, '%s - - [' % host)
194+
log_tracker.assertLog(
195+
-1,
196+
'] "GET /as_string HTTP/1.1" '
197+
'200 7 "REFERER" "USERAGENT" HOST',
198+
)
199+
200+
201+
def test_timez_log_format(log_tracker, monkeypatch, server):
202+
"""Test a customized access_log_format string, which is a
203+
feature of _cplogging.LogManager.access()."""
204+
monkeypatch.setattr(
147205
'cherrypy._cplogging.LogManager.access_log_format',
148206
'{h} {l} {u} {z} "{r}" {s} {b} "{f}" "{a}" {o}',
149207
)
150-
def testTimezLogFormat(self):
151-
"""Test a customized access_log_format string, which is a
152-
feature of _cplogging.LogManager.access()."""
153-
self.markLog()
154-
155-
expected_time = str(cherrypy._cplogging.LazyRfc3339UtcTime())
156-
with mock.patch(
157-
'cherrypy._cplogging.LazyRfc3339UtcTime',
158-
lambda: expected_time):
159-
self.getPage('/as_string', headers=[('Referer', 'REFERER'),
160-
('User-Agent', 'USERAGENT'),
161-
('Host', 'HOST')])
162-
163-
self.assertLog(-1, '%s - - ' % self.interface())
164-
self.assertLog(-1, expected_time)
165-
self.assertLog(-1, ' "GET /as_string HTTP/1.1" '
166-
'200 7 "REFERER" "USERAGENT" HOST')
167-
168-
@mock.patch(
208+
log_tracker.markLog()
209+
210+
expected_time = str(cherrypy._cplogging.LazyRfc3339UtcTime())
211+
monkeypatch.setattr(
212+
'cherrypy._cplogging.LazyRfc3339UtcTime',
213+
lambda: expected_time,
214+
)
215+
host = webtest.interface(webtest.WebCase.HOST)
216+
port = webtest.WebCase.PORT
217+
requests.get(
218+
'http://%s:%s/as_string' % (host, port),
219+
headers={
220+
'Referer': 'REFERER',
221+
'User-Agent': 'USERAGENT',
222+
'Host': 'HOST',
223+
},
224+
)
225+
226+
log_tracker.assertLog(-1, '%s - - ' % host)
227+
log_tracker.assertLog(-1, expected_time)
228+
log_tracker.assertLog(
229+
-1,
230+
' "GET /as_string HTTP/1.1" '
231+
'200 7 "REFERER" "USERAGENT" HOST',
232+
)
233+
234+
235+
def test_UUIDv4_parameter_log_format(log_tracker, monkeypatch, server):
236+
"""Test rendering of UUID4 within access log."""
237+
monkeypatch.setattr(
169238
'cherrypy._cplogging.LogManager.access_log_format',
170239
'{i}',
171240
)
172-
def testUUIDv4ParameterLogFormat(self):
173-
"""Test rendering of UUID4 within access log."""
174-
self.markLog()
175-
self.getPage('/as_string')
176-
self.assertValidUUIDv4()
177-
178-
def testEscapedOutput(self):
179-
# Test unicode in access log pieces.
180-
self.markLog()
181-
self.getPage('/uni_code')
182-
self.assertStatus(200)
183-
# The repr of a bytestring includes a b'' prefix
184-
self.assertLog(-1, repr(tartaros.encode('utf8'))[2:-1])
185-
# Test the erebos value. Included inline for your enlightenment.
186-
# Note the 'r' prefix--those backslashes are literals.
187-
self.assertLog(-1, r'\xce\x88\xcf\x81\xce\xb5\xce\xb2\xce\xbf\xcf\x82')
188-
189-
# Test backslashes in output.
190-
self.markLog()
191-
self.getPage('/slashes')
192-
self.assertStatus(200)
193-
self.assertLog(-1, b'"GET /slashed\\path HTTP/1.1"')
194-
195-
# Test whitespace in output.
196-
self.markLog()
197-
self.getPage('/whitespace')
198-
self.assertStatus(200)
199-
# Again, note the 'r' prefix.
200-
self.assertLog(-1, r'"Browzuh (1.0\r\n\t\t.3)"')
241+
log_tracker.markLog()
242+
host = webtest.interface(webtest.WebCase.HOST)
243+
port = webtest.WebCase.PORT
244+
requests.get('http://%s:%s/as_string' % (host, port))
245+
log_tracker.assertValidUUIDv4()
246+
247+
248+
def test_escaped_output(log_tracker, server):
249+
# Test unicode in access log pieces.
250+
log_tracker.markLog()
251+
host = webtest.interface(webtest.WebCase.HOST)
252+
port = webtest.WebCase.PORT
253+
resp = requests.get('http://%s:%s/uni_code' % (host, port))
254+
assert resp.status_code == 200
255+
# The repr of a bytestring includes a b'' prefix
256+
log_tracker.assertLog(-1, repr(tartaros.encode('utf8'))[2:-1])
257+
# Test the erebos value. Included inline for your enlightenment.
258+
# Note the 'r' prefix--those backslashes are literals.
259+
log_tracker.assertLog(
260+
-1,
261+
r'\xce\x88\xcf\x81\xce\xb5\xce\xb2\xce\xbf\xcf\x82',
262+
)
263+
264+
# Test backslashes in output.
265+
log_tracker.markLog()
266+
resp = requests.get('http://%s:%s/slashes' % (host, port))
267+
assert resp.status_code == 200
268+
log_tracker.assertLog(-1, b'"GET /slashed\\path HTTP/1.1"')
269+
270+
# Test whitespace in output.
271+
log_tracker.markLog()
272+
resp = requests.get('http://%s:%s/whitespace' % (host, port))
273+
assert resp.status_code == 200
274+
# Again, note the 'r' prefix.
275+
log_tracker.assertLog(-1, r'"Browzuh (1.0\r\n\t\t.3)"')
201276

202277

203278
def test_tracebacks(server, caplog):
279+
host = webtest.interface(webtest.WebCase.HOST)
280+
port = webtest.WebCase.PORT
204281
with caplog.at_level(logging.ERROR, logger='cherrypy.error'):
205-
resp = requests.get('http://127.0.0.1:54583/error')
282+
resp = requests.get('http://%s:%s/error' % (host, port))
206283

207284
rec = caplog.records[0]
208285
exc_cls, exc_msg = rec.exc_info[0], rec.message

0 commit comments

Comments
 (0)