73 lines
3.2 KiB
Python
73 lines
3.2 KiB
Python
from types import SimpleNamespace
|
|||
|
|
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
|
||
|
|
|
||
|
|
|
||
|
|
def client_for(monkeypatch, search):
|
||
|
|
client = SimpleNamespace(collections={'schools': SimpleNamespace(documents=SimpleNamespace(search=search))})
|
||
|
|
monkeypatch.setattr(data_loader, '_get_typesense_client', lambda: client)
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_returns_matches_beyond_first_page(monkeypatch):
|
||
|
|
pages = []
|
||
|
|
def search(params):
|
||
|
|
pages.append(params['page'])
|
||
|
|
urns = range(100000, 100250) if params['page'] == 1 else [100999]
|
||
|
|
return {'found': 251, 'hits': [{'document': {'urn': u}} for u in urns]}
|
||
|
|
client_for(monkeypatch, search)
|
||
|
|
result = data_loader.search_schools_typesense('academy')
|
||
|
|
assert len(result) == 251
|
||
|
|
assert result[-1] == 100999
|
||
|
|
assert pages == [1, 2]
|
||
|
|
|
||
|
|
|
||
|
|
def test_later_page_failure_does_not_return_partial_results(monkeypatch):
|
||
|
|
def search(params):
|
||
|
|
if params['page'] == 2:
|
||
|
|
raise RuntimeError('timeout')
|
||
|
|
return {'found': 251, 'hits': [{'document': {'urn': u}} for u in range(100000, 100250)]}
|
||
|
|
client_for(monkeypatch, search)
|
||
|
|
assert data_loader.search_schools_typesense('academy') is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_zero_matches_are_distinct_from_unavailable(monkeypatch):
|
||
|
|
client_for(monkeypatch, lambda _: {'found': 0, 'hits': []})
|
||
|
|
assert data_loader.search_schools_typesense('academy') == []
|
||
|
|
monkeypatch.setattr(data_loader, '_get_typesense_client', lambda: None)
|
||
|
|
assert data_loader.search_schools_typesense('academy') is None
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize('matches, expected', [([], []), (None, [100001])])
|
||
|
|
def test_fallback_only_on_dependency_failure(monkeypatch, matches, expected):
|
||
|
|
monkeypatch.setattr(api.limiter, 'enabled', False)
|
||
|
|
monkeypatch.setattr(api, 'load_latest_school_data', _schools_df)
|
||
|
|
monkeypatch.setattr(api, 'search_schools_typesense', lambda _: matches)
|
||
|
|
response = TestClient(api.app).get('/api/schools?search=Alpha')
|
||
|
|
assert response.status_code == 200
|
||
|
|
assert [s['urn'] for s in response.json()['schools']] == expected
|
||
|
|
|
||
|
|
|
||
|
|
def test_filtered_api_keeps_match_from_second_search_page(monkeypatch):
|
||
|
|
monkeypatch.setattr(api.limiter, 'enabled', False)
|
||
|
|
df = _schools_df()
|
||
|
|
monkeypatch.setattr(api, 'load_latest_school_data', lambda: df)
|
||
|
|
def search(params):
|
||
|
|
urns = range(200000, 200250) if params['page'] == 1 else [100001]
|
||
|
|
return {'found': 251, 'hits': [{'document': {'urn': u}} for u in urns]}
|
||
|
|
client_for(monkeypatch, search)
|
||
|
|
response = TestClient(api.app).get('/api/schools?search=Alpha&local_authority=Testshire')
|
||
|
|
assert response.status_code == 200
|
||
|
|
assert response.json()['total'] == 1
|
||
|
|
assert response.json()['schools'][0]['urn'] == 100001
|
||
|
|
|
||
|
|
|
||
|
|
def test_unavailable_dataset_is_not_a_missing_school_or_empty_search(monkeypatch):
|
||
|
|
import pandas as pd
|
||
|
|
monkeypatch.setattr(api.limiter, 'enabled', False)
|
||
|
|
monkeypatch.setattr(api, 'load_school_data', lambda: pd.DataFrame())
|
||
|
|
monkeypatch.setattr(api, 'load_latest_school_data', lambda: pd.DataFrame())
|
||
|
|
client = TestClient(api.app)
|
||
|
|
assert client.get('/api/schools/100001').status_code == 503
|
||
|
|
assert client.get('/api/schools?search=school').status_code == 503
|