Skip to content

Commit

Permalink
Improve transports and connection pools tests, make coverage 100%
Browse files Browse the repository at this point in the history
  • Loading branch information
karpetrosyan committed Jul 28, 2023
1 parent c0d9eeb commit 30d8bd9
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 55 deletions.
11 changes: 6 additions & 5 deletions hishel/_async/_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ async def handle_async_request(self, request: Request) -> Response:
# Re-validating the response.

response = await self._pool.handle_async_request(res)
await response.aread()

# Merge headers with the stale response.
self._controller.handle_validation_response(
full_response = self._controller.handle_validation_response(
old_response=stored_resposne, new_response=response
)
await self._storage.store(key, response)
response.extensions["from_cache"] = response.status == 304 # type: ignore[index]
return response

await full_response.aread()
await self._storage.store(key, full_response)
full_response.extensions["from_cache"] = response.status == 304 # type: ignore[index]
return full_response

response = await self._pool.handle_async_request(request)

Expand Down
20 changes: 10 additions & 10 deletions hishel/_async/_transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .._serializers import JSONSerializer
from ._storages import AsyncBaseStorage, AsyncFileStorage

if tp.TYPE_CHECKING:
if tp.TYPE_CHECKING: # pragma: no cover
from typing_extensions import Self

__all__ = ("AsyncCacheTransport",)
Expand Down Expand Up @@ -89,22 +89,22 @@ async def handle_async_request(self, request: Request) -> Response:
)

# Merge headers with the stale response.
self._controller.handle_validation_response(
full_response = self._controller.handle_validation_response(
old_response=stored_resposne, new_response=httpcore_response
)

await httpcore_response.aread()
await self._storage.store(key, httpcore_response)
await full_response.aread()
await self._storage.store(key, full_response)

assert isinstance(httpcore_response.stream, tp.AsyncIterable)
httpcore_response.extensions["from_cache"] = ( # type: ignore[index]
assert isinstance(full_response.stream, tp.AsyncIterable)
full_response.extensions["from_cache"] = ( # type: ignore[index]
httpcore_response.status == 304
)
return Response(
status_code=httpcore_response.status,
headers=httpcore_response.headers,
stream=AsyncResponseStream(httpcore_response.stream),
extensions=httpcore_response.extensions,
status_code=full_response.status,
headers=full_response.headers,
stream=AsyncResponseStream(full_response.stream),
extensions=full_response.extensions,
)

response = await self._transport.handle_async_request(request)
Expand Down
4 changes: 2 additions & 2 deletions hishel/_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def _validate_vary(self, request: Request, response: Response) -> bool:
vary = Vary.from_value(vary_values=vary_headers)
for vary_header in vary._values:
if vary_header == "*":
return False
return False # pragma: no cover

if extract_header_values(
request.headers, vary_header
Expand Down Expand Up @@ -247,7 +247,7 @@ def construct_response_from_cache(
# response (if any) match those presented (see Section 4.1)
if not self._validate_vary(request=request, response=response):
# If the vary headers does not match, then do not use the response
return None
return None # pragma: no cover

# the stored response does not contain the
# no-cache directive (Section 5.2.2.4), unless
Expand Down
11 changes: 6 additions & 5 deletions hishel/_sync/_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ def handle_request(self, request: Request) -> Response:
# Re-validating the response.

response = self._pool.handle_request(res)
response.read()

# Merge headers with the stale response.
self._controller.handle_validation_response(
full_response = self._controller.handle_validation_response(
old_response=stored_resposne, new_response=response
)
self._storage.store(key, response)
response.extensions["from_cache"] = response.status == 304 # type: ignore[index]
return response

full_response.read()
self._storage.store(key, full_response)
full_response.extensions["from_cache"] = response.status == 304 # type: ignore[index]
return full_response

response = self._pool.handle_request(request)

Expand Down
20 changes: 10 additions & 10 deletions hishel/_sync/_transports.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .._serializers import JSONSerializer
from ._storages import BaseStorage, FileStorage

if tp.TYPE_CHECKING:
if tp.TYPE_CHECKING: # pragma: no cover
from typing_extensions import Self

__all__ = ("CacheTransport",)
Expand Down Expand Up @@ -89,22 +89,22 @@ def handle_request(self, request: Request) -> Response:
)

# Merge headers with the stale response.
self._controller.handle_validation_response(
full_response = self._controller.handle_validation_response(
old_response=stored_resposne, new_response=httpcore_response
)

httpcore_response.read()
self._storage.store(key, httpcore_response)
full_response.read()
self._storage.store(key, full_response)

assert isinstance(httpcore_response.stream, tp.Iterable)
httpcore_response.extensions["from_cache"] = ( # type: ignore[index]
assert isinstance(full_response.stream, tp.Iterable)
full_response.extensions["from_cache"] = ( # type: ignore[index]
httpcore_response.status == 304
)
return Response(
status_code=httpcore_response.status,
headers=httpcore_response.headers,
stream=ResponseStream(httpcore_response.stream),
extensions=httpcore_response.extensions,
status_code=full_response.status,
headers=full_response.headers,
stream=ResponseStream(full_response.stream),
extensions=full_response.extensions,
)

response = self._transport.handle_request(request)
Expand Down
1 change: 0 additions & 1 deletion hishel/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ def extract_header_values(
if isinstance(header_key, str):
header_key = header_key.encode(HEADERS_ENCODING)
extracted_headers = []

for key, value in headers:
if key.lower() == header_key.lower():
extracted_headers.append(value)
Expand Down
25 changes: 15 additions & 10 deletions tests/_async/test_client.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import httpx
import pytest

import hishel


@pytest.mark.anyio
async def test_client():
async with hishel.AsyncCacheClient() as client:
await client.request(
"GET",
"https://httpbun.org/redirect/?url=https%3A//httpbun.org&status_code=301",
async def test_client_301():
async with hishel.MockAsyncTransport() as transport:
transport.add_responses(
[httpx.Response(301, headers=[(b"Location", b"https://example.com")])]
)
response = await client.request(
"GET",
"https://httpbun.org/redirect/?url=https%3A//httpbun.org&status_code=301",
)
assert "network_stream" not in response.extensions # from cache
async with hishel.AsyncCacheClient(transport=transport) as client:
await client.request(
"GET",
"https://www.example.com",
)
response = await client.request(
"GET",
"https://www.example.com",
)
assert response.extensions["from_cache"]
39 changes: 39 additions & 0 deletions tests/_async/test_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest

import hishel
from hishel._utils import extract_header_values, header_presents


@pytest.mark.anyio
Expand All @@ -14,3 +15,41 @@ async def test_pool_301(use_temp_dir):
await cache_pool.request("GET", "https://www.example.com")
response = await cache_pool.request("GET", "https://www.example.com")
assert response.extensions["from_cache"]


@pytest.mark.anyio
async def test_pool_response_validation(use_temp_dir):
async with hishel.MockAsyncConnectionPool() as pool:
pool.add_responses(
[
httpcore.Response(
200,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
],
content=b"test",
),
httpcore.Response(
304,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
(b"Content-Type", b"application/json"),
],
),
]
)
async with hishel.AsyncCacheConnectionPool(pool=pool) as cache_pool:
request = httpcore.Request("GET", "https://www.example.com")

await cache_pool.handle_async_request(request)
response = await cache_pool.handle_async_request(request)
assert response.status == 200
assert response.extensions["from_cache"]
assert header_presents(response.headers, b"Content-Type")
assert (
extract_header_values(response.headers, b"Content-Type", single=True)[0]
== b"application/json"
)
assert await response.aread() == b"test"
37 changes: 36 additions & 1 deletion tests/_async/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


@pytest.mark.anyio
async def test_transport_301():
async def test_transport_301(use_temp_dir):
async with hishel.MockAsyncTransport() as transport:
transport.add_responses(
[httpx.Response(301, headers=[(b"Location", b"https://example.com")])]
Expand All @@ -16,3 +16,38 @@ async def test_transport_301():
await cache_transport.handle_async_request(request)
response = await cache_transport.handle_async_request(request)
assert response.extensions["from_cache"]


@pytest.mark.anyio
async def test_transport_response_validation(use_temp_dir):
async with hishel.MockAsyncTransport() as transport:
transport.add_responses(
[
httpx.Response(
200,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
],
content="test",
),
httpx.Response(
304,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
(b"Content-Type", b"application/json"),
],
),
]
)
async with hishel.AsyncCacheTransport(transport=transport) as cache_transport:
request = httpx.Request("GET", "https://www.example.com")

await cache_transport.handle_async_request(request)
response = await cache_transport.handle_async_request(request)
assert response.status_code == 200
assert response.extensions["from_cache"]
assert "Content-Type" in response.headers
assert response.headers["Content-Type"] == "application/json"
assert await response.aread() == b"test"
25 changes: 15 additions & 10 deletions tests/_sync/test_client.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import httpx
import pytest

import hishel



def test_client():
with hishel.CacheClient() as client:
client.request(
"GET",
"https://httpbun.org/redirect/?url=https%3A//httpbun.org&status_code=301",
def test_client_301():
with hishel.MockTransport() as transport:
transport.add_responses(
[httpx.Response(301, headers=[(b"Location", b"https://example.com")])]
)
response = client.request(
"GET",
"https://httpbun.org/redirect/?url=https%3A//httpbun.org&status_code=301",
)
assert "network_stream" not in response.extensions # from cache
with hishel.CacheClient(transport=transport) as client:
client.request(
"GET",
"https://www.example.com",
)
response = client.request(
"GET",
"https://www.example.com",
)
assert response.extensions["from_cache"]
39 changes: 39 additions & 0 deletions tests/_sync/test_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import pytest

import hishel
from hishel._utils import extract_header_values, header_presents



Expand All @@ -14,3 +15,41 @@ def test_pool_301(use_temp_dir):
cache_pool.request("GET", "https://www.example.com")
response = cache_pool.request("GET", "https://www.example.com")
assert response.extensions["from_cache"]



def test_pool_response_validation(use_temp_dir):
with hishel.MockConnectionPool() as pool:
pool.add_responses(
[
httpcore.Response(
200,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
],
content=b"test",
),
httpcore.Response(
304,
headers=[
(b"Cache-Control", b"max-age=3600"),
(b"Date", b"Mon, 25 Aug 2015 12:00:00 GMT"),
(b"Content-Type", b"application/json"),
],
),
]
)
with hishel.CacheConnectionPool(pool=pool) as cache_pool:
request = httpcore.Request("GET", "https://www.example.com")

cache_pool.handle_request(request)
response = cache_pool.handle_request(request)
assert response.status == 200
assert response.extensions["from_cache"]
assert header_presents(response.headers, b"Content-Type")
assert (
extract_header_values(response.headers, b"Content-Type", single=True)[0]
== b"application/json"
)
assert response.read() == b"test"
Loading

0 comments on commit 30d8bd9

Please sign in to comment.