Aug 4 - Update code to follow up - MT11 b
This commit is contained in:
+46
-4
@@ -10,15 +10,54 @@ whole suite can run with no MySQL, no Redis, no Stripe, and no real secrets.
|
||||
|
||||
The pure-logic tests (SLA math, webhook helpers) never touch the DB. The
|
||||
routing-inertness test uses the in-memory SQLite engine only.
|
||||
|
||||
Why these are ASSIGNED and not `setdefault`
|
||||
-------------------------------------------
|
||||
`os.environ.setdefault` is a no-op when the key is already present, so running
|
||||
pytest from a shell that exports the deployment's variables — or under anything
|
||||
that loads `.env` before pytest starts — silently handed the suite the REAL
|
||||
configuration. Two consequences, both observed:
|
||||
|
||||
* `MULTI_TENANT_ENABLED=true` engages Host→tenant resolution. The test client
|
||||
sends Host `localhost`, `resolve_tenant()` returns None, and
|
||||
`app/tenancy/middleware.py::_tenant_resolver` returns the "workspace not
|
||||
found" page with status 404 for EVERY request, before any view runs. The
|
||||
whole suite fails with `assert 404 == <expected>`.
|
||||
* `DATABASE_URL` pointing at MySQL would make the `db.drop_all()` in each
|
||||
module's `client` fixture run against a real database.
|
||||
|
||||
The values below are therefore forced. Anything a developer needs to vary they
|
||||
can vary in the fixture, not through ambient environment. `load_dotenv()` in
|
||||
config.py runs later with `override=False`, so these win.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# ── Import-time env (must be set BEFORE `import app`) ────────────────────────
|
||||
os.environ.setdefault('SECRET_KEY', 'test-secret-key')
|
||||
os.environ.setdefault('DATABASE_URL', 'sqlite:///:memory:')
|
||||
os.environ.setdefault('MULTI_TENANT_ENABLED', 'false')
|
||||
os.environ.setdefault('BILLING_ENABLED', 'false')
|
||||
# Assigned, NOT setdefault — see the module docstring.
|
||||
os.environ['SECRET_KEY'] = 'test-secret-key'
|
||||
os.environ['DATABASE_URL'] = 'sqlite:///:memory:'
|
||||
os.environ['MULTI_TENANT_ENABLED'] = 'false'
|
||||
os.environ['BILLING_ENABLED'] = 'false'
|
||||
# The apex-host branch of the tenant resolver runs even with the MT flag off, so
|
||||
# pin the base domain rather than inheriting it. 'jqc.app' is config.py's own
|
||||
# default and is what tests/test_landing.py asserts against; the test client's
|
||||
# Host ('localhost') can never match it.
|
||||
os.environ['TENANT_BASE_DOMAIN'] = 'jqc.app'
|
||||
# Control-plane vars must be absent: their presence is what lets the resolver
|
||||
# reach a real control DB instead of failing loudly.
|
||||
os.environ.pop('CONTROL_DATABASE_URL', None)
|
||||
os.environ.pop('CONTROL_FERNET_KEY', None)
|
||||
|
||||
# ── Belt-and-braces guard ────────────────────────────────────────────────────
|
||||
# Every module-level `client` fixture calls db.drop_all(). If anything ever
|
||||
# re-points DATABASE_URL at a real server, refuse to run rather than drop it.
|
||||
if not os.environ['DATABASE_URL'].startswith('sqlite:'):
|
||||
sys.exit(
|
||||
f"REFUSING TO RUN: DATABASE_URL is {os.environ['DATABASE_URL']!r}, not "
|
||||
f"SQLite. The test fixtures call db.drop_all()."
|
||||
)
|
||||
|
||||
import pytest # noqa: E402
|
||||
|
||||
@@ -29,6 +68,9 @@ def app():
|
||||
from app import create_app
|
||||
application = create_app('default')
|
||||
application.config.update(TESTING=True, WTF_CSRF_ENABLED=False, SQLALCHEMY_ECHO=False)
|
||||
# Belt-and-braces again at the app layer: config.py could pick these up from
|
||||
# a source we have not anticipated. A test run must never resolve tenants.
|
||||
application.config.update(MULTI_TENANT_ENABLED=False, BILLING_ENABLED=False)
|
||||
return application
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user