2013-10-02 16:33:41 +00:00
|
|
|
# encoding: utf8
|
|
|
|
import operator
|
|
|
|
from django.test import TestCase
|
|
|
|
from django.db.migrations.optimizer import MigrationOptimizer
|
|
|
|
from django.db import migrations
|
|
|
|
from django.db import models
|
|
|
|
|
|
|
|
|
|
|
|
class OptimizerTests(TestCase):
|
|
|
|
"""
|
|
|
|
Tests the migration autodetector.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def optimize(self, operations):
|
|
|
|
"""
|
|
|
|
Handy shortcut for getting results + number of loops
|
|
|
|
"""
|
|
|
|
optimizer = MigrationOptimizer()
|
|
|
|
return optimizer.optimize(operations), optimizer._iterations
|
|
|
|
|
|
|
|
def assertOptimizesTo(self, operations, expected, exact=None, less_than=None):
|
|
|
|
result, iterations = self.optimize(operations)
|
|
|
|
self.assertEqual(expected, result)
|
|
|
|
if exact is not None and iterations != exact:
|
|
|
|
raise self.failureException("Optimization did not take exactly %s iterations (it took %s)" % (exact, iterations))
|
|
|
|
if less_than is not None and iterations >= less_than:
|
|
|
|
raise self.failureException("Optimization did not take less than %s iterations (it took %s)" % (less_than, iterations))
|
|
|
|
|
|
|
|
def test_operation_equality(self):
|
|
|
|
"""
|
|
|
|
Tests the equality operator on lists of operations.
|
|
|
|
If this is broken, then the optimizer will get stuck in an
|
|
|
|
infinite loop, so it's kind of important.
|
|
|
|
"""
|
|
|
|
self.assertEqual(
|
|
|
|
[migrations.DeleteModel("Test")],
|
|
|
|
[migrations.DeleteModel("Test")],
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
[migrations.CreateModel("Test", [("name", models.CharField(max_length=255))])],
|
|
|
|
[migrations.CreateModel("Test", [("name", models.CharField(max_length=255))])],
|
|
|
|
)
|
|
|
|
self.assertNotEqual(
|
|
|
|
[migrations.CreateModel("Test", [("name", models.CharField(max_length=255))])],
|
|
|
|
[migrations.CreateModel("Test", [("name", models.CharField(max_length=100))])],
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
[migrations.AddField("Test", "name", models.CharField(max_length=255))],
|
|
|
|
[migrations.AddField("Test", "name", models.CharField(max_length=255))],
|
|
|
|
)
|
|
|
|
self.assertNotEqual(
|
|
|
|
[migrations.AddField("Test", "name", models.CharField(max_length=255))],
|
|
|
|
[migrations.AddField("Test", "name", models.CharField(max_length=100))],
|
|
|
|
)
|
|
|
|
self.assertNotEqual(
|
|
|
|
[migrations.AddField("Test", "name", models.CharField(max_length=255))],
|
|
|
|
[migrations.AlterField("Test", "name", models.CharField(max_length=255))],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_single(self):
|
|
|
|
"""
|
|
|
|
Tests that the optimizer does nothing on a single operation,
|
|
|
|
and that it does it in just one pass.
|
|
|
|
"""
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[migrations.DeleteModel("Foo")],
|
|
|
|
[migrations.DeleteModel("Foo")],
|
|
|
|
exact = 1,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_create_delete_model(self):
|
|
|
|
"""
|
|
|
|
CreateModel and DeleteModel should collapse into nothing.
|
|
|
|
"""
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_create_alter_delete_model(self):
|
|
|
|
"""
|
|
|
|
CreateModel, AlterModelTable, AlterUniqueTogether, and DeleteModel should collapse into nothing.
|
|
|
|
"""
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.AlterModelTable("Foo", "woohoo"),
|
|
|
|
migrations.AlterUniqueTogether("Foo", [["a", "b"]]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[],
|
|
|
|
)
|
2013-10-16 10:09:33 +00:00
|
|
|
|
|
|
|
def test_optimize_through_create(self):
|
|
|
|
"""
|
|
|
|
We should be able to optimize away create/delete through a create or delete
|
|
|
|
of a different model, but only if the create operation does not mention the model
|
|
|
|
at all.
|
|
|
|
"""
|
|
|
|
# These should work
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())]),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())]),
|
|
|
|
migrations.DeleteModel("Bar"),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[],
|
|
|
|
)
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
migrations.DeleteModel("Bar"),
|
|
|
|
],
|
|
|
|
[],
|
|
|
|
)
|
|
|
|
# This should not work - FK should block it
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo"))]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("other", models.ForeignKey("testapp.Foo"))]),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
# This should not work - bases should block it
|
|
|
|
self.assertOptimizesTo(
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
migrations.CreateModel("Foo", [("name", models.CharField(max_length=255))]),
|
|
|
|
migrations.CreateModel("Bar", [("size", models.IntegerField())], bases=("testapp.Foo", )),
|
|
|
|
migrations.DeleteModel("Foo"),
|
|
|
|
],
|
|
|
|
)
|