Skip to content

Commit

Permalink
feat: Add new test for roundtrip downgrade isolation.
Browse files Browse the repository at this point in the history
  • Loading branch information
DanCardin committed Nov 24, 2021
1 parent ea9b59d commit 2fb20d0
Show file tree
Hide file tree
Showing 17 changed files with 302 additions and 0 deletions.
36 changes: 36 additions & 0 deletions examples/test_downgrade_leaves_no_trace_failure/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[alembic]
script_location = migrations

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
3 changes: 3 additions & 0 deletions examples/test_downgrade_leaves_no_trace_failure/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from pytest_mock_resources import create_postgres_fixture

alembic_engine = create_postgres_fixture()
25 changes: 25 additions & 0 deletions examples/test_downgrade_leaves_no_trace_failure/migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from logging.config import fileConfig

from alembic import context
from sqlalchemy import engine_from_config, pool

from models import Base

fileConfig(context.config.config_file_name)
target_metadata = Base.metadata


connectable = context.config.attributes.get("connection", None)

if connectable is None:
connectable = engine_from_config(
context.config.get_section(context.config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from alembic import op
import sqlalchemy as sa

revision = "aaaaaaaaaaaa"
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
"foo",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint("id"),
)


def downgrade():
op.rename_table('foo', 'bar')
11 changes: 11 additions & 0 deletions examples/test_downgrade_leaves_no_trace_failure/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sqlalchemy
from sqlalchemy import Column, types
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class CreatedAt(Base):
__tablename__ = "foo"

id = Column(types.Integer(), autoincrement=True, primary_key=True)
2 changes: 2 additions & 0 deletions examples/test_downgrade_leaves_no_trace_failure/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tool:pytest]
pytest_alembic_include_experimental = downgrade_leaves_no_trace
36 changes: 36 additions & 0 deletions examples/test_downgrade_leaves_no_trace_success/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[alembic]
script_location = migrations

[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
3 changes: 3 additions & 0 deletions examples/test_downgrade_leaves_no_trace_success/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from pytest_mock_resources import create_postgres_fixture

alembic_engine = create_postgres_fixture()
25 changes: 25 additions & 0 deletions examples/test_downgrade_leaves_no_trace_success/migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from logging.config import fileConfig

from alembic import context
from sqlalchemy import engine_from_config, pool

from models import Base

fileConfig(context.config.config_file_name)
target_metadata = Base.metadata


connectable = context.config.attributes.get("connection", None)

if connectable is None:
connectable = engine_from_config(
context.config.get_section(context.config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)

with context.begin_transaction():
context.run_migrations()
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from alembic import op
import sqlalchemy as sa

revision = "aaaaaaaaaaaa"
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
"foo",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.PrimaryKeyConstraint("id"),
)


def downgrade():
op.drop_table('foo')
11 changes: 11 additions & 0 deletions examples/test_downgrade_leaves_no_trace_success/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import sqlalchemy
from sqlalchemy import Column, types
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class CreatedAt(Base):
__tablename__ = "foo"

id = Column(types.Integer(), autoincrement=True, primary_key=True)
2 changes: 2 additions & 0 deletions examples/test_downgrade_leaves_no_trace_success/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tool:pytest]
pytest_alembic_include_experimental = downgrade_leaves_no_trace
3 changes: 3 additions & 0 deletions src/pytest_alembic/tests/experimental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
from pytest_alembic.tests.experimental.all_models_register_on_metadata import (
test_all_models_register_on_metadata,
)
from pytest_alembic.tests.experimental.downgrade_leaves_no_trace import (
test_downgrade_leaves_no_trace,
)
41 changes: 41 additions & 0 deletions src/pytest_alembic/tests/experimental/downgrade_leaves_no_trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import List, Optional, Set, Tuple

from sqlalchemy import MetaData

from pytest_alembic.plugin.error import AlembicTestFailure
from pytest_alembic.runner import MigrationContext

try:
from sqlalchemy.ext.declarative import DeclarativeMeta
except ImportError: # pragma: no cover
from sqlalchemy.declarative import DeclarativeMeta


def test_downgrade_leaves_no_trace(alembic_runner: MigrationContext, alembic_engine):
"""Assert that all tables defined on your `MetaData`, are imported in the `env.py`.
"""
original_metadata = MetaData()
original_metadata.reflect(alembic_engine)

alembic_runner.migrate_up_one()

upgrade_metadata = MetaData()
upgrade_metadata.reflect(alembic_engine)

alembic_runner.migrate_down_one()

downgrade_metadata = MetaData()
downgrade_metadata.reflect(alembic_engine)

# old_tables = {k: v for k, v in old_metadata.tables.items()}
# new_tables = {k: v for k, v in new_metadata.tables.items() if k != 'alembic_version'}

import pdb; pdb.set_trace()
if new_tables:
tables = ', '.join(new_tables.keys())
raise AlembicTestFailure(
f"{new_tables}"
)

raise
18 changes: 18 additions & 0 deletions tests/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,21 @@ def test_consistency_doesnt_roundtrip(pytester):
assert_failed_test_has_content(
result, test="test_up_down_consistency", content="after performing a roundtrip"
)

def test_downgrade_leaves_no_trace_success(pytester):
"""Assert the all-models-register test is collected when included through automatic test insertion.
I.e. through use of pytest_alembic_include_experimental, rather than a manually
written test.
"""
result = run_pytest(pytester, passed=5)
assert_has_test(result, "test_downgrade_leaves_no_trace")


def test_downgrade_leaves_no_trace_failure(pytester):
"""Assert the all-models-register test is collected when included through automatic test insertion.
"""
result = run_pytest(pytester, success=False, passed=0, failed=1, test_alembic=False)
assert_failed_test_has_content(
result, test="test_downgrade_leaves_no_trace", content="after performing a roundtrip"
)

0 comments on commit 2fb20d0

Please sign in to comment.