83 lines
2.8 KiB
Python
83 lines
2.8 KiB
Python
"""Offline tests for shared flight pacing, cooldowns and route/date caching."""
|
|
|
|
import typing
|
|
from datetime import date
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
import agenda.conference_flights as flights
|
|
import agenda.flight_search_cache as cache
|
|
from agenda.types import StrDict
|
|
|
|
|
|
@pytest.fixture
|
|
def clock(monkeypatch: typing.Any) -> tuple[list[float], list[float]]:
|
|
"""Advance simulated time instead of sleeping or contacting Google."""
|
|
now = [1000.0]
|
|
sleeps: list[float] = []
|
|
|
|
def current_time() -> float:
|
|
return now[0]
|
|
|
|
def sleep(seconds: float) -> None:
|
|
sleeps.append(seconds)
|
|
now[0] += seconds
|
|
|
|
monkeypatch.setattr(cache, "time", SimpleNamespace(time=current_time, sleep=sleep))
|
|
return now, sleeps
|
|
|
|
|
|
def test_shared_request_spacing(
|
|
tmp_path: Path, clock: tuple[list[float], list[float]]
|
|
) -> None:
|
|
"""Separate callers share the same three-second spacing state."""
|
|
cache.wait_for_request(tmp_path)
|
|
cache.wait_for_request(tmp_path)
|
|
cache.wait_for_request(tmp_path)
|
|
assert clock[1] == [3.0, 3.0]
|
|
assert cache.read_state(tmp_path / "rate-limit.json")["last_request_at"] == 1006.0
|
|
|
|
|
|
@pytest.mark.parametrize("rows", [[], [{"price": 50}]])
|
|
def test_day_cache_reuses_results_during_cooldown(
|
|
tmp_path: Path, clock: tuple[list[float], list[float]], rows: list[StrDict]
|
|
) -> None:
|
|
"""Successful and empty route/date results survive a global request cooldown."""
|
|
calls: list[bool] = []
|
|
|
|
def fetch() -> list[StrDict]:
|
|
calls.append(True)
|
|
return rows
|
|
|
|
assert cache.cached_day(tmp_path, "BRS", "CPH", "2099-01-04", True, fetch) == rows
|
|
cache.block_requests(tmp_path)
|
|
assert cache.cached_day(tmp_path, "BRS", "CPH", "2099-01-04", True, fetch) == rows
|
|
assert len(calls) == 1
|
|
clock[0][0] += cache.DAY_CACHE_SECONDS + 1
|
|
cache.cached_day(tmp_path, "BRS", "CPH", "2099-01-04", True, fetch)
|
|
assert len(calls) == 2
|
|
|
|
|
|
def test_overlapping_conferences_reuse_day_cache(
|
|
tmp_path: Path, monkeypatch: typing.Any
|
|
) -> None:
|
|
"""Two conferences sharing a departure date fetch that outbound only once."""
|
|
calls: list[tuple[str, str, date]] = []
|
|
|
|
def fetch(
|
|
origin: str, destination: str, day: date, direct: bool, directory: Path
|
|
) -> list[StrDict]:
|
|
calls.append((origin, destination, day))
|
|
return [{"arrival": day.isoformat() + "T18:00:00", "price": 50}]
|
|
|
|
monkeypatch.setattr(flights, "fetch_day", fetch)
|
|
start = date(2099, 1, 5)
|
|
for end in (date(2099, 1, 6), date(2099, 1, 7)):
|
|
path = flights.cache_path(str(tmp_path), start, end, "CPH", False)
|
|
result = flights.lookup(path, start, end, "CPH", False)
|
|
assert result["searches"][0]["outbound"]
|
|
assert len(calls) == 3
|
|
assert sum(origin == "LON" for origin, _, _ in calls) == 1
|
|
assert cache.search_directory.get() is None
|