tests: Use JSON for webserver_sub logging.

This simplifies logging output and parsing.
This commit is contained in:
Florian Bruhin 2015-11-26 14:37:47 +01:00
parent b8467b8fef
commit 7eb6f658eb
3 changed files with 23 additions and 48 deletions

View File

@ -19,6 +19,7 @@
"""Test the httpbin webserver used for tests."""
import json
import urllib.request
import urllib.error
@ -51,17 +52,13 @@ def test_httpbin(httpbin, qtbot, path, content, expected):
@pytest.mark.parametrize('line, verb, path, equal', [
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
'GET', '/', True),
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET /foo/ HTTP/1.1" 200 -',
'GET', '/foo', True),
({'verb': 'GET', 'path': '/', 'status': 200}, 'GET', '/', True),
({'verb': 'GET', 'path': '/foo/', 'status': 200}, 'GET', '/foo', True),
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
'GET', '/foo', False),
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
'POST', '/foo', False),
({'verb': 'GET', 'path': '/', 'status': 200}, 'GET', '/foo', False),
({'verb': 'POST', 'path': '/', 'status': 200}, 'GET', '/', False),
])
def test_expected_request(httpbin, line, verb, path, equal):
expected = httpbin.ExpectedRequest(verb, path)
request = httpbin.Request(line)
request = httpbin.Request(json.dumps(line))
assert (expected == request) == equal

View File

@ -24,6 +24,7 @@
import re
import sys
import json
import socket
import os.path
@ -38,45 +39,25 @@ class Request(testprocess.Line):
"""A parsed line from the httpbin/flask log output.
Attributes:
timestamp/verb/path/status: Parsed from the log output.
Class attributes:
LOG_RE: Used to parse the CLF log which httpbin outputs.
verb/path/status: Parsed from the log output.
"""
LOG_RE = re.compile(r"""
(?P<host>[^ ]*)
\ ([^ ]*) # ignored
\ (?P<user>[^ ]*)
\ \[(?P<date>[^]]*)\]
\ "(?P<request>
(?P<verb>[^ ]*)
\ (?P<path>[^ ]*)
\ (?P<protocol>[^ ]*)
)"
\ (?P<status>[^ ]*)
\ (?P<size>[^ ]*)
""", re.VERBOSE)
def __init__(self, data):
super().__init__(data)
match = self.LOG_RE.match(data)
if match is None:
try:
parsed = json.loads(data)
except ValueError:
raise testprocess.InvalidLine(data)
assert match.group('host') == '127.0.0.1'
assert match.group('user') == '-'
self.timestamp = match.group('date')
self.verb = match.group('verb')
assert isinstance(parsed, dict)
assert set(parsed.keys()) == {'path', 'verb', 'status'}
# FIXME do we need to allow other options?
assert match.group('protocol') == 'HTTP/1.1'
assert self.verb == 'GET'
self.verb = parsed['verb']
path = match.group('path')
path = parsed['path']
self.path = '/' if path == '/' else path.rstrip('/')
self.status = int(match.group('status'))
self.status = parsed['status']
missing_paths = ['/favicon.ico', '/does-not-exist']
@ -85,8 +66,6 @@ class Request(testprocess.Line):
else:
assert self.status < 400
assert match.group('size') == '-'
def __eq__(self, other):
return NotImplemented

View File

@ -23,6 +23,7 @@ This script gets called as a QProcess from integration/conftest.py.
"""
import sys
import json
import time
import signal
import os
@ -87,14 +88,12 @@ def redirect_later_continue():
def log_request(response):
"""Log a webserver request."""
request = flask.request
template = '127.0.0.1 - - [{date}] "{verb} {path} {http}" {status} -'
print(template.format(
date=datetime.now().strftime('%d/%b/%Y %H:%M:%S'),
verb=request.method,
path=request.full_path if request.query_string else request.path,
http=request.environ['SERVER_PROTOCOL'],
status=response.status_code,
), file=sys.stderr, flush=True)
data = {
'verb': request.method,
'path': request.full_path if request.query_string else request.path,
'status': response.status_code,
}
print(json.dumps(data), file=sys.stderr, flush=True)
return response