Manual Migration TestingΒΆ
This guide describes how to manually test Alembic database migrations against PostgreSQL using Docker containers.
π What Are Database Migrations?ΒΆ
Database migrations are versioned, incremental changes to a database schema β adding columns, creating tables, renaming fields, or adjusting constraints. ContextForge uses Alembic to manage migrations, which tracks every schema change as a numbered revision file under mcpgateway/alembic/versions/.
When the gateway starts, Alembic compares the current database state against the revision history and automatically applies any pending migrations in order.
Why Do Migrations Need to Be Tested Manually?ΒΆ
Automated unit tests run against SQLite, which is permissive and forgiving about types, constraints, and syntax. Production deployments, however, commonly use PostgreSQL β which has stricter type enforcement, different default behaviours, and subtle SQL dialect differences.
A migration that works perfectly on SQLite can fail silently or raise errors on PostgreSQL. Manual testing catches:
- Type incompatibilities β e.g.
BOOLEANvsTINYINT(1),TEXTlength limits - Constraint differences β nullable defaults, foreign key enforcement
- SQL dialect issues β syntax accepted by one engine but rejected by another
- Migration ordering bugs β a revision that assumes a column exists before it is created
- Idempotency failures β a migration that errors when run twice on an existing schema
Testing migrations manually before merging ensures that upgrades work reliably across all supported databases.
π§© PrerequisitesΒΆ
- Docker
- DBeaver (or any SQL client)
- A working
.envfile
π³ Start Database ContainersΒΆ
Start the PostgreSQL container:
PostgreSQLΒΆ
docker run -d \
--name mcp-postgres \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=mysecretpassword \
-p 5432:5432 \
postgres:17
ποΈ Inspect the Database in DBeaverΒΆ
- Open DBeaver and create a new connection to the running container using the credentials above.
- Verify the
mcpdatabase exists. If for any reason it was not created automatically, create it manually:
βοΈ Configure the GatewayΒΆ
Update DATABASE_URL in your .env to point to the PostgreSQL database:
π Start the GatewayΒΆ
Start the gateway. On first run it will apply all Alembic migrations and populate the tables:
β Verify Migration StatusΒΆ
Check that all migrations were applied successfully:
You should see all revisions listed as applied with no pending migrations.
You can also inspect the tables directly in DBeaver to confirm the schema matches the expected structure.
π± Populate the Database (Optional)ΒΆ
Once the gateway is running you can seed it with test data using the populate scripts.
make populate-small defaults to port 8080. When running make dev (port 8000), override the target URL with --base-url or the MCPGATEWAY_BASE_URL environment variable:
# Pass the URL directly
source .venv/bin/activate
export MCPGATEWAY_BEARER_TOKEN="your_token"
python -m tests.populate --profile small --base-url http://localhost:8000
Check if the values your migration affects are populated in the DB.
π§Ή CleanupΒΆ
Stop and remove the container when done:
π Testing Migrations Against Existing Data (Upgrade Simulation)ΒΆ
The most realistic migration test is to verify that a new migration applies cleanly to a database that already contains data β exactly as it would in a production upgrade.
Step-by-stepΒΆ
1. Start with a clean database on main
Ensure the Docker container is running and the database is empty (or drop and recreate it):
# Drop and recreate the mcp database to start fresh
docker exec -it mcp-postgres psql -U postgres -c "DROP DATABASE IF EXISTS mcp; CREATE DATABASE mcp;"
2. Checkout main and start the gateway
The gateway will apply all current migrations and create the schema.
3. Populate the database with test data
This seeds the database with realistic data that the migration must handle without data loss or errors.
4. Stop the gateway
5. Checkout the branch containing the new migration
6. Apply the pending migration
This runs alembic upgrade head, applying only the new revision(s) on top of the existing populated schema.
7. Verify the migration succeeded
All revisions should show as applied. Inspect the affected tables in DBeaver to confirm the schema change is correct and existing data is intact.