diff options
| author | Pankrat <lhaehne@gmail.com> | 2016-01-30 21:46:28 +0100 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-02-05 09:09:05 -0500 |
| commit | f91a04621ea8d7a657ff755645d823026257e898 (patch) | |
| tree | 2b06f3ce1cbb8e5f04499838154cf715ff76ce5b /tests | |
| parent | 0edb8a146fd6c60f4c3b1ad0a4a89963962f22af (diff) | |
Fixed #25833 -- Added support for non-atomic migrations.
Added the Migration.atomic attribute which can be set to False
for non-atomic migrations.
Diffstat (limited to 'tests')
6 files changed, 97 insertions, 0 deletions
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py index 4eb96de2e9..68fa658d76 100644 --- a/tests/migrations/test_commands.py +++ b/tests/migrations/test_commands.py @@ -362,6 +362,19 @@ class MigrateTests(MigrationTestBase): # Cleanup by unmigrating everything call_command("migrate", "migrations", "zero", verbosity=0) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"}) + def test_sqlmigrate_for_non_atomic_migration(self): + """ + Transaction wrappers aren't shown for non-atomic migrations. + """ + out = six.StringIO() + call_command("sqlmigrate", "migrations", "0001", stdout=out) + output = out.getvalue().lower() + queries = [q.strip() for q in output.splitlines()] + if connection.ops.start_transaction_sql(): + self.assertNotIn(connection.ops.start_transaction_sql().lower(), queries) + self.assertNotIn(connection.ops.end_transaction_sql().lower(), queries) + @override_settings( INSTALLED_APPS=[ "migrations.migrations_test_apps.migrated_app", diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py index 1bbed48e3c..b51e7be90e 100644 --- a/tests/migrations/test_executor.py +++ b/tests/migrations/test_executor.py @@ -100,6 +100,33 @@ class ExecutorTests(MigrationTestBase): self.assertTableNotExists("migrations_author") self.assertTableNotExists("migrations_book") + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_non_atomic"}) + def test_non_atomic_migration(self): + """ + Applying a non-atomic migration works as expected. + """ + executor = MigrationExecutor(connection) + with self.assertRaisesMessage(RuntimeError, "Abort migration"): + executor.migrate([("migrations", "0001_initial")]) + self.assertTableExists("migrations_publisher") + migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps + Publisher = migrations_apps.get_model("migrations", "Publisher") + self.assertTrue(Publisher.objects.exists()) + self.assertTableNotExists("migrations_book") + + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_atomic_operation"}) + def test_atomic_operation_in_non_atomic_migration(self): + """ + An atomic operation is properly rolled back inside a non-atomic + migration. + """ + executor = MigrationExecutor(connection) + with self.assertRaisesMessage(RuntimeError, "Abort migration"): + executor.migrate([("migrations", "0001_initial")]) + migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps + Editor = migrations_apps.get_model("migrations", "Editor") + self.assertFalse(Editor.objects.exists()) + @override_settings(MIGRATION_MODULES={ "migrations": "migrations.test_migrations", "migrations2": "migrations2.test_migrations_2", diff --git a/tests/migrations/test_migrations_atomic_operation/0001_initial.py b/tests/migrations/test_migrations_atomic_operation/0001_initial.py new file mode 100644 index 0000000000..11bd2f7ce2 --- /dev/null +++ b/tests/migrations/test_migrations_atomic_operation/0001_initial.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +def raise_error(apps, schema_editor): + # Test atomic operation in non-atomic migration is wrapped in transaction + Editor = apps.get_model('migrations', 'Editor') + Editor.objects.create(name='Test Editor') + raise RuntimeError('Abort migration') + + +class Migration(migrations.Migration): + atomic = False + + operations = [ + migrations.CreateModel( + "Editor", + [ + ("name", models.CharField(primary_key=True, max_length=255)), + ], + ), + migrations.RunPython(raise_error, atomic=True), + ] diff --git a/tests/migrations/test_migrations_atomic_operation/__init__.py b/tests/migrations/test_migrations_atomic_operation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/migrations/test_migrations_atomic_operation/__init__.py diff --git a/tests/migrations/test_migrations_non_atomic/0001_initial.py b/tests/migrations/test_migrations_non_atomic/0001_initial.py new file mode 100644 index 0000000000..47a03a16f9 --- /dev/null +++ b/tests/migrations/test_migrations_non_atomic/0001_initial.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +def raise_error(apps, schema_editor): + # Test operation in non-atomic migration is not wrapped in transaction + Publisher = apps.get_model('migrations', 'Publisher') + Publisher.objects.create(name='Test Publisher') + raise RuntimeError('Abort migration') + + +class Migration(migrations.Migration): + atomic = False + + operations = [ + migrations.CreateModel( + "Publisher", + [ + ("name", models.CharField(primary_key=True, max_length=255)), + ], + ), + migrations.RunPython(raise_error), + migrations.CreateModel( + "Book", + [ + ("title", models.CharField(primary_key=True, max_length=255)), + ("publisher", models.ForeignKey("migrations.Publisher", models.SET_NULL, null=True)), + ], + ), + ] diff --git a/tests/migrations/test_migrations_non_atomic/__init__.py b/tests/migrations/test_migrations_non_atomic/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/migrations/test_migrations_non_atomic/__init__.py |
