tests: Make httpbin.Request a proper class.

This commit is contained in:
Florian Bruhin 2015-11-16 23:14:24 +01:00
parent bc96da47ef
commit 7fe9be432a
5 changed files with 90 additions and 35 deletions

View File

@ -99,12 +99,12 @@ def wait_for_message(quteproc, httpbin, category, message):
@bdd.then(bdd.parsers.parse("{path} should be loaded"))
def path_should_be_loaded(httpbin, path):
requests = httpbin.get_requests()
assert requests[-1] == httpbin.Request('GET', '/' + path)
assert requests[-1] == httpbin.ExpectedRequest('GET', '/' + path)
@bdd.then(bdd.parsers.parse("The requests should be:\n{pages}"))
def list_of_loaded_pages(httpbin, pages):
expected_requests = [httpbin.Request('GET', '/' + path.strip())
expected_requests = [httpbin.ExpectedRequest('GET', '/' + path.strip())
for path in pages.split('\n')]
actual_requests = httpbin.get_requests()
assert actual_requests == expected_requests

View File

@ -47,13 +47,6 @@ def is_ignored_qt_message(message):
return False
class NoLineMatch(Exception):
"""Raised by LogLine on unmatched lines."""
pass
class LogLine(testprocess.Line):
"""A parsed line from the qutebrowser log output.
@ -78,7 +71,7 @@ class LogLine(testprocess.Line):
super().__init__(data)
match = self.LOG_RE.match(data)
if match is None:
raise NoLineMatch(data)
raise testprocess.InvalidLine(data)
self.timestamp = datetime.datetime.strptime(match.group('timestamp'),
'%H:%M:%S')
@ -138,7 +131,7 @@ class QuteProc(testprocess.Process):
def _parse_line(self, line):
try:
log_line = LogLine(line)
except NoLineMatch:
except testprocess.InvalidLine:
if line.startswith(' '):
# Multiple lines in some log output...
return None
@ -147,7 +140,7 @@ class QuteProc(testprocess.Process):
elif is_ignored_qt_message(line):
return None
else:
raise testprocess.InvalidLine
raise
if (log_line.loglevel in ['INFO', 'WARNING', 'ERROR'] or
pytest.config.getoption('--verbose')):

View File

@ -25,6 +25,7 @@ import datetime
import pytest
import quteprocess
import testprocess
from qutebrowser.utils import log
@ -113,5 +114,5 @@ def test_log_line_parse(data, attrs):
def test_log_line_no_match():
with pytest.raises(quteprocess.NoLineMatch):
with pytest.raises(testprocess.InvalidLine):
quteprocess.LogLine("Hello World!")

View File

@ -46,5 +46,19 @@ def test_httpbin(httpbin, qtbot, path, content, expected):
data = response.read().decode('utf-8')
assert httpbin.get_requests() == [httpbin.Request('GET', path)]
assert httpbin.get_requests() == [httpbin.ExpectedRequest('GET', path)]
assert (content in data) == 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 / 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),
])
def test_expected_request(httpbin, line, verb, path, equal):
expected = httpbin.ExpectedRequest(verb, path)
request = httpbin.Request(line)
assert (expected == request) == equal

View File

@ -26,7 +26,7 @@ import re
import sys
import socket
import os.path
import collections
import datetime
import pytest
from PyQt5.QtCore import pyqtSignal
@ -34,25 +34,17 @@ from PyQt5.QtCore import pyqtSignal
import testprocess # pylint: disable=import-error
Request = collections.namedtuple('Request', 'verb, path')
class Request(testprocess.Line):
"""A parsed line from the httpbin/flask log output.
class HTTPBin(testprocess.Process):
"""Abstraction over a running HTTPbin server process.
Reads the log from its stdout and parses it.
Attributes:
timestamp/verb/path/status: Parsed from the log output.
Class attributes:
LOG_RE: Used to parse the CLF log which httpbin outputs.
Signals:
new_request: Emitted when there's a new request received.
"""
new_request = pyqtSignal(Request)
Request = Request # So it can be used from the fixture easily.
LOG_RE = re.compile(r"""
(?P<host>[^ ]*)
\ ([^ ]*) # ignored
@ -67,6 +59,68 @@ class HTTPBin(testprocess.Process):
\ (?P<size>[^ ]*)
""", re.VERBOSE)
def __init__(self, data):
super().__init__(data)
match = self.LOG_RE.match(data)
if match is None:
raise testprocess.InvalidLine(data)
assert match.group('host') == '127.0.0.1'
assert match.group('user') == '-'
self.timestamp = datetime.datetime.strptime(match.group('date'),
'%d/%b/%Y %H:%M:%S')
self.verb = match.group('verb')
# FIXME do we need to allow other options?
assert match.group('protocol') == 'HTTP/1.1'
assert self.verb == 'GET'
self.path = match.group('path')
self.status = int(match.group('status'))
missing_paths = ['/favicon.ico', '/does-not-exist']
if self.path in missing_paths:
assert self.status == 404
else:
assert self.status < 400
assert match.group('size') == '-'
def __eq__(self, other):
return NotImplemented
class ExpectedRequest:
"""Class to compare expected requests easily."""
def __init__(self, verb, path):
self.verb = verb
self.path = path
def __eq__(self, other):
if isinstance(other, (Request, ExpectedRequest)):
return (self.verb == other.verb and
self.path == other.path)
else:
return NotImplemented
class HTTPBin(testprocess.Process):
"""Abstraction over a running HTTPbin server process.
Reads the log from its stdout and parses it.
Signals:
new_request: Emitted when there's a new request received.
"""
new_request = pyqtSignal(Request)
Request = Request # So it can be used from the fixture easily.
ExpectedRequest = ExpectedRequest
KEYS = ['verb', 'path']
def __init__(self, parent=None):
@ -93,14 +147,7 @@ class HTTPBin(testprocess.Process):
'quit)'.format(self.port)):
self.ready.emit()
return None
match = self.LOG_RE.match(line)
if match is None:
raise testprocess.InvalidLine
# FIXME do we need to allow other options?
assert match.group('protocol') == 'HTTP/1.1'
return Request(verb=match.group('verb'), path=match.group('path'))
return Request(line)
def _executable_args(self):
if hasattr(sys, 'frozen'):