mirror of
https://github.com/kevin1024/vcrpy.git
synced 2025-12-08 16:53:23 +00:00
Fix handling of encoded content in HTTPX stub.
Also copied over and adjusted some of the tests from test_requests.py relating to gzipped handling to show that the HTTPX stub is behaving in a consistent way to how the requests stub is.
This commit is contained in:
committed by
Jair Henrique
parent
5cf23298ac
commit
c5487384ee
@@ -5,6 +5,7 @@ import vcr
|
|||||||
asyncio = pytest.importorskip("asyncio")
|
asyncio = pytest.importorskip("asyncio")
|
||||||
httpx = pytest.importorskip("httpx")
|
httpx = pytest.importorskip("httpx")
|
||||||
|
|
||||||
|
from ..assertions import assert_is_json_bytes
|
||||||
|
|
||||||
@pytest.fixture(params=["https", "http"])
|
@pytest.fixture(params=["https", "http"])
|
||||||
def scheme(request):
|
def scheme(request):
|
||||||
@@ -207,22 +208,6 @@ def test_redirect(httpbin, yml, do_request):
|
|||||||
assert cassette_response.request.headers.items() == response.request.headers.items()
|
assert cassette_response.request.headers.items() == response.request.headers.items()
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.online
|
|
||||||
def test_work_with_gzipped_data(httpbin, do_request, yml):
|
|
||||||
url = httpbin.url + "/gzip?foo=bar"
|
|
||||||
headers = {"accept-encoding": "deflate, gzip"}
|
|
||||||
|
|
||||||
with vcr.use_cassette(yml):
|
|
||||||
do_request(headers=headers)("GET", url)
|
|
||||||
|
|
||||||
with vcr.use_cassette(yml) as cassette:
|
|
||||||
cassette_response = do_request(headers=headers)("GET", url)
|
|
||||||
|
|
||||||
# Show we can read the content of the cassette.
|
|
||||||
assert cassette_response.json()['gzipped'] == True
|
|
||||||
assert cassette.play_count == 1
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.online
|
@pytest.mark.online
|
||||||
@pytest.mark.parametrize("url", ["https://github.com/kevin1024/vcrpy/issues/" + str(i) for i in range(3, 6)])
|
@pytest.mark.parametrize("url", ["https://github.com/kevin1024/vcrpy/issues/" + str(i) for i in range(3, 6)])
|
||||||
def test_simple_fetching(do_request, yml, url):
|
def test_simple_fetching(do_request, yml, url):
|
||||||
@@ -296,7 +281,7 @@ def test_stream(tmpdir, httpbin, do_request):
|
|||||||
("httpx_old_format", "OK"),
|
("httpx_old_format", "OK"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_load_gzipped(do_request, cassette_name, reason):
|
def test_load_cassette_format(do_request, cassette_name, reason):
|
||||||
mydir = os.path.dirname(os.path.realpath(__file__))
|
mydir = os.path.dirname(os.path.realpath(__file__))
|
||||||
yml = f"{mydir}/cassettes/gzip_{cassette_name}.yaml"
|
yml = f"{mydir}/cassettes/gzip_{cassette_name}.yaml"
|
||||||
url = "https://httpbin.org/gzip"
|
url = "https://httpbin.org/gzip"
|
||||||
@@ -314,3 +299,48 @@ def test_load_gzipped(do_request, cassette_name, reason):
|
|||||||
assert cassette_response.status_code == 200
|
assert cassette_response.status_code == 200
|
||||||
assert cassette_response.reason_phrase == reason
|
assert cassette_response.reason_phrase == reason
|
||||||
|
|
||||||
|
|
||||||
|
def test_gzip__decode_compressed_response_false(tmpdir, httpbin, do_request):
|
||||||
|
"""
|
||||||
|
Ensure that httpx is able to automatically decompress the response body.
|
||||||
|
"""
|
||||||
|
for _ in range(2): # one for recording, one for re-playing
|
||||||
|
with vcr.use_cassette(str(tmpdir.join("gzip.yaml"))) as cassette:
|
||||||
|
response = do_request()("GET", httpbin + "/gzip")
|
||||||
|
assert response.headers["content-encoding"] == "gzip" # i.e. not removed
|
||||||
|
# The content stored in the cassette should be gzipped.
|
||||||
|
assert cassette.responses[0]["body"]["string"][:2] == b"\x1f\x8b"
|
||||||
|
assert_is_json_bytes(response.content) # i.e. uncompressed bytes
|
||||||
|
|
||||||
|
|
||||||
|
def test_gzip__decode_compressed_response_true(do_request, tmpdir, httpbin):
|
||||||
|
url = httpbin + "/gzip"
|
||||||
|
|
||||||
|
expected_response = do_request()("GET", url)
|
||||||
|
expected_content = expected_response.content
|
||||||
|
assert expected_response.headers["content-encoding"] == "gzip" # self-test
|
||||||
|
|
||||||
|
with vcr.use_cassette(
|
||||||
|
str(tmpdir.join("decode_compressed.yaml")),
|
||||||
|
decode_compressed_response=True,
|
||||||
|
) as cassette:
|
||||||
|
r = do_request()("GET", url)
|
||||||
|
assert r.headers["content-encoding"] == "gzip" # i.e. not removed
|
||||||
|
content_length = r.headers["content-length"]
|
||||||
|
assert r.content == expected_content
|
||||||
|
|
||||||
|
# Has the cassette body been decompressed?
|
||||||
|
cassette_response_body = cassette.responses[0]["body"]["string"]
|
||||||
|
assert isinstance(cassette_response_body, str)
|
||||||
|
|
||||||
|
# Content should be JSON.
|
||||||
|
assert cassette_response_body[0:1] == "{"
|
||||||
|
|
||||||
|
with vcr.use_cassette(str(tmpdir.join("decode_compressed.yaml")), decode_compressed_response=True):
|
||||||
|
r = httpx.get(url)
|
||||||
|
assert "content-encoding" not in r.headers # i.e. removed
|
||||||
|
assert r.content == expected_content
|
||||||
|
|
||||||
|
# As the content is uncompressed, it should have a bigger
|
||||||
|
# length than the compressed version.
|
||||||
|
assert r.headers["content-length"] > content_length
|
||||||
|
|||||||
@@ -38,17 +38,27 @@ def _transform_headers(httpx_response):
|
|||||||
|
|
||||||
async def _to_serialized_response(resp, aread):
|
async def _to_serialized_response(resp, aread):
|
||||||
|
|
||||||
if aread:
|
# The content shouldn't already have been read in by HTTPX.
|
||||||
await resp.aread()
|
assert not hasattr(resp, "_decoder")
|
||||||
else:
|
|
||||||
resp.read()
|
|
||||||
|
|
||||||
return {
|
# Retrieve the content, but without decoding it.
|
||||||
|
with patch.dict(resp.headers, {"Content-Encoding": ""}):
|
||||||
|
if aread:
|
||||||
|
await resp.aread()
|
||||||
|
else:
|
||||||
|
resp.read()
|
||||||
|
|
||||||
|
result = {
|
||||||
"status": dict(code=resp.status_code, message=resp.reason_phrase),
|
"status": dict(code=resp.status_code, message=resp.reason_phrase),
|
||||||
"headers": _transform_headers(resp),
|
"headers": _transform_headers(resp),
|
||||||
"body": {"string": resp.content},
|
"body": {"string": resp.content},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# As the content wasn't decoded, we restore the response to a state which
|
||||||
|
# will be capable of decoding the content for the consumer.
|
||||||
|
del resp._decoder
|
||||||
|
resp._content = resp._get_content_decoder().decode(resp.content)
|
||||||
|
return result
|
||||||
|
|
||||||
def _from_serialized_headers(headers):
|
def _from_serialized_headers(headers):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user