Tighten provider normalization contract and fallback semantics
This commit is contained in:
@ -5,7 +5,7 @@ import pytest
|
||||
from apps.competitions.models import Competition, Season
|
||||
from apps.ingestion.models import IngestionError, IngestionRun
|
||||
from apps.ingestion.services.sync import run_sync_job
|
||||
from apps.players.models import Player
|
||||
from apps.players.models import Nationality, Player
|
||||
from apps.providers.exceptions import ProviderRateLimitError
|
||||
from apps.providers.models import ExternalMapping
|
||||
from apps.stats.models import PlayerSeason, PlayerSeasonStats
|
||||
@ -114,7 +114,7 @@ def test_balldontlie_sync_idempotency_with_stable_payload(monkeypatch):
|
||||
"competition_type": "league",
|
||||
"gender": "men",
|
||||
"level": 1,
|
||||
"country": {"name": "United States", "iso2_code": "US", "iso3_code": "USA"},
|
||||
"country": None,
|
||||
"is_active": True,
|
||||
}
|
||||
],
|
||||
@ -124,7 +124,7 @@ def test_balldontlie_sync_idempotency_with_stable_payload(monkeypatch):
|
||||
"name": "Los Angeles Lakers",
|
||||
"short_name": "LAL",
|
||||
"slug": "los-angeles-lakers",
|
||||
"country": {"name": "United States", "iso2_code": "US", "iso3_code": "USA"},
|
||||
"country": None,
|
||||
"is_national_team": False,
|
||||
}
|
||||
],
|
||||
@ -144,7 +144,7 @@ def test_balldontlie_sync_idempotency_with_stable_payload(monkeypatch):
|
||||
"last_name": "James",
|
||||
"full_name": "LeBron James",
|
||||
"birth_date": None,
|
||||
"nationality": {"name": "United States", "iso2_code": "US", "iso3_code": "USA"},
|
||||
"nationality": None,
|
||||
"nominal_position": {"code": "SF", "name": "Small Forward"},
|
||||
"inferred_role": {"code": "wing", "name": "Wing"},
|
||||
"height_cm": None,
|
||||
@ -202,6 +202,10 @@ def test_balldontlie_sync_idempotency_with_stable_payload(monkeypatch):
|
||||
monkeypatch.setattr("apps.ingestion.services.sync.get_provider", lambda namespace: StableProvider())
|
||||
|
||||
run_sync_job(provider_namespace="balldontlie", job_type=IngestionRun.JobType.FULL_SYNC)
|
||||
lebron = Player.objects.get(full_name="LeBron James")
|
||||
assert lebron.nationality is None
|
||||
assert not Nationality.objects.filter(iso2_code="ZZ").exists()
|
||||
|
||||
counts_first = {
|
||||
"competition": Competition.objects.count(),
|
||||
"team": Team.objects.count(),
|
||||
|
||||
@ -41,3 +41,37 @@ def test_provider_registry_resolution(settings):
|
||||
|
||||
with pytest.raises(ProviderNotFoundError):
|
||||
get_provider("does-not-exist")
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_demo_provider_sync_payload_uses_normalized_shape():
|
||||
adapter = MvpDemoProviderAdapter()
|
||||
payload = adapter.sync_all()
|
||||
|
||||
assert set(payload.keys()) == {
|
||||
"players",
|
||||
"competitions",
|
||||
"teams",
|
||||
"seasons",
|
||||
"player_stats",
|
||||
"player_careers",
|
||||
"cursor",
|
||||
}
|
||||
assert payload["cursor"] is None
|
||||
|
||||
player = payload["players"][0]
|
||||
assert set(player.keys()) == {
|
||||
"external_id",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"full_name",
|
||||
"birth_date",
|
||||
"nationality",
|
||||
"nominal_position",
|
||||
"inferred_role",
|
||||
"height_cm",
|
||||
"weight_kg",
|
||||
"dominant_hand",
|
||||
"is_active",
|
||||
"aliases",
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ from apps.providers.adapters.mvp_provider import MvpDemoProviderAdapter
|
||||
from apps.providers.clients.balldontlie import BalldontlieClient
|
||||
from apps.providers.exceptions import ProviderRateLimitError, ProviderTransientError
|
||||
from apps.providers.registry import get_default_provider_namespace, get_provider
|
||||
from apps.providers.services.balldontlie_mappings import map_seasons
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
@ -133,6 +134,36 @@ def test_balldontlie_adapter_maps_payloads(settings):
|
||||
assert payload["player_stats"][0]["points"] == 25.0
|
||||
assert payload["player_stats"][0]["fg_pct"] == 55.0
|
||||
|
||||
player = payload["players"][0]
|
||||
assert player["nationality"] is None
|
||||
assert "current_team_external_id" not in player
|
||||
|
||||
expected_keys = {
|
||||
"external_id",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"full_name",
|
||||
"birth_date",
|
||||
"nationality",
|
||||
"nominal_position",
|
||||
"inferred_role",
|
||||
"height_cm",
|
||||
"weight_kg",
|
||||
"dominant_hand",
|
||||
"is_active",
|
||||
"aliases",
|
||||
}
|
||||
assert set(player.keys()) == expected_keys
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_balldontlie_map_seasons_marks_latest_as_current():
|
||||
seasons = map_seasons([2022, 2024, 2023, 2024])
|
||||
current_rows = [row for row in seasons if row["is_current"]]
|
||||
assert len(current_rows) == 1
|
||||
assert current_rows[0]["external_id"] == "season-2024"
|
||||
assert [row["external_id"] for row in seasons] == ["season-2022", "season-2023", "season-2024"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_balldontlie_client_retries_after_rate_limit(monkeypatch, settings):
|
||||
|
||||
Reference in New Issue
Block a user