89 lines
3.7 KiB
Python
89 lines
3.7 KiB
Python
"""Shared test fixtures. Locates the Jan-2026 sample files (large; integration tests)."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
# ---------------------------------------------------------------------------------------
|
|
# Redirect ALL test data away from production — BEFORE anything imports app.config, which
|
|
# reads these variables once at module load and caches them.
|
|
#
|
|
# The suite creates AND DELETES closings, so pointing it at the live database would destroy
|
|
# Finance's data. That already happened once under SQLite (75 test sessions accumulated in
|
|
# the production file), and the blast radius is larger now that the store is a shared MySQL
|
|
# server rather than a local file.
|
|
#
|
|
# `load_dotenv()` in app/config.py does not override variables already present in the
|
|
# environment, so setting MYSQL_DATABASE here wins over .env. The database is created
|
|
# automatically by database._ensure_database().
|
|
# ---------------------------------------------------------------------------------------
|
|
_TEST_DATA_DIR = Path(tempfile.mkdtemp(prefix="ar-aging-tests-"))
|
|
os.environ["AR_DATA_DIR"] = str(_TEST_DATA_DIR)
|
|
|
|
# Processing auto-fetches daily FX rates from the provider (jobs.FX_AUTO_DAILY); tests
|
|
# must never touch the network, so the automatic fetch is forced off for the whole suite.
|
|
# The FX tests exercise seeding explicitly through a mocked HTTP layer — including one
|
|
# integration test that re-enables the flag with monkeypatch (test_fx_service.py).
|
|
os.environ["AR_FX_AUTO_DAILY"] = "0"
|
|
|
|
_PROD_DB = os.environ.get("MYSQL_DATABASE", "")
|
|
TEST_DB_NAME = os.environ.get("AR_TEST_MYSQL_DATABASE", "ar_aging_pytest")
|
|
os.environ["MYSQL_DATABASE"] = TEST_DB_NAME
|
|
|
|
# Default: the project root two levels above ar-aging-app/backend.
|
|
_DEFAULT_SAMPLE_DIR = Path(__file__).resolve().parents[3]
|
|
|
|
SAMPLE_DIR = Path(os.environ.get("AR_SAMPLE_DIR", str(_DEFAULT_SAMPLE_DIR)))
|
|
|
|
JAN_FILES = [
|
|
"USA Amazon Transactions 01 to 10 January,2026.xlsx",
|
|
"USA Amazon Transactions 11 to 20 January,2026.xlsx",
|
|
"USA Amazon Transactions 21 to 31 January,2026.xlsx",
|
|
]
|
|
SAMPLE_WORKBOOK = "Accounts Receivable Aging (Jan-26) 1.xlsx"
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def jan_files() -> list[str]:
|
|
paths = [str(SAMPLE_DIR / f) for f in JAN_FILES]
|
|
missing = [p for p in paths if not os.path.exists(p)]
|
|
if missing:
|
|
pytest.skip(f"Sample Jan-2026 files not found: {missing}")
|
|
return paths
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def sample_workbook() -> str:
|
|
p = str(SAMPLE_DIR / SAMPLE_WORKBOOK)
|
|
if not os.path.exists(p):
|
|
pytest.skip(f"Sample workbook not found: {p}")
|
|
return p
|
|
|
|
|
|
@pytest.fixture(autouse=True, scope="session")
|
|
def _never_touch_production_data():
|
|
"""
|
|
Hard stop if the redirect above ever fails.
|
|
|
|
The suite creates and deletes closings, so running against the live database would
|
|
destroy Finance's data. Assert the isolation actually took effect rather than trusting
|
|
it — this fixture is the reason a renamed config variable can't silently re-point the
|
|
tests at production.
|
|
"""
|
|
from app.config import DATA_DIR, MYSQL_DATABASE
|
|
assert MYSQL_DATABASE == TEST_DB_NAME, (
|
|
f"tests are pointed at MySQL database {MYSQL_DATABASE!r} — expected "
|
|
f"{TEST_DB_NAME!r}. app/config.py reads MYSQL_DATABASE; check that name."
|
|
)
|
|
assert not _PROD_DB or MYSQL_DATABASE != _PROD_DB, (
|
|
f"the test database is the same as the configured production database "
|
|
f"({_PROD_DB!r}). Set AR_TEST_MYSQL_DATABASE to a separate name."
|
|
)
|
|
assert str(DATA_DIR).startswith(str(_TEST_DATA_DIR)), (
|
|
f"tests would write uploads/exports to {DATA_DIR}, not a temp directory."
|
|
)
|
|
yield
|