Respect SpaceDevs request limits and cooldowns

This commit is contained in:
Edward Betts 2026-09-30 16:41:13 +01:00
parent 69992bebb7
commit 3f6ee4f2ec
3 changed files with 124 additions and 13 deletions

View file

@ -0,0 +1,62 @@
"""Regression tests for the shared SpaceDevs request budget."""
import json
from pathlib import Path
from unittest.mock import Mock
import pytest
from agenda import thespacedevs
def test_budget_survives_separate_calls(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
request = Mock(return_value=Mock(status_code=200))
monkeypatch.setattr("agenda.thespacedevs.requests.get", request)
monkeypatch.setattr("agenda.thespacedevs.time.time", lambda: 10000.0)
for _ in range(12):
thespacedevs.api_get(str(tmp_path), "https://example.com")
with pytest.raises(thespacedevs.RateLimitDeferred):
thespacedevs.api_get(str(tmp_path), "https://example.com")
assert request.call_count == 12
monkeypatch.setattr("agenda.thespacedevs.time.time", lambda: 13601.0)
thespacedevs.api_get(str(tmp_path), "https://example.com")
assert request.call_count == 13
@pytest.mark.parametrize("headers", [{}, {"Retry-After": "1832"}])
def test_throttle_persists_cooldown(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, headers: dict[str, str]
) -> None:
request = Mock(
return_value=Mock(
status_code=429,
headers=headers,
text='{"detail": "Request was throttled. Expected available in 1832 seconds."}',
)
)
monkeypatch.setattr("agenda.thespacedevs.requests.get", request)
monkeypatch.setattr("agenda.thespacedevs.time.time", lambda: 10000.0)
with pytest.raises(thespacedevs.RateLimitDeferred):
thespacedevs.api_get(str(tmp_path), "https://example.com")
state = json.loads((tmp_path / "api_budget.json").read_text())
assert state["retry_at"] == 11833.0
monkeypatch.setattr("agenda.thespacedevs.time.time", lambda: 11000.0)
with pytest.raises(thespacedevs.RateLimitDeferred):
thespacedevs.api_get(str(tmp_path), "https://example.com")
assert request.call_count == 1
def test_incomplete_pagination_keeps_cached_flights(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
cached = [{"slug": "still-in-orbit"}]
thespacedevs.write_active_crewed_flights_cache(str(tmp_path), cached)
response = Mock(status_code=200, ok=True)
response.json.return_value = {"results": [], "next": "https://example.com/page2"}
request = Mock(side_effect=[response, thespacedevs.RateLimitDeferred()])
monkeypatch.setattr(thespacedevs, "api_get", request)
assert thespacedevs.get_active_crewed_flights(str(tmp_path), refresh=True) == cached
loaded = thespacedevs.load_active_crewed_flights_cache(str(tmp_path))
assert loaded is not None and loaded[1] == cached