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'''
'''.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'''
'''.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()