Raxx · internal docs

internal · gated ↑ index

Testing Raptor (backend_v2)

Two-dialect test strategy

Raptor's test suite runs against two database dialects:

Mode Dialect When How to invoke
SQLite (default) sqlite Local dev — fast, no Postgres required pytest backend_v2/tests
Postgres postgresql CI gate + optional local validation DATABASE_URL=... pytest backend_v2/tests

Both modes share the same test code. The db_engine and db_session fixtures in backend_v2/conftest.py detect the dialect from DATABASE_URL and adapt automatically. Individual tests do not need any dialect-specific code.

ADR reference: docs/architecture/adr/0070-pytest-postgresql-over-testcontainers.md


SQLite mode (default)

No environment variables needed. Run from the repo root:

python -m pytest backend_v2/tests -q

An ephemeral SQLite file is created under pytest's tmp_path per session. The Alembic baseline migration (0001_raptor_baseline.py) is applied automatically so the schema matches the Postgres-typed DDL. The DB is discarded after the session.


Postgres mode (CI gate)

Prerequisites

macOS (developer machine):

brew install postgresql@15
brew services start postgresql@15
# The installer adds pg_ctl to PATH automatically; verify:
pg_ctl --version

Create the test database:

createdb raptor_test

Ubuntu / Debian (CI or Linux dev machine):

sudo apt-get update && sudo apt-get install -y postgresql postgresql-client
sudo -u postgres createuser --superuser "$USER"
createdb raptor_test

Run against Postgres

DATABASE_URL=postgresql://localhost/raptor_test \
  python -m pytest backend_v2/tests -q

Or use the --postgres pytest flag (spawns an ephemeral pg_ctl process via pytest-postgresql; does not require a running Postgres service):

python -m pytest backend_v2/tests -q --postgres

The --postgres flag is useful for quick one-off validation on a machine that has pg_ctl on PATH but no persistent Postgres instance running. In CI the services: postgres: container approach is used instead (lower latency).

When to run Postgres mode locally


Fixtures

db_engine (session-scoped)

A SQLAlchemy Engine connected to the test database. The Alembic baseline migration is applied once at session startup. Use this when you need direct engine access (reflection, DDL inspection, bulk operations).

def test_table_exists(db_engine):
    from sqlalchemy import inspect
    assert "symbols" in inspect(db_engine).get_table_names()

db_session (function-scoped)

A SQLAlchemy Session that rolls back after each test. Use this for all DML — rows inserted in one test are never visible in the next.

def test_insert_visible_in_session(db_session):
    from sqlalchemy import text
    db_session.execute(text("INSERT INTO symbols (symbol, ...) VALUES (...)"))
    db_session.flush()
    result = db_session.execute(text("SELECT symbol FROM symbols")).fetchall()
    assert len(result) == 1

Legacy fixtures

Tests that predate RM-8 (test_engine.py, test_baseline_migration.py) use their own in-module fixtures and do not depend on db_engine / db_session. This is intentional — the RM-8 fixtures are opt-in for new tests.


CI jobs

Job Dialect Trigger
backend-tests SQLite Every PR + push to main where code == true
backend-tests-postgres Postgres 15 Every PR + push to main where code == true

Both jobs are non-optional. A PR cannot merge if either job fails.

The Postgres CI job uses a services: postgres:15 container and sets DATABASE_URL=postgresql://raptor:raptor_test@localhost:5432/raptor_test. alembic upgrade head is run as a pre-test step so the schema is applied before pytest collects tests.


pyproject.toml / pytest.ini

Pytest is configured via pyproject.toml at the repo root. The --postgres flag is registered in backend_v2/conftest.py via pytest_addoption.


Common failures

Symptom Likely cause Fix
alembic upgrade head fails in conftest 0001_raptor_baseline.py has a syntax error for the active dialect Run alembic upgrade head manually with DATABASE_URL set and inspect the error
pytest_postgresql not installed requirements.txt not installed in current venv pip install -r backend_v2/requirements.txt
pg_ctl: command not found when using --postgres Postgres not installed locally brew install postgresql@15 (macOS) or apt-get install postgresql
Postgres CI job fails but SQLite passes Dialect-specific SQL (e.g. ? placeholder, SQLite-only pragma) Replace with SQLAlchemy parameterised form