mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
test response model, push coverage to 100% branch cov
This commit is contained in:
parent
466888b01a
commit
23d13e4c12
@ -58,6 +58,7 @@ def _read_quoted_string(s, start):
|
||||
escaping = False
|
||||
ret = []
|
||||
# Skip the first quote
|
||||
i = start # initialize in case the loop doesn't run.
|
||||
for i in range(start + 1, len(s)):
|
||||
if escaping:
|
||||
ret.append(s[i])
|
||||
|
@ -18,6 +18,16 @@ else:
|
||||
_always_bytes = lambda x: utils.always_bytes(x, "utf-8", "surrogateescape")
|
||||
|
||||
|
||||
class MessageData(object):
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, MessageData):
|
||||
return self.__dict__ == other.__dict__
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class Message(object):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
@ -10,10 +10,10 @@ from netlib.http import cookies
|
||||
from netlib.odict import ODict
|
||||
from .. import encoding
|
||||
from .headers import Headers
|
||||
from .message import Message, _native, _always_bytes
|
||||
from .message import Message, _native, _always_bytes, MessageData
|
||||
|
||||
|
||||
class RequestData(object):
|
||||
class RequestData(MessageData):
|
||||
def __init__(self, first_line_format, method, scheme, host, port, path, http_version, headers=None, content=None,
|
||||
timestamp_start=None, timestamp_end=None):
|
||||
if not headers:
|
||||
@ -32,14 +32,6 @@ class RequestData(object):
|
||||
self.timestamp_start = timestamp_start
|
||||
self.timestamp_end = timestamp_end
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, RequestData):
|
||||
return self.__dict__ == other.__dict__
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class Request(Message):
|
||||
"""
|
||||
|
@ -4,12 +4,12 @@ import warnings
|
||||
|
||||
from . import cookies
|
||||
from .headers import Headers
|
||||
from .message import Message, _native, _always_bytes
|
||||
from .message import Message, _native, _always_bytes, MessageData
|
||||
from .. import utils
|
||||
from ..odict import ODict
|
||||
|
||||
|
||||
class ResponseData(object):
|
||||
class ResponseData(MessageData):
|
||||
def __init__(self, http_version, status_code, reason=None, headers=None, content=None,
|
||||
timestamp_start=None, timestamp_end=None):
|
||||
if not headers:
|
||||
@ -24,14 +24,6 @@ class ResponseData(object):
|
||||
self.timestamp_start = timestamp_start
|
||||
self.timestamp_end = timestamp_end
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, ResponseData):
|
||||
return self.__dict__ == other.__dict__
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class Response(Message):
|
||||
"""
|
||||
@ -48,7 +40,7 @@ class Response(Message):
|
||||
utils.pretty_size(len(self.content))
|
||||
)
|
||||
else:
|
||||
details = "content missing"
|
||||
details = "no content"
|
||||
return "Response({status_code} {reason}, {details})".format(
|
||||
status_code=self.status_code,
|
||||
reason=self.reason,
|
||||
|
@ -78,10 +78,19 @@ def test_assemble_request_headers():
|
||||
# https://github.com/mitmproxy/mitmproxy/issues/186
|
||||
r = treq(content=b"")
|
||||
r.headers["Transfer-Encoding"] = "chunked"
|
||||
c = _assemble_request_headers(r)
|
||||
c = _assemble_request_headers(r.data)
|
||||
assert b"Transfer-Encoding" in c
|
||||
|
||||
assert b"host" in _assemble_request_headers(treq(headers=Headers()))
|
||||
|
||||
def test_assemble_request_headers_host_header():
|
||||
r = treq()
|
||||
r.headers = Headers()
|
||||
c = _assemble_request_headers(r.data)
|
||||
assert b"host" in c
|
||||
|
||||
r.host = None
|
||||
c = _assemble_request_headers(r.data)
|
||||
assert b"host" not in c
|
||||
|
||||
|
||||
def test_assemble_response_headers():
|
||||
|
@ -117,6 +117,9 @@ def test_connection_close():
|
||||
headers["connection"] = "close"
|
||||
assert connection_close(b"HTTP/1.1", headers)
|
||||
|
||||
headers["connection"] = "foobar"
|
||||
assert connection_close(b"HTTP/1.0", headers)
|
||||
assert not connection_close(b"HTTP/1.1", headers)
|
||||
|
||||
def test_expected_http_body_size():
|
||||
# Expect: 100-continue
|
||||
|
@ -21,6 +21,7 @@ def test_read_quoted_string():
|
||||
[(r'"f\\o" x', 0), (r"f\o", 6)],
|
||||
[(r'"f\\" x', 0), (r"f" + '\\', 5)],
|
||||
[('"fo\\\"" x', 0), ("fo\"", 6)],
|
||||
[('"foo" x', 7), ("", 8)],
|
||||
]
|
||||
for q, a in tokens:
|
||||
assert cookies._read_quoted_string(*q) == a
|
||||
|
@ -1,43 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, print_function, division
|
||||
|
||||
from netlib.http import decoded
|
||||
from netlib.tutils import tresp
|
||||
from netlib.http import decoded, Headers
|
||||
from netlib.tutils import tresp, raises
|
||||
|
||||
|
||||
def _test_passthrough_attr(message, attr):
|
||||
def t(self=None):
|
||||
assert getattr(message, attr) == getattr(message.data, attr)
|
||||
setattr(message, attr, "foo")
|
||||
assert getattr(message.data, attr) == "foo"
|
||||
return t
|
||||
assert getattr(message, attr) == getattr(message.data, attr)
|
||||
setattr(message, attr, "foo")
|
||||
assert getattr(message.data, attr) == "foo"
|
||||
|
||||
|
||||
def _test_decoded_attr(message, attr):
|
||||
def t(self=None):
|
||||
assert getattr(message, attr) == getattr(message.data, attr).decode("utf8")
|
||||
# Set str, get raw bytes
|
||||
setattr(message, attr, "foo")
|
||||
assert getattr(message.data, attr) == b"foo"
|
||||
# Set raw bytes, get decoded
|
||||
setattr(message.data, attr, b"bar")
|
||||
assert getattr(message, attr) == "bar"
|
||||
# Set bytes, get raw bytes
|
||||
setattr(message, attr, b"baz")
|
||||
assert getattr(message.data, attr) == b"baz"
|
||||
assert getattr(message, attr) == getattr(message.data, attr).decode("utf8")
|
||||
# Set str, get raw bytes
|
||||
setattr(message, attr, "foo")
|
||||
assert getattr(message.data, attr) == b"foo"
|
||||
# Set raw bytes, get decoded
|
||||
setattr(message.data, attr, b"bar")
|
||||
assert getattr(message, attr) == "bar"
|
||||
# Set bytes, get raw bytes
|
||||
setattr(message, attr, b"baz")
|
||||
assert getattr(message.data, attr) == b"baz"
|
||||
|
||||
# Set UTF8
|
||||
setattr(message, attr, "Non-Autorisé")
|
||||
assert getattr(message.data, attr) == b"Non-Autoris\xc3\xa9"
|
||||
# Don't fail on garbage
|
||||
setattr(message.data, attr, b"foo\xFF\x00bar")
|
||||
assert getattr(message, attr).startswith("foo")
|
||||
assert getattr(message, attr).endswith("bar")
|
||||
# foo.bar = foo.bar should not cause any side effects.
|
||||
d = getattr(message, attr)
|
||||
setattr(message, attr, d)
|
||||
assert getattr(message.data, attr) == b"foo\xFF\x00bar"
|
||||
return t
|
||||
# Set UTF8
|
||||
setattr(message, attr, "Non-Autorisé")
|
||||
assert getattr(message.data, attr) == b"Non-Autoris\xc3\xa9"
|
||||
# Don't fail on garbage
|
||||
setattr(message.data, attr, b"foo\xFF\x00bar")
|
||||
assert getattr(message, attr).startswith("foo")
|
||||
assert getattr(message, attr).endswith("bar")
|
||||
# foo.bar = foo.bar should not cause any side effects.
|
||||
d = getattr(message, attr)
|
||||
setattr(message, attr, d)
|
||||
assert getattr(message.data, attr) == b"foo\xFF\x00bar"
|
||||
|
||||
|
||||
class TestMessageData(object):
|
||||
def test_eq_ne(self):
|
||||
data = tresp(timestamp_start=42, timestamp_end=42).data
|
||||
same = tresp(timestamp_start=42, timestamp_end=42).data
|
||||
assert data == same
|
||||
assert not data != same
|
||||
|
||||
other = tresp(content=b"foo").data
|
||||
assert not data == other
|
||||
assert data != other
|
||||
|
||||
assert data != 0
|
||||
|
||||
|
||||
class TestMessage(object):
|
||||
@ -67,12 +77,20 @@ class TestMessage(object):
|
||||
assert resp.data.content == b""
|
||||
assert resp.headers["content-length"] == "0"
|
||||
|
||||
test_content_basic = _test_passthrough_attr(tresp(), "content")
|
||||
test_headers = _test_passthrough_attr(tresp(), "headers")
|
||||
test_timestamp_start = _test_passthrough_attr(tresp(), "timestamp_start")
|
||||
test_timestamp_end = _test_passthrough_attr(tresp(), "timestamp_end")
|
||||
def test_content_basic(self):
|
||||
_test_passthrough_attr(tresp(), "content")
|
||||
|
||||
test_http_version = _test_decoded_attr(tresp(), "http_version")
|
||||
def test_headers(self):
|
||||
_test_passthrough_attr(tresp(), "headers")
|
||||
|
||||
def test_timestamp_start(self):
|
||||
_test_passthrough_attr(tresp(), "timestamp_start")
|
||||
|
||||
def test_timestamp_end(self):
|
||||
_test_passthrough_attr(tresp(), "timestamp_end")
|
||||
|
||||
def teste_http_version(self):
|
||||
_test_decoded_attr(tresp(), "http_version")
|
||||
|
||||
|
||||
class TestDecodedDecorator(object):
|
||||
@ -133,4 +151,3 @@ class TestDecodedDecorator(object):
|
||||
|
||||
assert "content-encoding" not in r.headers
|
||||
assert r.content is None
|
||||
|
||||
|
@ -1,94 +0,0 @@
|
||||
|
||||
from netlib import tutils
|
||||
from netlib.odict import ODict, ODictCaseless
|
||||
from netlib.http import Response, Headers, CONTENT_MISSING
|
||||
|
||||
class TestResponse(object):
|
||||
def test_headers(self):
|
||||
tutils.raises(AssertionError, Response,
|
||||
b"HTTP/1.1",
|
||||
200,
|
||||
headers='foobar',
|
||||
)
|
||||
|
||||
resp = Response(
|
||||
b"HTTP/1.1",
|
||||
200,
|
||||
)
|
||||
assert isinstance(resp.headers, Headers)
|
||||
|
||||
def test_equal(self):
|
||||
a = tutils.tresp(timestamp_start=42, timestamp_end=43)
|
||||
b = tutils.tresp(timestamp_start=42, timestamp_end=43)
|
||||
assert a == b
|
||||
|
||||
assert not a == 'foo'
|
||||
assert not b == 'foo'
|
||||
assert not 'foo' == a
|
||||
assert not 'foo' == b
|
||||
|
||||
def test_repr(self):
|
||||
r = tutils.tresp()
|
||||
assert "unknown content type" in repr(r)
|
||||
r.headers["content-type"] = "foo"
|
||||
assert "foo" in repr(r)
|
||||
assert repr(tutils.tresp(content=CONTENT_MISSING))
|
||||
|
||||
def test_get_cookies_none(self):
|
||||
resp = tutils.tresp()
|
||||
resp.headers = Headers()
|
||||
assert not resp.get_cookies()
|
||||
|
||||
def test_get_cookies_simple(self):
|
||||
resp = tutils.tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=cookievalue")
|
||||
result = resp.get_cookies()
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0] == ["cookievalue", ODict()]
|
||||
|
||||
def test_get_cookies_with_parameters(self):
|
||||
resp = tutils.tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=cookievalue;domain=example.com;expires=Wed Oct 21 16:29:41 2015;path=/; HttpOnly")
|
||||
result = resp.get_cookies()
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0][0] == "cookievalue"
|
||||
attrs = result["cookiename"][0][1]
|
||||
assert len(attrs) == 4
|
||||
assert attrs["domain"] == ["example.com"]
|
||||
assert attrs["expires"] == ["Wed Oct 21 16:29:41 2015"]
|
||||
assert attrs["path"] == ["/"]
|
||||
assert attrs["httponly"] == [None]
|
||||
|
||||
def test_get_cookies_no_value(self):
|
||||
resp = tutils.tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/")
|
||||
result = resp.get_cookies()
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0][0] == ""
|
||||
assert len(result["cookiename"][0][1]) == 2
|
||||
|
||||
def test_get_cookies_twocookies(self):
|
||||
resp = tutils.tresp()
|
||||
resp.headers = Headers([
|
||||
[b"Set-Cookie", b"cookiename=cookievalue"],
|
||||
[b"Set-Cookie", b"othercookie=othervalue"]
|
||||
])
|
||||
result = resp.get_cookies()
|
||||
assert len(result) == 2
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0] == ["cookievalue", ODict()]
|
||||
assert "othercookie" in result
|
||||
assert result["othercookie"][0] == ["othervalue", ODict()]
|
||||
|
||||
def test_set_cookies(self):
|
||||
resp = tutils.tresp()
|
||||
v = resp.get_cookies()
|
||||
v.add("foo", ["bar", ODictCaseless()])
|
||||
resp.set_cookies(v)
|
||||
|
||||
v = resp.get_cookies()
|
||||
assert len(v) == 1
|
||||
assert v["foo"] == [["bar", ODictCaseless()]]
|
@ -17,31 +17,31 @@ class TestRequestData(object):
|
||||
|
||||
assert isinstance(treq(headers=None).headers, Headers)
|
||||
|
||||
def test_eq_ne(self):
|
||||
request_data = treq().data
|
||||
same = treq().data
|
||||
assert request_data == same
|
||||
assert not request_data != same
|
||||
|
||||
other = treq(content=b"foo").data
|
||||
assert not request_data == other
|
||||
assert request_data != other
|
||||
|
||||
assert request_data != 0
|
||||
|
||||
|
||||
class TestRequestCore(object):
|
||||
"""
|
||||
Tests for builtins and the attributes that are directly proxied from the data structure
|
||||
"""
|
||||
def test_repr(self):
|
||||
request = treq()
|
||||
assert repr(request) == "Request(GET address:22/path)"
|
||||
request.host = None
|
||||
assert repr(request) == "Request(GET /path)"
|
||||
|
||||
test_first_line_format = _test_passthrough_attr(treq(), "first_line_format")
|
||||
test_method = _test_decoded_attr(treq(), "method")
|
||||
test_scheme = _test_decoded_attr(treq(), "scheme")
|
||||
test_port = _test_passthrough_attr(treq(), "port")
|
||||
test_path = _test_decoded_attr(treq(), "path")
|
||||
def test_first_line_format(self):
|
||||
_test_passthrough_attr(treq(), "first_line_format")
|
||||
|
||||
def test_method(self):
|
||||
_test_decoded_attr(treq(), "method")
|
||||
|
||||
def test_scheme(self):
|
||||
_test_decoded_attr(treq(), "scheme")
|
||||
|
||||
def test_port(self):
|
||||
_test_passthrough_attr(treq(), "port")
|
||||
|
||||
def test_path(self):
|
||||
_test_decoded_attr(treq(), "path")
|
||||
|
||||
def test_host(self):
|
||||
if six.PY2:
|
||||
@ -86,6 +86,9 @@ class TestRequestCore(object):
|
||||
|
||||
|
||||
class TestRequestUtils(object):
|
||||
"""
|
||||
Tests for additional convenience methods.
|
||||
"""
|
||||
def test_url(self):
|
||||
request = treq()
|
||||
assert request.url == "http://address:22/path"
|
||||
@ -199,6 +202,11 @@ class TestRequestUtils(object):
|
||||
|
||||
def test_constrain_encoding(self):
|
||||
request = treq()
|
||||
|
||||
h = request.headers.copy()
|
||||
request.constrain_encoding() # no-op if there is no accept_encoding header.
|
||||
assert request.headers == h
|
||||
|
||||
request.headers["Accept-Encoding"] = "identity, gzip, foo"
|
||||
request.constrain_encoding()
|
||||
assert "foo" not in request.headers["Accept-Encoding"]
|
||||
|
@ -1,3 +1,100 @@
|
||||
from __future__ import absolute_import, print_function, division
|
||||
|
||||
# TODO
|
||||
from netlib.http import Headers
|
||||
from netlib.odict import ODict, ODictCaseless
|
||||
from netlib.tutils import raises, tresp
|
||||
from .test_message import _test_passthrough_attr, _test_decoded_attr
|
||||
|
||||
|
||||
class TestResponseData(object):
|
||||
def test_init(self):
|
||||
with raises(AssertionError):
|
||||
tresp(headers="foobar")
|
||||
|
||||
assert isinstance(tresp(headers=None).headers, Headers)
|
||||
|
||||
|
||||
class TestResponseCore(object):
|
||||
"""
|
||||
Tests for builtins and the attributes that are directly proxied from the data structure
|
||||
"""
|
||||
def test_repr(self):
|
||||
response = tresp()
|
||||
assert repr(response) == "Response(200 OK, unknown content type, 7B)"
|
||||
response.content = None
|
||||
assert repr(response) == "Response(200 OK, no content)"
|
||||
|
||||
def test_status_code(self):
|
||||
_test_passthrough_attr(tresp(), "status_code")
|
||||
|
||||
def test_reason(self):
|
||||
_test_decoded_attr(tresp(), "reason")
|
||||
|
||||
|
||||
class TestResponseUtils(object):
|
||||
"""
|
||||
Tests for additional convenience methods.
|
||||
"""
|
||||
def test_get_cookies_none(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers()
|
||||
assert not resp.cookies
|
||||
|
||||
def test_get_cookies_empty(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers(set_cookie="")
|
||||
assert not resp.cookies
|
||||
|
||||
def test_get_cookies_simple(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=cookievalue")
|
||||
result = resp.cookies
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0] == ["cookievalue", ODict()]
|
||||
|
||||
def test_get_cookies_with_parameters(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=cookievalue;domain=example.com;expires=Wed Oct 21 16:29:41 2015;path=/; HttpOnly")
|
||||
result = resp.cookies
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0][0] == "cookievalue"
|
||||
attrs = result["cookiename"][0][1]
|
||||
assert len(attrs) == 4
|
||||
assert attrs["domain"] == ["example.com"]
|
||||
assert attrs["expires"] == ["Wed Oct 21 16:29:41 2015"]
|
||||
assert attrs["path"] == ["/"]
|
||||
assert attrs["httponly"] == [None]
|
||||
|
||||
def test_get_cookies_no_value(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers(set_cookie="cookiename=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/")
|
||||
result = resp.cookies
|
||||
assert len(result) == 1
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0][0] == ""
|
||||
assert len(result["cookiename"][0][1]) == 2
|
||||
|
||||
def test_get_cookies_twocookies(self):
|
||||
resp = tresp()
|
||||
resp.headers = Headers([
|
||||
[b"Set-Cookie", b"cookiename=cookievalue"],
|
||||
[b"Set-Cookie", b"othercookie=othervalue"]
|
||||
])
|
||||
result = resp.cookies
|
||||
assert len(result) == 2
|
||||
assert "cookiename" in result
|
||||
assert result["cookiename"][0] == ["cookievalue", ODict()]
|
||||
assert "othercookie" in result
|
||||
assert result["othercookie"][0] == ["othervalue", ODict()]
|
||||
|
||||
def test_set_cookies(self):
|
||||
resp = tresp()
|
||||
v = resp.cookies
|
||||
v.add("foo", ["bar", ODictCaseless()])
|
||||
resp.set_cookies(v)
|
||||
|
||||
v = resp.cookies
|
||||
assert len(v) == 1
|
||||
assert v["foo"] == [["bar", ODictCaseless()]]
|
||||
|
Loading…
Reference in New Issue
Block a user