Skip to content

Commit

Permalink
Add response cache (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
mib1185 authored Feb 16, 2024
1 parent 92d2c2e commit ddb724d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 6 deletions.
25 changes: 22 additions & 3 deletions aiopegelonline/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from .const import BASE_URL, CONNECT_ERRORS, LOGGER
from .exceptions import PegelonlineDataError
from .models import Station, StationMeasurements
from .models import CacheEntry, Station, StationMeasurements


class PegelOnline:
Expand All @@ -17,15 +17,34 @@ class PegelOnline:
def __init__(self, aiohttp_session: ClientSession) -> None:
"""Pegelonline api init."""
self.session: ClientSession = aiohttp_session
self.cache: dict[str, CacheEntry] = {}

async def _async_do_request(self, url: str, params: dict):
"""Perform an async request."""
LOGGER.debug("REQUEST url: %s params: %s", url, params)
cache_key = f"{url}_{params}"
if cache_key not in self.cache:
self.cache[cache_key] = CacheEntry(None, None)

cache_entry = self.cache[cache_key]

headers = {}
if (etag := cache_entry.etag) is not None:
headers = {"If-None-Match": etag}

LOGGER.debug("REQUEST url: %s params: %s headers: %s", url, params, headers)
try:
async with self.session.get(url, params=params) as resp:
async with self.session.get(url, params=params, headers=headers) as resp:
result = await resp.text()
LOGGER.debug("RESPONSE status: %s text: %s", resp.status, result)

if resp.status == 304: # 304 = not modified
return cache_entry.result

if cache_entry.etag is None:
cache_entry.etag = resp.headers.get("Etag")

result = json.loads(result)
cache_entry.result = result
if resp.status != 200:
raise PegelonlineDataError(
result.get("status"), result.get("message")
Expand Down
10 changes: 10 additions & 0 deletions aiopegelonline/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

from dataclasses import dataclass


class Station:
"""Representation of a station."""
Expand Down Expand Up @@ -93,3 +95,11 @@ def as_dict(self) -> dict[str, CurrentMeasurement | None]:
"water_level": self.water_level,
"water_temperature": self.water_temperature,
}


@dataclass
class CacheEntry:
"""Representation of response cache entry."""

etag: str | None
result: dict | None
24 changes: 21 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import aiohttp
import pytest
from aioresponses import aioresponses
from aioresponses import CallbackResult, aioresponses

from aiopegelonline import PegelOnline
from aiopegelonline.const import BASE_URL

from .const import MOCK_DATA
from .const import MOCK_DATA, MOCK_STATION_DATA_DRESDEN


@pytest.fixture
Expand All @@ -29,7 +29,7 @@ async def mock_pegelonline():

@pytest.fixture
def mock_pegelonline_with_data(mock_aioresponse, mock_pegelonline):
"""Comfort fixture to initialize deCONZ session."""
"""Comfort fixture to initialize pegelonline session."""

async def data_to_pegelonline() -> PegelOnline:
"""Initialize PegelOnline session."""
Expand All @@ -43,3 +43,21 @@ async def data_to_pegelonline() -> PegelOnline:
return mock_pegelonline

return data_to_pegelonline

@pytest.fixture
def mock_pegelonline_with_cached_data(mock_aioresponse, mock_pegelonline):
"""Comfort fixture to initialize pegelonline session with cached data."""

def cache_response(_, **kwargs) -> CallbackResult:
etag = "etag_station_dresden"
if (headers := kwargs.get("headers")) and headers.get("If-None-Match") == etag:
return CallbackResult(status=304, body="", headers={"Etag": etag})
return CallbackResult(status=200, body=json.dumps(MOCK_STATION_DATA_DRESDEN), headers={"Etag": etag})

async def data_to_pegelonline() -> PegelOnline:
"""Initialize PegelOnline session."""
query = f"{BASE_URL}/stations/70272185-xxxx-xxxx-xxxx-43bea330dcae.json?prettyprint=false"
mock_aioresponse.get(query, callback=cache_response, repeat=True)
return mock_pegelonline

return data_to_pegelonline
28 changes: 28 additions & 0 deletions tests/test_aiopegelonline.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,31 @@ async def test_get_station_measurements(mock_pegelonline_with_data):
"water_level": None,
"water_temperature": None,
}


async def test_get_station_details_cached(mock_pegelonline_with_cached_data):
"""Test response cache."""
api = await mock_pegelonline_with_cached_data()
station = await api.async_get_station_details(
"70272185-xxxx-xxxx-xxxx-43bea330dcae"
)
assert isinstance(station, Station)
assert station.uuid == "70272185-xxxx-xxxx-xxxx-43bea330dcae"
assert station.name == "DRESDEN"
assert station.agency == "STANDORT DRESDEN"
assert station.river_kilometer == 55.63
assert station.longitude == 13.738831783620384
assert station.latitude == 51.054459765598125
assert station.water_name == "ELBE"

station = await api.async_get_station_details(
"70272185-xxxx-xxxx-xxxx-43bea330dcae"
)
assert isinstance(station, Station)
assert station.uuid == "70272185-xxxx-xxxx-xxxx-43bea330dcae"
assert station.name == "DRESDEN"
assert station.agency == "STANDORT DRESDEN"
assert station.river_kilometer == 55.63
assert station.longitude == 13.738831783620384
assert station.latitude == 51.054459765598125
assert station.water_name == "ELBE"

0 comments on commit ddb724d

Please sign in to comment.