mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #23410 -- Avoided unnecessary rollbacks in related apps when migrating backwards.
This commit is contained in:
parent
e7b9a58b08
commit
ab2819aa7b
4 changed files with 114 additions and 11 deletions
|
@ -1,6 +1,7 @@
|
|||
from django.db import connection
|
||||
from django.db.migrations.executor import MigrationExecutor
|
||||
from django.test import modify_settings, override_settings
|
||||
from django.db.migrations.graph import MigrationGraph
|
||||
from django.test import modify_settings, override_settings, TestCase
|
||||
from django.apps.registry import apps as global_apps
|
||||
|
||||
from .test_base import MigrationTestBase
|
||||
|
@ -231,3 +232,96 @@ class ExecutorTests(MigrationTestBase):
|
|||
executor.migrate([("migrations", None)])
|
||||
self.assertTableNotExists("migrations_author")
|
||||
self.assertTableNotExists("migrations_tribble")
|
||||
|
||||
|
||||
class FakeLoader(object):
|
||||
def __init__(self, graph, applied):
|
||||
self.graph = graph
|
||||
self.applied_migrations = applied
|
||||
|
||||
|
||||
class FakeMigration(object):
|
||||
"""Really all we need is any object with a debug-useful repr."""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
def __repr__(self):
|
||||
return 'M<%s>' % self.name
|
||||
|
||||
|
||||
class ExecutorUnitTests(TestCase):
|
||||
"""(More) isolated unit tests for executor methods."""
|
||||
def test_minimize_rollbacks(self):
|
||||
"""
|
||||
Minimize unnecessary rollbacks in connected apps.
|
||||
|
||||
When you say "./manage.py migrate appA 0001", rather than migrating to
|
||||
just after appA-0001 in the linearized migration plan (which could roll
|
||||
back migrations in other apps that depend on appA 0001, but don't need
|
||||
to be rolled back since we're not rolling back appA 0001), we migrate
|
||||
to just before appA-0002.
|
||||
"""
|
||||
a1_impl = FakeMigration('a1')
|
||||
a1 = ('a', '1')
|
||||
a2_impl = FakeMigration('a2')
|
||||
a2 = ('a', '2')
|
||||
b1_impl = FakeMigration('b1')
|
||||
b1 = ('b', '1')
|
||||
graph = MigrationGraph()
|
||||
graph.add_node(a1, a1_impl)
|
||||
graph.add_node(a2, a2_impl)
|
||||
graph.add_node(b1, b1_impl)
|
||||
graph.add_dependency(None, b1, a1)
|
||||
graph.add_dependency(None, a2, a1)
|
||||
|
||||
executor = MigrationExecutor(None)
|
||||
executor.loader = FakeLoader(graph, {a1, b1, a2})
|
||||
|
||||
plan = executor.migration_plan({a1})
|
||||
|
||||
self.assertEqual(plan, [(a2_impl, True)])
|
||||
|
||||
def test_minimize_rollbacks_branchy(self):
|
||||
"""
|
||||
Minimize rollbacks when target has multiple in-app children.
|
||||
|
||||
a: 1 <---- 3 <--\
|
||||
\ \- 2 <--- 4
|
||||
\ \
|
||||
b: \- 1 <--- 2
|
||||
"""
|
||||
a1_impl = FakeMigration('a1')
|
||||
a1 = ('a', '1')
|
||||
a2_impl = FakeMigration('a2')
|
||||
a2 = ('a', '2')
|
||||
a3_impl = FakeMigration('a3')
|
||||
a3 = ('a', '3')
|
||||
a4_impl = FakeMigration('a4')
|
||||
a4 = ('a', '4')
|
||||
b1_impl = FakeMigration('b1')
|
||||
b1 = ('b', '1')
|
||||
b2_impl = FakeMigration('b2')
|
||||
b2 = ('b', '2')
|
||||
graph = MigrationGraph()
|
||||
graph.add_node(a1, a1_impl)
|
||||
graph.add_node(a2, a2_impl)
|
||||
graph.add_node(a3, a3_impl)
|
||||
graph.add_node(a4, a4_impl)
|
||||
graph.add_node(b1, b1_impl)
|
||||
graph.add_node(b2, b2_impl)
|
||||
graph.add_dependency(None, a2, a1)
|
||||
graph.add_dependency(None, a3, a1)
|
||||
graph.add_dependency(None, a4, a2)
|
||||
graph.add_dependency(None, a4, a3)
|
||||
graph.add_dependency(None, b2, b1)
|
||||
graph.add_dependency(None, b1, a1)
|
||||
graph.add_dependency(None, b2, a2)
|
||||
|
||||
executor = MigrationExecutor(None)
|
||||
executor.loader = FakeLoader(graph, {a1, b1, a2, b2, a3, a4})
|
||||
|
||||
plan = executor.migration_plan({a1})
|
||||
|
||||
should_be_rolled_back = [b2_impl, a4_impl, a2_impl, a3_impl]
|
||||
exp = [(m, True) for m in should_be_rolled_back]
|
||||
self.assertEqual(plan, exp)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue