Skip to content

Commit

Permalink
rename Migrator before and after methods (#83)
Browse files Browse the repository at this point in the history
Rename ``Migrator`` methods:

+ ``before`` to ``apply_initial_migration``
+ ``after`` to ``apply_tested_migration``
  • Loading branch information
skarzi authored May 17, 2020
1 parent a7aeb32 commit 066a323
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 42 deletions.
33 changes: 19 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,13 @@ To test all migrations we have a [`Migrator`](https://github.com/wemake-services

It has three methods to work with:

- `.before()` which takes app and migration names to generate a state
before the actual migration happens.
It creates the `before state` by applying all migrations up to and including
the one passed as an argument.
- `.apply_initial_migration()` which takes app and migration names to generate
a state before the actual migration happens. It creates the `before state`
by applying all migrations up to and including the ones passed as an argument.

- `.apply_tested_migration()` which takes app and migration names to perform the
actual migration

- `.after()` which takes app and migration names to perform the actual migration
- `.reset()` to clean everything up after we are done with testing

So, here's an example:
Expand All @@ -71,19 +72,21 @@ migrator = Migrator(database='default')
# Initial migration, currently our model has only a single string field:
# Note:
# We are testing migration `0002_someitem_is_clean`, so we are specifying
# the name of the previous migration (`0001_initial`) in the .before()
# method in order to prepare a state of the database before applying
# the migration we are going to test.
# the name of the previous migration (`0001_initial`) in the
# .apply_initial_migration() method in order to prepare a state of the database
# before applying the migration we are going to test.
#
old_state = migrator.before(('main_app', '0001_initial'))
old_state = migrator.apply_initial_migration(('main_app', '0001_initial'))
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')

# Let's create a model with just a single field specified:
SomeItem.objects.create(string_field='a')
assert len(SomeItem._meta.get_fields()) == 2 # id + string_field

# Now this migration will add `is_clean` field to the model:
new_state = migrator.after(('main_app', '0002_someitem_is_clean'))
new_state = migrator.apply_tested_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

# We can now test how our migration worked, new field is there:
Expand All @@ -105,14 +108,16 @@ Nothing really changes except migration names that you pass and your logic:
migrator = Migrator()

# Currently our model has two field, but we need a rollback:
old_state = migrator.before(('main_app', '0002_someitem_is_clean'))
old_state = migrator.apply_initial_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')

# Create some data to illustrate your cases:
# ...

# Now this migration will drop `is_clean` field:
new_state = migrator.after(('main_app', '0001_initial'))
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))

# Assert the results:
# ...
Expand Down Expand Up @@ -170,13 +175,13 @@ import pytest
@pytest.mark.django_db
def test_pytest_plugin_initial(migrator):
"""Ensures that the initial migration works."""
old_state = migrator.before(('main_app', None))
old_state = migrator.apply_initial_migration(('main_app', None))

with pytest.raises(LookupError):
# Models does not yet exist:
old_state.apps.get_model('main_app', 'SomeItem')

new_state = migrator.after(('main_app', '0001_initial'))
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))
# After the initial migration is done, we can use the model state:
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')
assert SomeItem.objects.filter(string_field='').count() == 0
Expand Down
12 changes: 8 additions & 4 deletions django_test_migrations/contrib/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ def migrator_factory(request, transactional_db, django_db_use_migrations):
@pytest.mark.django_db
def test_migration(migrator_factory):
migrator = migrator_factory('custom_db_alias')
old_state = migrator.before(('main_app', None))
new_state = migrator.after(('main_app', '0001_initial'))
old_state = migrator.apply_initial_migration(('main_app', None))
new_state = migrator.apply_tested_migration(
('main_app', '0001_initial'),
)
assert isinstance(old_state, ProjectState)
assert isinstance(new_state, ProjectState)
Expand Down Expand Up @@ -55,8 +57,10 @@ def migrator(migrator_factory): # noqa: WPS442
@pytest.mark.django_db
def test_migration(migrator):
old_state = migrator.before(('main_app', None))
new_state = migrator.after(('main_app', '0001_initial'))
old_state = migrator.apply_initial_migration(('main_app', None))
new_state = migrator.apply_tested_migration(
('main_app', '0001_initial'),
)
assert isinstance(old_state, ProjectState)
assert isinstance(new_state, ProjectState)
Expand Down
6 changes: 4 additions & 2 deletions django_test_migrations/contrib/unittest_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ def setUp(self) -> None:
"""
super().setUp()
self._migrator = Migrator(self.database_name)
self.old_state = self._migrator.before(self.migrate_from)
self.old_state = self._migrator.apply_initial_migration(
self.migrate_from,
)
self.prepare()
self.new_state = self._migrator.after(self.migrate_to)
self.new_state = self._migrator.apply_tested_migration(self.migrate_to)

def prepare(self) -> None:
"""
Expand Down
12 changes: 6 additions & 6 deletions django_test_migrations/migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ def __init__(
self._database: str = database
self._executor = MigrationExecutor(connections[self._database])

def before(self, migrate_from: MigrationSpec) -> ProjectState:
def apply_initial_migration(self, targets: MigrationSpec) -> ProjectState:
"""Reverse back to the original migration."""
migrate_from = normalize(migrate_from)
targets = normalize(targets)

style = no_style()
# start from clean database state
Expand All @@ -77,17 +77,17 @@ def before(self, migrate_from: MigrationSpec) -> ProjectState:
self._executor.loader.graph.leaf_nodes(),
clean_start=True,
)
plan = truncate_plan(migrate_from, full_plan)
plan = truncate_plan(targets, full_plan)

# apply all migrations from generated plan on clean database
# (only forward, so any unexpected migration won't be applied)
# to restore database state before tested migration
return self._migrate(migrate_from, plan=plan)
return self._migrate(targets, plan=plan)

def after(self, migrate_to: MigrationSpec) -> ProjectState:
def apply_tested_migration(self, targets: MigrationSpec) -> ProjectState:
"""Apply the next migration."""
self._executor.loader.build_graph() # reload
return self._migrate(normalize(migrate_to))
return self._migrate(normalize(targets))

def reset(self) -> None:
"""Reset the state to the most recent one."""
Expand Down
26 changes: 18 additions & 8 deletions tests/test_contrib/test_pytest_plugin/test_pytest_plugin_direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
@pytest.mark.django_db
def test_pytest_plugin_initial(migrator):
"""Ensures that the initial migration works."""
old_state = migrator.before(('main_app', None))
old_state = migrator.apply_initial_migration(('main_app', None))

with pytest.raises(LookupError):
# Models does not yet exist:
old_state.apps.get_model('main_app', 'SomeItem')

new_state = migrator.after(('main_app', '0001_initial'))
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))
# After the initial migration is done, we can use the model state:
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')
assert SomeItem.objects.filter(string_field='').count() == 0
Expand All @@ -27,13 +27,15 @@ def test_pytest_plugin_initial(migrator):
@pytest.mark.django_db
def test_pytest_plugin0001(migrator):
"""Ensures that the first migration works."""
old_state = migrator.before(('main_app', '0001_initial'))
old_state = migrator.apply_initial_migration(('main_app', '0001_initial'))
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')

with pytest.raises(FieldError):
SomeItem.objects.filter(is_clean=True)

new_state = migrator.after(('main_app', '0002_someitem_is_clean'))
new_state = migrator.apply_tested_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

assert SomeItem.objects.filter(is_clean=True).count() == 0
Expand All @@ -42,15 +44,19 @@ def test_pytest_plugin0001(migrator):
@pytest.mark.django_db
def test_pytest_plugin0002(migrator):
"""Ensures that the second migration works."""
old_state = migrator.before(('main_app', '0002_someitem_is_clean'))
old_state = migrator.apply_initial_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
SomeItem.objects.create(string_field='a')
SomeItem.objects.create(string_field='a b')

assert SomeItem.objects.count() == 2
assert SomeItem.objects.filter(is_clean=True).count() == 2

new_state = migrator.after(('main_app', '0003_update_is_clean'))
new_state = migrator.apply_tested_migration(
('main_app', '0003_update_is_clean'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

assert SomeItem.objects.count() == 2
Expand All @@ -60,14 +66,18 @@ def test_pytest_plugin0002(migrator):
@pytest.mark.django_db
def test_pytest_plugin0003(migrator):
"""Ensures that the third migration works."""
old_state = migrator.before(('main_app', '0003_update_is_clean'))
old_state = migrator.apply_initial_migration(
('main_app', '0003_update_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
SomeItem.objects.create(string_field='a') # default is still there

assert SomeItem.objects.count() == 1
assert SomeItem.objects.filter(is_clean=True).count() == 1

new_state = migrator.after(('main_app', '0004_auto_20191119_2125'))
new_state = migrator.apply_tested_migration(
('main_app', '0004_auto_20191119_2125'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

with pytest.raises(IntegrityError):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
@pytest.mark.django_db
def test_pytest_plugin0001(migrator):
"""Ensures that the first migration works."""
old_state = migrator.before(('main_app', '0002_someitem_is_clean'))
old_state = migrator.apply_initial_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')

assert SomeItem.objects.filter(is_clean=True).count() == 0

new_state = migrator.after(('main_app', '0001_initial'))
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

with pytest.raises(FieldError):
Expand All @@ -27,15 +29,19 @@ def test_pytest_plugin0001(migrator):
@pytest.mark.django_db
def test_pytest_plugin0002(migrator):
"""Ensures that the second migration works."""
old_state = migrator.before(('main_app', '0003_update_is_clean'))
old_state = migrator.apply_initial_migration(
('main_app', '0003_update_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
SomeItem.objects.create(string_field='a', is_clean=True)
SomeItem.objects.create(string_field='a b', is_clean=False)

assert SomeItem.objects.count() == 2
assert SomeItem.objects.filter(is_clean=True).count() == 1

new_state = migrator.after(('main_app', '0002_someitem_is_clean'))
new_state = migrator.apply_tested_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')

assert SomeItem.objects.count() == 2
Expand Down
8 changes: 4 additions & 4 deletions tests/test_migrator/test_migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
def test_migrator(transactional_db):
"""We only need this test for coverage."""
migrator = Migrator()
old_state = migrator.before(('main_app', None))
new_state = migrator.after(('main_app', '0001_initial'))
old_state = migrator.apply_initial_migration(('main_app', None))
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))

assert isinstance(old_state, ProjectState)
assert isinstance(new_state, ProjectState)
Expand All @@ -20,8 +20,8 @@ def test_migrator(transactional_db):
def test_migrator_list(transactional_db):
"""We only need this test for coverage."""
migrator = Migrator()
old_state = migrator.before([('main_app', None)])
new_state = migrator.after([('main_app', '0001_initial')])
old_state = migrator.apply_initial_migration([('main_app', None)])
new_state = migrator.apply_tested_migration([('main_app', '0001_initial')])

assert isinstance(old_state, ProjectState)
assert isinstance(new_state, ProjectState)
Expand Down

0 comments on commit 066a323

Please sign in to comment.