Add pytest harness and 55-test suite for core backend logic

Covers: billing-cycle characterization (the BE-06 convention, boundary
instants, year wraps, deferred transactions), projection engine
(recurring schedules, no-double-count, cumulative balances, overrides,
fresh start), auth (JWT roundtrip/expiry, API tokens, constant-time
creds, rate-limit window), fail-fast settings, and the BAC paste
parser. SQLite in-memory fixtures, exchange rates pinned — no network.
Also doubles as the float-behavior baseline for the Phase 2 Decimal
migration (plan 1.5). config.py moves to SettingsConfigDict to clear
the pydantic deprecation warning from test output.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-06-09 19:46:54 -06:00
parent 996bd437a1
commit c725c1487d
9 changed files with 707 additions and 3 deletions

View File

@@ -0,0 +1,44 @@
"""Fail-fast settings validation (SEC-01 / BE-15)."""
import pytest
from pydantic import ValidationError
from app.config import Settings
GOOD = {
"SECRET_KEY": "f" * 64,
"ADMIN_USERNAME": "charlie",
"ADMIN_PASSWORD": "a-real-password",
}
def make(**overrides) -> Settings:
return Settings(_env_file=None, **{**GOOD, **overrides})
def test_valid_settings_boot():
s = make()
assert s.ACCESS_TOKEN_EXPIRE_MINUTES == 60 * 24 * 7
assert s.COOKIE_SECURE is True
assert s.cors_origins_list[0] == "https://wealth.cescalante.dev"
@pytest.mark.parametrize(
"overrides",
[
{"SECRET_KEY": "change-me-in-production"},
{"SECRET_KEY": "short"},
{"SECRET_KEY": ""},
{"ADMIN_PASSWORD": "admin"},
{"ADMIN_PASSWORD": ""},
{"ADMIN_USERNAME": ""},
],
)
def test_weak_or_missing_secrets_rejected(overrides):
with pytest.raises(ValidationError):
make(**overrides)
def test_cors_origins_parse_and_strip():
s = make(CORS_ORIGINS=" https://a.example , http://b.example ,")
assert s.cors_origins_list == ["https://a.example", "http://b.example"]