Files
orion/conftest.py
Samir Boulahtit e9253fbd84 refactor: rename Wizamart to Orion across entire codebase
Replace all ~1,086 occurrences of Wizamart/wizamart/WIZAMART/WizaMart
with Orion/orion/ORION across 184 files. This includes database
identifiers, email addresses, domain references, R2 bucket names,
DNS prefixes, encryption salt, Celery app name, config defaults,
Docker configs, CI configs, documentation, seed data, and templates.

Renames homepage-wizamart.html template to homepage-orion.html.
Fixes duplicate file_pattern key in api.yaml architecture rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 16:46:56 +01:00

181 lines
5.6 KiB
Python

# conftest.py - PostgreSQL test configuration (project root)
"""
Core pytest configuration and fixtures.
This project uses PostgreSQL for testing. Start the test database with:
make test-db-up
IMPORTANT - Fixture Best Practices:
===================================
1. DO NOT use db.expunge() on fixtures - it detaches objects from the session
and breaks lazy loading of relationships (e.g., product.marketplace_product).
2. Test isolation is achieved through TRUNCATE CASCADE after each test,
which is much faster than dropping/recreating tables.
3. If you need to ensure an object has fresh data, use db.refresh(obj) instead
of expunge/re-query patterns.
4. The session uses expire_on_commit=False to prevent objects from being expired
after commits, which helps with relationship access across operations.
See docs/testing/testing-guide.md for comprehensive testing documentation.
"""
import os
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from app.core.database import Base, get_db
from main import app
# PostgreSQL test database URL
# Use environment variable or default to local Docker test database
TEST_DATABASE_URL = os.getenv(
"TEST_DATABASE_URL",
"postgresql://test_user:test_password@localhost:5433/orion_test"
)
@pytest.fixture(scope="session")
def engine():
"""Create test database engine.
Verifies PostgreSQL connection on startup and provides helpful
error message if the test database is not running.
"""
engine = create_engine(
TEST_DATABASE_URL,
pool_pre_ping=True,
echo=False, # Set to True for SQL debugging
)
# Verify connection on startup
try:
with engine.connect() as conn:
conn.execute(text("SELECT 1"))
except Exception as e:
pytest.exit(
f"\n\nCannot connect to test database at {TEST_DATABASE_URL}\n"
f"Error: {e}\n\n"
"Start the test database with:\n"
" make test-db-up\n\n"
"Or manually:\n"
" docker-compose -f docker-compose.test.yml up -d\n"
)
return engine
@pytest.fixture(scope="session")
def testing_session_local(engine):
"""
Create session factory for tests.
Uses expire_on_commit=False to prevent objects from being expired after
commits. This allows fixtures to remain usable after database operations
without needing to refresh or re-query them.
"""
return sessionmaker(
autocommit=False,
autoflush=False,
bind=engine,
expire_on_commit=False, # Prevents lazy-load issues after commits
)
@pytest.fixture(scope="session", autouse=True)
def setup_database(engine):
"""Create all tables once at the start of the test session."""
with engine.connect() as conn:
# Terminate any other connections to avoid deadlocks
conn.execute(text("""
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = current_database() AND pid <> pg_backend_pid()
"""))
conn.execute(text("DROP SCHEMA public CASCADE"))
conn.execute(text("CREATE SCHEMA public"))
conn.commit()
Base.metadata.create_all(bind=engine)
yield
@pytest.fixture(scope="function")
def db(engine, testing_session_local):
"""
Create a database session for each test function.
Provides test isolation by:
- Using a fresh session for each test
- Truncating all tables after each test (fast cleanup)
Note: Fixtures should NOT use db.expunge() as this detaches objects
from the session and breaks lazy loading. The TRUNCATE provides
sufficient isolation between tests.
"""
db_session = testing_session_local()
try:
yield db_session
finally:
db_session.close()
# Fast cleanup with TRUNCATE CASCADE
with engine.connect() as conn:
# Disable FK checks temporarily for fast truncation
conn.execute(text("SET session_replication_role = 'replica'"))
for table in reversed(Base.metadata.sorted_tables):
conn.execute(text(f'TRUNCATE TABLE "{table.name}" CASCADE'))
conn.execute(text("SET session_replication_role = 'origin'"))
conn.commit()
@pytest.fixture(scope="function")
def client(db):
"""Create a test client with database dependency override"""
# Override the dependency to use our test database
def override_get_db():
try:
yield db
finally:
pass # Don't close here, the db fixture handles it
app.dependency_overrides[get_db] = override_get_db
try:
client = TestClient(app)
yield client
finally:
# Clean up the dependency override
if get_db in app.dependency_overrides:
del app.dependency_overrides[get_db]
# Cleanup fixture to ensure clean state
@pytest.fixture(autouse=True)
def cleanup():
"""Automatically clean up after each test"""
yield
# Clear any remaining dependency overrides
app.dependency_overrides.clear()
# Import fixtures from fixture modules
pytest_plugins = [
"tests.fixtures.admin_platform_fixtures",
"tests.fixtures.auth_fixtures",
"tests.fixtures.loyalty_fixtures",
"tests.fixtures.marketplace_product_fixtures",
"tests.fixtures.store_fixtures",
"tests.fixtures.customer_fixtures",
"tests.fixtures.marketplace_import_job_fixtures",
"tests.fixtures.message_fixtures",
"tests.fixtures.testing_fixtures",
"tests.fixtures.content_page_fixtures",
"tests.fixtures.merchant_domain_fixtures",
]