132 lines
5.9 KiB
Python
132 lines
5.9 KiB
Python
from __future__ import annotations
|
||
|
||
import tempfile
|
||
import unittest
|
||
from datetime import date, timedelta
|
||
from pathlib import Path
|
||
|
||
from hockey_data.client import Stat2TVNotFoundError, Stat2TVResponse
|
||
from hockey_data.config import HockeySettingsStore
|
||
from hockey_data.models import Tournament
|
||
from hockey_data.service import HockeyDataService
|
||
from support import LocalTestDatabase
|
||
|
||
|
||
class TournamentScheduleFallbackTests(unittest.IsolatedAsyncioTestCase):
|
||
async def test_missing_live_schedule_uses_tournament_scoped_fallback(self) -> None:
|
||
with tempfile.TemporaryDirectory() as temp_dir:
|
||
base_dir = Path(temp_dir)
|
||
database = LocalTestDatabase(base_dir / "test.sqlite3")
|
||
database.create_all()
|
||
settings = HockeySettingsStore(base_dir / "settings")
|
||
service = HockeyDataService(base_dir=base_dir, database=database, settings=settings)
|
||
|
||
today = date.today()
|
||
tomorrow = today + timedelta(days=1)
|
||
with database.session() as session:
|
||
session.add(Tournament(
|
||
external_id="1437",
|
||
name_ru="Предсезонные матчи КХЛ",
|
||
season="2026-2027",
|
||
start_date=today - timedelta(days=5),
|
||
end_date=today + timedelta(days=20),
|
||
))
|
||
|
||
calls: list[str] = []
|
||
fallback_xml = f'''<Schedule tournamentId="1437" tournamentType="tmp">
|
||
<Game id="902918" date="{today.isoformat()}" time="15:00" teama="1" teamb="2" homeName="СКА" visitorName="Динамо" />
|
||
<Game id="902919" date="{tomorrow.isoformat()}" time="18:00" teama="3" teamb="4" homeName="Локомотив" visitorName="Ак Барс" />
|
||
</Schedule>'''.encode("utf-8")
|
||
|
||
async def fake_fetch(endpoint: str) -> Stat2TVResponse:
|
||
calls.append(endpoint)
|
||
if endpoint == "1437/schedule-1437-live.xml":
|
||
raise Stat2TVNotFoundError("https://example.test/live", 404)
|
||
if endpoint == "1437/schedule-1437.xml":
|
||
return Stat2TVResponse(
|
||
content=fallback_xml,
|
||
status_code=200,
|
||
content_type="application/xml",
|
||
auth_mode="test",
|
||
url=f"https://example.test/{endpoint}",
|
||
)
|
||
raise Stat2TVNotFoundError(f"https://example.test/{endpoint}", 404)
|
||
|
||
service.client.fetch_xml = fake_fetch # type: ignore[method-assign]
|
||
result = await service.sync_games(tournament_external_id="1437", on_date=today)
|
||
|
||
self.assertTrue(result["fallback_used"])
|
||
self.assertEqual(result["selected_date_count"], 1)
|
||
self.assertEqual(result["endpoint"], "1437/schedule-1437.xml")
|
||
self.assertEqual(calls[:2], [
|
||
"1437/schedule-1437-live.xml",
|
||
"1437/schedule-1437.xml",
|
||
])
|
||
|
||
payload = service.games(tournament_external_id="1437", on_date=today)
|
||
self.assertEqual(payload["meta"]["count"], 1)
|
||
self.assertEqual(payload["items"][0]["external_id"], "902918")
|
||
database.engine.dispose()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|
||
|
||
class TournamentScheduleDateQueryFallbackTests(unittest.IsolatedAsyncioTestCase):
|
||
async def test_automatic_sync_reaches_root_date_query_candidates(self) -> None:
|
||
with tempfile.TemporaryDirectory() as temp_dir:
|
||
base_dir = Path(temp_dir)
|
||
database = LocalTestDatabase(base_dir / "test.sqlite3")
|
||
database.create_all()
|
||
settings = HockeySettingsStore(base_dir / "settings")
|
||
service = HockeyDataService(base_dir=base_dir, database=database, settings=settings)
|
||
|
||
selected = date(2026, 8, 12)
|
||
with database.session() as session:
|
||
session.add(Tournament(
|
||
external_id="1437",
|
||
name_ru="Предсезонные матчи КХЛ",
|
||
season="2026-2027",
|
||
start_date=date(2026, 7, 20),
|
||
end_date=date(2026, 9, 4),
|
||
))
|
||
|
||
calls: list[str] = []
|
||
payload = f'''<Schedule tournamentId="1437" tournamentType="tmp">
|
||
<Game id="902918" date="{selected.isoformat()}" time="15:00" teama="1" teamb="2" homeName="СКА" visitorName="Динамо" />
|
||
</Schedule>'''.encode("utf-8")
|
||
|
||
target = f"games.xml?tournament=1437&date={selected.isoformat()}"
|
||
|
||
async def fake_fetch(endpoint: str) -> Stat2TVResponse:
|
||
calls.append(endpoint)
|
||
if endpoint == target:
|
||
return Stat2TVResponse(
|
||
content=payload,
|
||
status_code=200,
|
||
content_type="application/xml",
|
||
auth_mode="test",
|
||
url=f"https://example.test/{endpoint}",
|
||
)
|
||
raise Stat2TVNotFoundError(f"https://example.test/{endpoint}", 404)
|
||
|
||
service.client.fetch_xml = fake_fetch # type: ignore[method-assign]
|
||
result = await service.sync_games(
|
||
tournament_external_id="1437",
|
||
on_date=selected,
|
||
force_discovery=False,
|
||
)
|
||
|
||
self.assertTrue(result["fallback_used"])
|
||
self.assertEqual(result["selected_date_count"], 1)
|
||
self.assertEqual(result["endpoint"], target)
|
||
self.assertIn(target, calls)
|
||
# Confirm this happened during the normal automatic path, not only
|
||
# force_discovery=True.
|
||
self.assertGreater(calls.index(target), 0)
|
||
|
||
visible = service.games(tournament_external_id="1437", on_date=selected)
|
||
self.assertEqual(visible["meta"]["count"], 1)
|
||
self.assertEqual(visible["items"][0]["external_id"], "902918")
|
||
database.engine.dispose()
|