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

48
backend/tests/conftest.py Normal file
View File

@@ -0,0 +1,48 @@
"""Shared fixtures. Env vars are set before any app import so config.Settings()
fail-fast validation passes with deterministic test values regardless of the
developer's .env."""
import os
os.environ.setdefault(
"SECRET_KEY", "test-secret-key-0123456789abcdef0123456789abcdef"
)
os.environ.setdefault("ADMIN_USERNAME", "testadmin")
os.environ.setdefault("ADMIN_PASSWORD", "test-password")
os.environ.setdefault("DATABASE_URL", "sqlite://")
import pytest
from sqlalchemy.pool import StaticPool
from sqlmodel import Session, SQLModel, create_engine
import app.models.models # noqa: F401 — register all tables on the metadata
@pytest.fixture()
def engine():
eng = create_engine(
"sqlite://",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
SQLModel.metadata.create_all(eng)
yield eng
eng.dispose()
@pytest.fixture()
def session(engine):
with Session(engine) as s:
yield s
@pytest.fixture(autouse=True)
def fixed_exchange_rates(monkeypatch):
"""Never hit the network: CRC passthrough, USD pinned at 500."""
from app.services import exchange_rate
monkeypatch.setattr(
exchange_rate,
"get_crc_multipliers",
lambda session: {"CRC": 1.0, "USD": 500.0},
)