111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
"""Smoke-test the ORM schema — every table must round-trip a row."""
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from fire_planner.db import (
|
|
AccountSnapshot,
|
|
McPath,
|
|
McRun,
|
|
ProjectionYearly,
|
|
Scenario,
|
|
ScenarioSummary,
|
|
)
|
|
|
|
|
|
async def test_account_snapshot_roundtrip(session: AsyncSession) -> None:
|
|
snap = AccountSnapshot(
|
|
external_id="wealthfolio:account-1:2026-04-25",
|
|
snapshot_date=date(2026, 4, 25),
|
|
account_id="account-1",
|
|
account_name="ISA",
|
|
account_type="ISA",
|
|
currency="GBP",
|
|
market_value=Decimal("123456.78"),
|
|
market_value_gbp=Decimal("123456.78"),
|
|
)
|
|
session.add(snap)
|
|
await session.commit()
|
|
result = await session.execute(select(AccountSnapshot))
|
|
rows = result.scalars().all()
|
|
assert len(rows) == 1
|
|
assert rows[0].external_id == "wealthfolio:account-1:2026-04-25"
|
|
|
|
|
|
async def test_scenario_roundtrip(session: AsyncSession) -> None:
|
|
scen = Scenario(
|
|
external_id="cyprus-vpw-leave-y3-glide-rising",
|
|
jurisdiction="cyprus",
|
|
strategy="vpw",
|
|
leave_uk_year=3,
|
|
glide_path="rising",
|
|
spending_gbp=Decimal("100000"),
|
|
nw_seed_gbp=Decimal("1000000"),
|
|
savings_per_year_gbp=Decimal("100000"),
|
|
config_json={"horizon_years": 60},
|
|
)
|
|
session.add(scen)
|
|
await session.commit()
|
|
result = await session.execute(select(Scenario))
|
|
rows = result.scalars().all()
|
|
assert len(rows) == 1
|
|
assert rows[0].jurisdiction == "cyprus"
|
|
|
|
|
|
async def test_mc_run_roundtrip(session: AsyncSession) -> None:
|
|
run = McRun(
|
|
scenario_id=1,
|
|
n_paths=10000,
|
|
seed=42,
|
|
success_rate=Decimal("0.9412"),
|
|
p10_ending_gbp=Decimal("250000"),
|
|
p50_ending_gbp=Decimal("3500000"),
|
|
p90_ending_gbp=Decimal("12000000"),
|
|
median_lifetime_tax_gbp=Decimal("750000"),
|
|
elapsed_seconds=Decimal("42.351"),
|
|
)
|
|
session.add(run)
|
|
await session.commit()
|
|
result = await session.execute(select(McRun))
|
|
rows = result.scalars().all()
|
|
assert len(rows) == 1
|
|
assert rows[0].n_paths == 10000
|
|
|
|
|
|
async def test_remaining_tables_smoke(session: AsyncSession) -> None:
|
|
session.add(
|
|
McPath(mc_run_id=1,
|
|
path_idx=0,
|
|
bucket="median",
|
|
year_idx=0,
|
|
portfolio_gbp=Decimal("1000000"),
|
|
withdrawal_gbp=Decimal("100000"),
|
|
tax_paid_gbp=Decimal("0"),
|
|
real_portfolio_gbp=Decimal("1000000")))
|
|
session.add(
|
|
ProjectionYearly(mc_run_id=1,
|
|
year_idx=0,
|
|
p10_portfolio_gbp=Decimal("800000"),
|
|
p25_portfolio_gbp=Decimal("900000"),
|
|
p50_portfolio_gbp=Decimal("1000000"),
|
|
p75_portfolio_gbp=Decimal("1100000"),
|
|
p90_portfolio_gbp=Decimal("1200000"),
|
|
p50_withdrawal_gbp=Decimal("100000"),
|
|
p50_tax_gbp=Decimal("0"),
|
|
survival_rate=Decimal("1")))
|
|
session.add(
|
|
ScenarioSummary(scenario_id=1,
|
|
mc_run_id=1,
|
|
jurisdiction="uk",
|
|
strategy="trinity",
|
|
leave_uk_year=0,
|
|
glide_path="static",
|
|
spending_gbp=Decimal("100000"),
|
|
success_rate=Decimal("0.95"),
|
|
p10_ending_gbp=Decimal("200000"),
|
|
p50_ending_gbp=Decimal("3000000"),
|
|
p90_ending_gbp=Decimal("10000000"),
|
|
median_lifetime_tax_gbp=Decimal("800000")))
|
|
await session.commit()
|