"""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