Files
FabledSteward/tests/integration/test_boot.py
T
bvandeusen d925709c77
CI / lint (push) Failing after 2s
CI / unit (push) Successful in 7s
CI / integration (push) Successful in 2m8s
ci: add Forgejo CI (lint + unit + Postgres integration) + ci-requirements.md
Single-repo CI now that plugins are bundled in-tree. Three lanes on push to
dev/main, modeled on FabledCurator's canonical ci.yml (minus frontend/Redis):
- lint: ruff check steward/ plugins/ tests/ (no dep install)
- unit: pytest -m 'not integration' — whole current suite (testing=True mocks DB)
- integration: postgres:16-alpine service via socket-discovered bridge IP; a
  boot-and-migrate test creates the real app, running core + all bundled-plugin
  migrations, then round-trips the DB — guards the folded-in migration graph.

Registers the 'integration' pytest marker; adds tests/integration/test_boot.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:37:32 -04:00

43 lines
1.4 KiB
Python

"""Integration: boot the real app against a live Postgres.
Creating the app with testing=False runs the core Alembic migrations AND every
bundled plugin's migrations (discovered across all plugin roots). This is the
canonical guard that the folded-in plugin migration graph resolves end-to-end —
a pure-unit test can't catch a broken plugin revision chain.
Requires STEWARD_DATABASE_URL pointing at a live Postgres; the integration CI
lane provides it. Skipped automatically when unset so the unit lane stays green.
"""
from __future__ import annotations
import asyncio
import os
import pytest
pytestmark = pytest.mark.integration
@pytest.mark.skipif(
not os.environ.get("STEWARD_DATABASE_URL"),
reason="integration test needs a live Postgres (STEWARD_DATABASE_URL)",
)
def test_real_boot_runs_all_migrations():
from sqlalchemy import text
from steward.app import create_app
# testing=False → init_db + run_core_migrations (core + all bundled-plugin
# migrations) + load_settings_sync + load_plugins all execute here.
app = create_app(testing=False)
assert app is not None
async def _roundtrip():
async with app.db_sessionmaker() as session:
# app_settings exists only if core migrations actually applied.
result = await session.execute(text("SELECT COUNT(*) FROM app_settings"))
return result.scalar()
count = asyncio.run(_roundtrip())
assert count is not None