"""Tests for poll() — the Schiphol API fetch-and-publish sweep.""" import pytest import requests from main import poll # --------------------------------------------------------------------------- # Test doubles # --------------------------------------------------------------------------- class _NoOpSpan: def __enter__(self): return self def __exit__(self, *args): pass class StubTracer: def start_as_current_span(self, name, attributes=None): return _NoOpSpan() class StubResponse: """Minimal requests.Response lookalike.""" def __init__(self, flights, *, next_url=None, raise_on_status=False): self._flights = flights self._raise = raise_on_status self.headers = {} if next_url: self.headers["link"] = f'<{next_url}>; rel="next"' def raise_for_status(self): if self._raise: raise requests.HTTPError("500 Server Error") def json(self): return {"flights": self._flights} class StubSession: """Returns pre-configured StubResponse objects keyed by URL.""" def __init__(self, responses_by_url: dict): self._responses = responses_by_url def get(self, url): return self._responses[url] class MockEngine: """Captures every send() call so tests can assert on Kafka output.""" def __init__(self): self.sent: list[dict] = [] async def send(self, topic, *, value, key): self.sent.append({"topic": topic, "value": value, "key": key}) class FakeApiSettings: base_url = "https://api.example.com/flights" class FakeKafkaSettings: topic = "flights-test" # --------------------------------------------------------------------------- # Tests # --------------------------------------------------------------------------- async def test_single_page_publishes_all_flights_and_returns_count(): """poll() publishes every Flight on a single-page response and returns the count.""" flights = [{"id": "1", "flightName": "KL100"}, {"id": "2", "flightName": "KL200"}] session = StubSession({FakeApiSettings.base_url: StubResponse(flights)}) engine = MockEngine() count = await poll(session, engine, FakeApiSettings(), FakeKafkaSettings(), StubTracer()) assert count == 2 assert len(engine.sent) == 2 published_keys = {msg["key"] for msg in engine.sent} assert published_keys == {"1", "2"} async def test_pagination_publishes_flights_across_all_pages(): """poll() follows link: rel="next" headers and publishes Flights from every page.""" page1_url = FakeApiSettings.base_url page2_url = "https://api.example.com/flights?page=2" page1_flights = [{"id": "A"}, {"id": "B"}] page2_flights = [{"id": "C"}, {"id": "D"}, {"id": "E"}] session = StubSession( { page1_url: StubResponse(page1_flights, next_url=page2_url), page2_url: StubResponse(page2_flights), } ) engine = MockEngine() count = await poll(session, engine, FakeApiSettings(), FakeKafkaSettings(), StubTracer()) assert count == 5 assert len(engine.sent) == 5 async def test_http_error_propagates_out_of_poll(): """poll() lets HTTP errors from raise_for_status() propagate to the caller.""" session = StubSession( {FakeApiSettings.base_url: StubResponse([], raise_on_status=True)} ) engine = MockEngine() with pytest.raises(requests.HTTPError): await poll(session, engine, FakeApiSettings(), FakeKafkaSettings(), StubTracer())