159 lines
5.1 KiB
Python
159 lines
5.1 KiB
Python
import os
|
|
import sys
|
|
from pathlib import Path
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
# Ensure required env vars for app import/config
|
|
os.environ.setdefault("SECRET_KEY", "x" * 32)
|
|
os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite")
|
|
|
|
# Ensure repository root on sys.path for direct test runs
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from app.main import app # noqa: E402
|
|
from app.auth.security import get_current_user # noqa: E402
|
|
from tests.helpers import assert_http_error # noqa: E402
|
|
from app.database.base import SessionLocal # noqa: E402
|
|
from app.models.pensions import LifeTable, NumberTable # noqa: E402
|
|
from app.services.mortality import ( # noqa: E402
|
|
get_life_values,
|
|
get_number_value,
|
|
InvalidCodeError,
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def client():
|
|
# Override auth to bypass JWT for these tests
|
|
class _User:
|
|
def __init__(self):
|
|
self.id = "test"
|
|
self.username = "tester"
|
|
self.is_admin = True
|
|
self.is_active = True
|
|
|
|
app.dependency_overrides[get_current_user] = lambda: _User()
|
|
|
|
try:
|
|
yield TestClient(app)
|
|
finally:
|
|
app.dependency_overrides.pop(get_current_user, None)
|
|
|
|
|
|
def _seed_life_and_number():
|
|
db = SessionLocal()
|
|
try:
|
|
# Seed a life table row for age 65
|
|
db.query(LifeTable).filter(LifeTable.age == 65).delete()
|
|
lt = LifeTable(
|
|
age=65,
|
|
le_wm=14.5,
|
|
na_wm=87000.0,
|
|
le_af=20.1,
|
|
na_af=92000.0,
|
|
le_ha=18.2,
|
|
na_ha=88000.0,
|
|
)
|
|
db.add(lt)
|
|
|
|
# Seed a number table row for month 305
|
|
db.query(NumberTable).filter(NumberTable.month == 305).delete()
|
|
nt = NumberTable(
|
|
month=305,
|
|
na_wm=80000.0,
|
|
na_af=90000.0,
|
|
na_ha=85000.0,
|
|
)
|
|
db.add(nt)
|
|
|
|
db.commit()
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def test_service_helpers_success_invalid_and_not_found():
|
|
_seed_life_and_number()
|
|
db = SessionLocal()
|
|
try:
|
|
# Success cases
|
|
res = get_life_values(db, age=65, sex="M", race="W")
|
|
assert res and res["le"] == 14.5 and res["na"] == 87000.0
|
|
res = get_life_values(db, age=65, sex="F", race="A")
|
|
assert res and res["le"] == 20.1 and res["na"] == 92000.0
|
|
res = get_life_values(db, age=65, sex="A", race="H")
|
|
assert res and res["le"] == 18.2 and res["na"] == 88000.0
|
|
|
|
nres = get_number_value(db, month=305, sex="M", race="W")
|
|
assert nres and nres["na"] == 80000.0
|
|
nres = get_number_value(db, month=305, sex="F", race="A")
|
|
assert nres and nres["na"] == 90000.0
|
|
nres = get_number_value(db, month=305, sex="A", race="H")
|
|
assert nres and nres["na"] == 85000.0
|
|
|
|
# Invalid codes
|
|
with pytest.raises(InvalidCodeError):
|
|
get_life_values(db, age=65, sex="X", race="W")
|
|
with pytest.raises(InvalidCodeError):
|
|
get_number_value(db, month=305, sex="M", race="Z")
|
|
|
|
# Not found
|
|
assert get_life_values(db, age=9999, sex="M", race="W") is None
|
|
assert get_number_value(db, month=99999, sex="M", race="W") is None
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def test_api_life_valid_invalid_not_found(client: TestClient):
|
|
_seed_life_and_number()
|
|
|
|
# Valid lookups
|
|
resp = client.get("/api/mortality/life/65", params={"sex": "M", "race": "W"})
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["le"] == 14.5 and data["na"] == 87000.0
|
|
|
|
resp = client.get("/api/mortality/life/65", params={"sex": "F", "race": "A"})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["le"] == 20.1
|
|
|
|
# Invalid code -> 400 wrapped error
|
|
resp = client.get("/api/mortality/life/65", params={"sex": "X", "race": "W"})
|
|
assert_http_error(resp, 400, "Invalid sex code")
|
|
|
|
# Not found -> 404 wrapped error
|
|
resp = client.get("/api/mortality/life/9999", params={"sex": "M", "race": "W"})
|
|
assert_http_error(resp, 404, "Age not found")
|
|
|
|
|
|
def test_api_number_valid_invalid_not_found(client: TestClient):
|
|
_seed_life_and_number()
|
|
|
|
# Valid lookup
|
|
resp = client.get("/api/mortality/number/305", params={"sex": "M", "race": "W"})
|
|
assert resp.status_code == 200
|
|
assert resp.json()["na"] == 80000.0
|
|
|
|
# Invalid code -> 400
|
|
resp = client.get("/api/mortality/number/305", params={"sex": "M", "race": "Z"})
|
|
assert_http_error(resp, 400, "Invalid race code")
|
|
|
|
# Not found -> 404
|
|
resp = client.get("/api/mortality/number/99999", params={"sex": "M", "race": "W"})
|
|
assert_http_error(resp, 404, "Month not found")
|
|
|
|
|
|
def test_api_validation_negative_inputs(client: TestClient):
|
|
# Negative age -> 422 validation envelope
|
|
resp = client.get("/api/mortality/life/-1", params={"sex": "M", "race": "W"})
|
|
from tests.helpers import assert_validation_error
|
|
assert_validation_error(resp, "age")
|
|
|
|
# Negative month -> 422 validation envelope
|
|
resp = client.get("/api/mortality/number/-5", params={"sex": "F", "race": "A"})
|
|
assert_validation_error(resp, "month")
|
|
|
|
|