68 lines
3.0 KiB
Python
68 lines
3.0 KiB
Python
"""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()))
|