"""Publication must preserve the current dataset until every replacement is ready.""" import asyncio import pandas as pd import pytest from fastapi.testclient import TestClient from backend import app as api, data_loader from backend.tests.test_sixth_form_flag import _schools_df @pytest.fixture def client(monkeypatch): old = _schools_df() monkeypatch.setattr(data_loader, '_df_cache', old) monkeypatch.setattr(data_loader, '_df_latest_cache', old) monkeypatch.setattr(api, '_place_registry', {'old': 'registry'}) monkeypatch.setattr(api, '_place_index', {'old': 'index'}) monkeypatch.setattr(api, '_place_index_source', api._place_registry) monkeypatch.setattr(api, '_sitemaps', {'old.xml': 'old sitemap'}) monkeypatch.setattr(api, '_publication_lock', asyncio.Lock()) monkeypatch.setattr(api.limiter, 'enabled', False) api.app.dependency_overrides[api.verify_admin_api_key] = lambda: True yield TestClient(api.app, raise_server_exceptions=False) api.app.dependency_overrides.clear() def state(): return (data_loader._df_cache, data_loader._df_latest_cache, api._place_registry, api._place_index, api._place_index_source, api._sitemaps) @pytest.mark.parametrize('failure', ['empty', 'database', 'sitemap', 'duplicate']) def test_failed_reload_preserves_every_published_object(client, monkeypatch, failure): before = state() df = _schools_df() if failure == 'empty': df = pd.DataFrame() if failure == 'duplicate': df = pd.concat([df, df.iloc[:1]], ignore_index=True) def load(): if failure == 'database': raise RuntimeError('database unavailable') return df monkeypatch.setattr(api, 'load_school_data_as_dataframe', load) if failure == 'sitemap': monkeypatch.setattr(api, 'build_sitemaps', lambda *args: (_ for _ in ()).throw(RuntimeError('bad XML'))) response = client.post('/api/admin/reload') assert response.status_code == 503 assert all(a is b for a, b in zip(before, state())) def test_success_publishes_school_data_places_and_sitemaps(client, monkeypatch): df = _schools_df() df.loc[0, 'school_name'] = 'Replacement School' monkeypatch.setattr(api, 'load_school_data_as_dataframe', lambda: df) response = client.post('/api/admin/reload') assert response.status_code == 200 assert data_loader.load_school_data() is df assert data_loader.load_latest_school_data().iloc[0].school_name == 'Replacement School' assert api._place_index_source is api._place_registry assert 'old.xml' not in api._sitemaps assert 'replacement-school' in api._sitemaps['schools-1.xml'] def test_failed_sitemap_regeneration_keeps_existing_publication(client, monkeypatch): before = state() monkeypatch.setattr(api, 'build_sitemaps', lambda *args: (_ for _ in ()).throw(RuntimeError('bad XML'))) assert client.post('/api/admin/regenerate-sitemap').status_code == 503 assert all(a is b for a, b in zip(before, state()))