Skip to content

The up-to-date test misses three kinds of drift: server defaults, CHECK constraints and enum members #37

Description

@AlexeyShalaev

Measured on 0.2.2 against PostgreSQL 17. Six kinds of drift between the migrated schema and the models, each a one-file change to a clean four-revision history, run through test_migrations_up_to_date:

drift_type              (String(100) in the migration, String(255) in the model)   failed   caught
drift_index_missing     (idx_orders_user_id never created)                         failed   caught
drift_extra_column      (a column the model does not have)                         failed   caught
drift_server_default    (server_default false in the migration, true in the model) passed   missed
drift_check_missing     (the amount check never created)                           passed   missed
drift_enum_value        (order_status without 'shipped')                           passed   missed

The three misses are Alembic's, not the test's: compare_metadata skips server defaults unless compare_server_default=True is in the context opts, never compares CHECK constraints, and never compares enum members. The test as written passes opts={"version_table_schema": ...} and nothing else, so a team that trusts "the diff is empty" is trusting it for half of what can drift, and the half it does not cover is the half that shows up as a production incident: a wrong default on insert, a check that is not there, a value the code writes and the type rejects.

Three checks close the gaps, written against the inspector and pg_enum; against the same six variants plus the clean history they catch the three misses and stay green on the clean one:

clean                  3 passed
drift_server_default   1 failed, 2 passed   (test_server_defaults_match)
drift_check_missing    1 failed, 2 passed   (test_check_constraints_match)
drift_enum_value       1 failed, 2 passed   (test_enum_values_match)

What I think it needs: a class attribute, say migration_diff_compare_server_default: ClassVar[bool] = False, that the up-to-date test passes through to compare_metadata (opt-in, because a default expressed two ways is a common false positive; the docs should say which spellings agree); and two new tests on MigrationConsistencyMixin, one comparing the CHECK constraints the metadata declares against get_check_constraints per table (by name, resolved through the metadata's naming convention the way the naming test already resolves rules), one comparing each Enum column's members against pg_enum in order. Both are PostgreSQL-only like the rest of the mixin. The hand-written versions are in the lab as tests/test_drift_extras.py; the enum one is a straight port, the check one needs the convention resolution done properly rather than my ad-hoc prefix guard.

Lab: https://github.com/bedrock-python/bedrock-python.github.io/tree/docs/production-python-series/docs/blog/lab/2026-09-07-five-alembic-migration-tests (migrations/versions/drift_*, tests/test_drift_extras.py, VARIANT=drift_enum_value python -m pytest tests/test_gauntlet.py tests/test_drift_extras.py).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions