feat(flags): ship-dark feature flags, with last-distance-offered behind the first one #125
No files matched your search
+7
-1
@@ -808,7 +808,13 @@ async def get_school_details(request: Request, urn: int):
|
||||
"census": supplementary.get("census"),
|
||||
"admissions": supplementary.get("admissions"),
|
||||
"admissions_history": supplementary.get("admissions_history") or [],
|
||||
"admission_distance": supplementary.get("admission_distance"),
|
||||
# Behind a flag, and withheld at the source rather than rendered-but-
|
||||
# hidden: this endpoint is public and unauthenticated, so a field left
|
||||
# in the payload is a published field. The key is absent, not null —
|
||||
# null would state that this school has no cut-off, which is a
|
||||
# different claim from "we are not publishing cut-offs".
|
||||
**({"admission_distance": supplementary.get("admission_distance")}
|
||||
if flags.is_enabled("admission_distance") else {}),
|
||||
"sen_detail": supplementary.get("sen_detail"),
|
||||
"phonics": supplementary.get("phonics"),
|
||||
"deprivation": supplementary.get("deprivation"),
|
||||
|
||||
@@ -93,3 +93,71 @@ def test_the_flags_endpoint_answers_false_when_unleash_is_unreachable(monkeypatc
|
||||
res = _client().get("/api/flags")
|
||||
assert res.status_code == 200
|
||||
assert all(v is False for v in res.json().values())
|
||||
|
||||
|
||||
def _school_payload(monkeypatch, *, flag_on: bool):
|
||||
"""Fetch one school's payload with the distance flag forced on or off.
|
||||
|
||||
The DataFrame shape is copied from test_school_details.py rather than
|
||||
minimised: the endpoint reads a wide set of GIAS columns, and a trimmed
|
||||
frame fails for reasons that have nothing to do with flags.
|
||||
"""
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from fastapi.testclient import TestClient
|
||||
from backend import app as app_module
|
||||
|
||||
df = pd.DataFrame([{
|
||||
"urn": 150275,
|
||||
"school_name": "West London Performing Arts Academy",
|
||||
"phase": "Secondary",
|
||||
"school_type": "Special post 16 institution",
|
||||
"trust_name": None,
|
||||
"religious_denomination": "Does not apply",
|
||||
"gender": None,
|
||||
"age_range": "16-25",
|
||||
"admissions_policy": None,
|
||||
"capacity": np.nan,
|
||||
"gias_total_pupils": np.nan,
|
||||
"headteacher_name": None,
|
||||
"website": None,
|
||||
"ofsted_grade": np.nan,
|
||||
"local_authority": "Ealing",
|
||||
"address": "268 Northfield Avenue, London, W5 4UB",
|
||||
"postcode": "W5 4UB",
|
||||
"latitude": 51.4986,
|
||||
"longitude": -0.3148,
|
||||
"year": np.nan,
|
||||
"total_pupils": np.nan,
|
||||
"eligible_pupils": np.nan,
|
||||
"rwm_expected_pct": np.nan,
|
||||
}])
|
||||
|
||||
monkeypatch.setattr(app_module, "load_school_data", lambda: df)
|
||||
# Two arguments: get_supplementary_data(db, urn). See backend/app.py.
|
||||
monkeypatch.setattr(
|
||||
app_module, "get_supplementary_data",
|
||||
lambda db, urn: {"admission_distance": {"distance_m": 772.49,
|
||||
"year": 2024}})
|
||||
monkeypatch.setattr(flags, "is_enabled", lambda name: flag_on)
|
||||
|
||||
client = TestClient(app_module.app, raise_server_exceptions=False)
|
||||
res = client.get("/api/schools/150275")
|
||||
assert res.status_code == 200, res.text
|
||||
return res.json()
|
||||
|
||||
|
||||
def test_the_distance_field_is_absent_when_the_flag_is_off(monkeypatch):
|
||||
"""Absent, not null, and withheld at the source.
|
||||
|
||||
/api/schools/ is public and unauthenticated. Leaving a withheld field in
|
||||
the payload while declining to render it hands the record to anyone who
|
||||
opens the network tab — the reasoning already recorded in c9a1892.
|
||||
"""
|
||||
body = _school_payload(monkeypatch, flag_on=False)
|
||||
assert "admission_distance" not in body
|
||||
|
||||
|
||||
def test_the_distance_field_is_present_when_the_flag_is_on(monkeypatch):
|
||||
body = _school_payload(monkeypatch, flag_on=True)
|
||||
assert body["admission_distance"]["distance_m"] == 772.49
|
||||
@@ -361,7 +361,12 @@ export interface SchoolDetailsResponse {
|
||||
* held back as a paid feature and are not part of this public payload — see
|
||||
* data_loader._admission_distance.
|
||||
*/
|
||||
admission_distance: SchoolAdmissionDistance | null;
|
||||
/**
|
||||
* Absent — not null — when the admission_distance flag is off. Null means
|
||||
* "this school has no published cut-off"; absent means "cut-offs are not
|
||||
* being published at all". They are different claims and the type says so.
|
||||
*/
|
||||
admission_distance?: SchoolAdmissionDistance | null;
|
||||
deprivation: SchoolDeprivation | null;
|
||||
finance: SchoolFinance | null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user