1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
import gzip
from datetime import datetime
from zoneinfo import ZoneInfo
import anysqlite
import httpx
import pytest
from httpx import ByteStream, MockTransport
from inline_snapshot import snapshot
from time_machine import travel
from hishel import AsyncSqliteStorage
from hishel._policies import FilterPolicy
from hishel.httpx import AsyncCacheClient, AsyncCacheTransport
@pytest.mark.anyio
@travel(datetime(2024, 1, 1, 0, 0, 0, tzinfo=ZoneInfo("UTC")), tick=False)
async def test_simple_caching(caplog: pytest.LogCaptureFixture) -> None:
client = AsyncCacheClient(
storage=AsyncSqliteStorage(connection=await anysqlite.connect(":memory:")),
)
with caplog.at_level("DEBUG", logger="hishel"):
await client.get("https://hishel.com")
response = await client.get("https://hishel.com")
assert caplog.messages == snapshot(
[
"Handling state: IdleClient",
"Handling state: CacheMiss",
"Storing response in cache",
"Handling state: StoreAndUse",
"Handling state: IdleClient",
"Handling state: FromCache",
]
)
assert response.extensions == snapshot(
{
"hishel_from_cache": True,
"hishel_created_at": 1704067200.0,
"hishel_revalidated": False,
"hishel_stored": False,
}
)
@pytest.mark.anyio
@travel(datetime(2024, 1, 1, 0, 0, 0, tzinfo=ZoneInfo("UTC")), tick=False)
async def test_simple_caching_ignoring_spec(caplog: pytest.LogCaptureFixture) -> None:
client = AsyncCacheClient(
storage=AsyncSqliteStorage(connection=await anysqlite.connect(":memory:")),
policy=FilterPolicy(),
)
with caplog.at_level("DEBUG", logger="hishel"):
await client.get("https://hishel.com", extensions={"hishel_spec_ignore": True})
response = await client.get("https://hishel.com", extensions={"hishel_spec_ignore": True})
assert caplog.messages == snapshot(
[
"Trying to get cached response ignoring specification",
"Found 0 cached entries for the request",
"Storing response in cache ignoring specification",
"Trying to get cached response ignoring specification",
"Found 1 cached entries for the request",
"Found matching cached response for the request",
]
)
assert response.extensions == snapshot(
{
"hishel_from_cache": True,
"hishel_created_at": 1704067200.0,
"hishel_revalidated": False,
"hishel_stored": False,
}
)
@pytest.mark.anyio
async def test_encoded_content_caching() -> None:
data = gzip.compress(b"a" * 1000)
compressed_data = ByteStream(data)
mocked_responses = [
httpx.Response(
200,
stream=compressed_data,
headers={
"Content-Encoding": "gzip",
"Content-Type": "text/plain",
"Content-Length": str(len(data)),
},
)
]
async def handler(request: httpx.Request) -> httpx.Response:
if not mocked_responses:
raise RuntimeError("No more mocked responses available")
return mocked_responses.pop(0)
storage = AsyncSqliteStorage(connection=await anysqlite.connect(":memory:"))
client = AsyncCacheClient(
transport=AsyncCacheTransport(
next_transport=MockTransport(handler=handler), storage=storage, policy=FilterPolicy()
),
)
# First request - should fetch from the mocked transport and store in cache
async with client.stream("get", "https://localhost", extensions={"hishel_spec_ignore": True}) as response:
response_data = b"".join([chunk async for chunk in response.aiter_raw()])
assert data == response_data
assert response.headers.get("Content-Length") == str(len(data)) == str(len(response_data))
assert response.headers.get("Content-Encoding") == "gzip"
# Second request - should fetch from cache
async with client.stream("get", "https://localhost", extensions={"hishel_spec_ignore": True}) as response:
response_data = b"".join([chunk async for chunk in response.aiter_raw()])
assert data == response_data
assert response.headers.get("Content-Length") == str(len(data)) == str(len(response_data))
assert response.headers.get("Content-Encoding") == "gzip"
|