tests: Use JSON for webserver_sub logging.
This simplifies logging output and parsing.
This commit is contained in:
parent
b8467b8fef
commit
7eb6f658eb
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
"""Test the httpbin webserver used for tests."""
|
"""Test the httpbin webserver used for tests."""
|
||||||
|
|
||||||
|
import json
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
|
||||||
@ -51,17 +52,13 @@ def test_httpbin(httpbin, qtbot, path, content, expected):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('line, verb, path, equal', [
|
@pytest.mark.parametrize('line, verb, path, equal', [
|
||||||
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
|
({'verb': 'GET', 'path': '/', 'status': 200}, 'GET', '/', True),
|
||||||
'GET', '/', True),
|
({'verb': 'GET', 'path': '/foo/', 'status': 200}, 'GET', '/foo', True),
|
||||||
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET /foo/ HTTP/1.1" 200 -',
|
|
||||||
'GET', '/foo', True),
|
|
||||||
|
|
||||||
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
|
({'verb': 'GET', 'path': '/', 'status': 200}, 'GET', '/foo', False),
|
||||||
'GET', '/foo', False),
|
({'verb': 'POST', 'path': '/', 'status': 200}, 'GET', '/', False),
|
||||||
('127.0.0.1 - - [01/Jan/1990 00:00:00] "GET / HTTP/1.1" 200 -',
|
|
||||||
'POST', '/foo', False),
|
|
||||||
])
|
])
|
||||||
def test_expected_request(httpbin, line, verb, path, equal):
|
def test_expected_request(httpbin, line, verb, path, equal):
|
||||||
expected = httpbin.ExpectedRequest(verb, path)
|
expected = httpbin.ExpectedRequest(verb, path)
|
||||||
request = httpbin.Request(line)
|
request = httpbin.Request(json.dumps(line))
|
||||||
assert (expected == request) == equal
|
assert (expected == request) == equal
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
import socket
|
import socket
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
@ -38,45 +39,25 @@ class Request(testprocess.Line):
|
|||||||
"""A parsed line from the httpbin/flask log output.
|
"""A parsed line from the httpbin/flask log output.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
timestamp/verb/path/status: Parsed from the log output.
|
verb/path/status: Parsed from the log output.
|
||||||
|
|
||||||
Class attributes:
|
|
||||||
LOG_RE: Used to parse the CLF log which httpbin outputs.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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):
|
def __init__(self, data):
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
match = self.LOG_RE.match(data)
|
try:
|
||||||
if match is None:
|
parsed = json.loads(data)
|
||||||
|
except ValueError:
|
||||||
raise testprocess.InvalidLine(data)
|
raise testprocess.InvalidLine(data)
|
||||||
|
|
||||||
assert match.group('host') == '127.0.0.1'
|
assert isinstance(parsed, dict)
|
||||||
assert match.group('user') == '-'
|
assert set(parsed.keys()) == {'path', 'verb', 'status'}
|
||||||
self.timestamp = match.group('date')
|
|
||||||
self.verb = match.group('verb')
|
|
||||||
|
|
||||||
# FIXME do we need to allow other options?
|
self.verb = parsed['verb']
|
||||||
assert match.group('protocol') == 'HTTP/1.1'
|
|
||||||
assert self.verb == 'GET'
|
|
||||||
|
|
||||||
path = match.group('path')
|
path = parsed['path']
|
||||||
self.path = '/' if path == '/' else path.rstrip('/')
|
self.path = '/' if path == '/' else path.rstrip('/')
|
||||||
|
|
||||||
self.status = int(match.group('status'))
|
self.status = parsed['status']
|
||||||
|
|
||||||
missing_paths = ['/favicon.ico', '/does-not-exist']
|
missing_paths = ['/favicon.ico', '/does-not-exist']
|
||||||
|
|
||||||
@ -85,8 +66,6 @@ class Request(testprocess.Line):
|
|||||||
else:
|
else:
|
||||||
assert self.status < 400
|
assert self.status < 400
|
||||||
|
|
||||||
assert match.group('size') == '-'
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ This script gets called as a QProcess from integration/conftest.py.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
import signal
|
import signal
|
||||||
import os
|
import os
|
||||||
@ -87,14 +88,12 @@ def redirect_later_continue():
|
|||||||
def log_request(response):
|
def log_request(response):
|
||||||
"""Log a webserver request."""
|
"""Log a webserver request."""
|
||||||
request = flask.request
|
request = flask.request
|
||||||
template = '127.0.0.1 - - [{date}] "{verb} {path} {http}" {status} -'
|
data = {
|
||||||
print(template.format(
|
'verb': request.method,
|
||||||
date=datetime.now().strftime('%d/%b/%Y %H:%M:%S'),
|
'path': request.full_path if request.query_string else request.path,
|
||||||
verb=request.method,
|
'status': response.status_code,
|
||||||
path=request.full_path if request.query_string else request.path,
|
}
|
||||||
http=request.environ['SERVER_PROTOCOL'],
|
print(json.dumps(data), file=sys.stderr, flush=True)
|
||||||
status=response.status_code,
|
|
||||||
), file=sys.stderr, flush=True)
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user