From f21ff2c27868ab3e7a8144d54792f341e5eade7e Mon Sep 17 00:00:00 2001 From: David Wobrock Date: Sat, 20 Jun 2020 17:39:59 +0200 Subject: [PATCH] Add (failing) tests cases for makeing a column not null with a Django default value --- tests/fixtures.py | 2 + tests/functional/test_migration_linter.py | 17 +++++++++ .../__init__.py | 0 .../apps.py | 5 +++ .../migrations/0001_initial.py | 28 ++++++++++++++ .../0002_make_not_null_with_django_default.py | 18 +++++++++ .../migrations/__init__.py | 0 .../models.py | 5 +++ .../__init__.py | 0 .../apps.py | 5 +++ .../migrations/0001_initial.py | 28 ++++++++++++++ .../0002_make_not_null_with_lib_default.py | 21 ++++++++++ .../migrations/__init__.py | 0 .../models.py | 5 +++ tests/test_project/settings.py | 2 + tests/unit/test_sql_analyser.py | 38 +++++++++++++++++++ 16 files changed, 174 insertions(+) create mode 100644 tests/test_project/app_make_not_null_with_django_default/__init__.py create mode 100644 tests/test_project/app_make_not_null_with_django_default/apps.py create mode 100644 tests/test_project/app_make_not_null_with_django_default/migrations/0001_initial.py create mode 100644 tests/test_project/app_make_not_null_with_django_default/migrations/0002_make_not_null_with_django_default.py create mode 100644 tests/test_project/app_make_not_null_with_django_default/migrations/__init__.py create mode 100644 tests/test_project/app_make_not_null_with_django_default/models.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/__init__.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/apps.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/migrations/0001_initial.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/migrations/0002_make_not_null_with_lib_default.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/migrations/__init__.py create mode 100644 tests/test_project/app_make_not_null_with_lib_default/models.py diff --git a/tests/fixtures.py b/tests/fixtures.py index d037295..571924d 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -11,3 +11,5 @@ ALTER_COLUMN_DROP_NOT_NULL = "app_alter_column_drop_not_null" DROP_UNIQUE_TOGETHER = "app_unique_together" ADD_MANYTOMANY_FIELD = "app_add_manytomany_field" DATA_MIGRATIONS = "app_data_migrations" +MAKE_NOT_NULL_WITH_DJANGO_DEFAULT = "app_make_not_null_with_django_default" +MAKE_NOT_NULL_WITH_LIB_DEFAULT = "app_make_not_null_with_lib_default" diff --git a/tests/functional/test_migration_linter.py b/tests/functional/test_migration_linter.py index a3f30b4..ed95302 100644 --- a/tests/functional/test_migration_linter.py +++ b/tests/functional/test_migration_linter.py @@ -44,6 +44,14 @@ class BaseBackwardCompatibilityDetection(object): app = fixtures.ADD_NOT_NULL_COLUMN self._test_linter_finds_errors(app) + def test_detect_make_column_not_null_with_django_default(self): + app = fixtures.MAKE_NOT_NULL_WITH_DJANGO_DEFAULT + self._test_linter_finds_errors(app) + + def test_detect_make_column_not_null_with_lib_default(self): + app = fixtures.MAKE_NOT_NULL_WITH_LIB_DEFAULT + self._test_linter_finds_no_errors(app) + def test_detect_drop_column(self): app = fixtures.DROP_COLUMN self._test_linter_finds_errors(app) @@ -97,6 +105,15 @@ class SqliteBackwardCompatibilityDetectionTestCase( app = fixtures.ADD_NOT_NULL_COLUMN_FOLLOWED_BY_DEFAULT self._test_linter_finds_errors(app) + def test_detect_make_column_not_null_with_django_default(self): + app = fixtures.MAKE_NOT_NULL_WITH_DJANGO_DEFAULT + self._test_linter_finds_errors(app) + + def test_detect_make_column_not_null_with_lib_default(self): + # The 'django-add-default-value' doesn't handle sqlite correctly + app = fixtures.MAKE_NOT_NULL_WITH_LIB_DEFAULT + self._test_linter_finds_errors(app) + class MySqlBackwardCompatibilityDetectionTestCase( BaseBackwardCompatibilityDetection, unittest.TestCase diff --git a/tests/test_project/app_make_not_null_with_django_default/__init__.py b/tests/test_project/app_make_not_null_with_django_default/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_project/app_make_not_null_with_django_default/apps.py b/tests/test_project/app_make_not_null_with_django_default/apps.py new file mode 100644 index 0000000..feabe81 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_django_default/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AppMakeNotNullWithDjangoDefaultConfig(AppConfig): + name = "app_make_not_null_with_django_default" diff --git a/tests/test_project/app_make_not_null_with_django_default/migrations/0001_initial.py b/tests/test_project/app_make_not_null_with_django_default/migrations/0001_initial.py new file mode 100644 index 0000000..62f9610 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_django_default/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2 on 2020-06-20 15:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="A", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("col", models.CharField(max_length=10, null=True)), + ], + ), + ] diff --git a/tests/test_project/app_make_not_null_with_django_default/migrations/0002_make_not_null_with_django_default.py b/tests/test_project/app_make_not_null_with_django_default/migrations/0002_make_not_null_with_django_default.py new file mode 100644 index 0000000..c8cb410 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_django_default/migrations/0002_make_not_null_with_django_default.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2 on 2020-06-20 15:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("app_make_not_null_with_django_default", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="a", + name="col", + field=models.CharField(default="empty", max_length=10), + ), + ] diff --git a/tests/test_project/app_make_not_null_with_django_default/migrations/__init__.py b/tests/test_project/app_make_not_null_with_django_default/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_project/app_make_not_null_with_django_default/models.py b/tests/test_project/app_make_not_null_with_django_default/models.py new file mode 100644 index 0000000..f4000fa --- /dev/null +++ b/tests/test_project/app_make_not_null_with_django_default/models.py @@ -0,0 +1,5 @@ +from django.db import models + + +class A(models.Model): + col = models.CharField(max_length=10, null=False, default="empty") diff --git a/tests/test_project/app_make_not_null_with_lib_default/__init__.py b/tests/test_project/app_make_not_null_with_lib_default/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_project/app_make_not_null_with_lib_default/apps.py b/tests/test_project/app_make_not_null_with_lib_default/apps.py new file mode 100644 index 0000000..a13fcd9 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_lib_default/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AppMakeNotNullWithLibDefaultConfig(AppConfig): + name = "app_make_not_null_with_lib_default" diff --git a/tests/test_project/app_make_not_null_with_lib_default/migrations/0001_initial.py b/tests/test_project/app_make_not_null_with_lib_default/migrations/0001_initial.py new file mode 100644 index 0000000..5e20102 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_lib_default/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2 on 2020-06-20 15:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="A", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("col", models.CharField(max_length=10, null=True)), + ], + ), + ] diff --git a/tests/test_project/app_make_not_null_with_lib_default/migrations/0002_make_not_null_with_lib_default.py b/tests/test_project/app_make_not_null_with_lib_default/migrations/0002_make_not_null_with_lib_default.py new file mode 100644 index 0000000..d8cd75c --- /dev/null +++ b/tests/test_project/app_make_not_null_with_lib_default/migrations/0002_make_not_null_with_lib_default.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2 on 2020-06-20 15:23 + +from django.db import migrations, models + +from django_add_default_value import AddDefaultValue + + +class Migration(migrations.Migration): + + dependencies = [ + ("app_make_not_null_with_lib_default", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="a", + name="col", + field=models.CharField(default="avalue", max_length=10), + ), + AddDefaultValue(model_name="a", name="col", value="avalue"), + ] diff --git a/tests/test_project/app_make_not_null_with_lib_default/migrations/__init__.py b/tests/test_project/app_make_not_null_with_lib_default/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_project/app_make_not_null_with_lib_default/models.py b/tests/test_project/app_make_not_null_with_lib_default/models.py new file mode 100644 index 0000000..a6acbc5 --- /dev/null +++ b/tests/test_project/app_make_not_null_with_lib_default/models.py @@ -0,0 +1,5 @@ +from django.db import models + + +class A(models.Model): + col = models.CharField(max_length=10, null=False, default="avalue") diff --git a/tests/test_project/settings.py b/tests/test_project/settings.py index c2a4bc3..41747b7 100644 --- a/tests/test_project/settings.py +++ b/tests/test_project/settings.py @@ -54,6 +54,8 @@ INSTALLED_APPS = [ "tests.test_project.app_rename_table", "tests.test_project.app_unique_together", "tests.test_project.app_data_migrations", + "tests.test_project.app_make_not_null_with_django_default", + "tests.test_project.app_make_not_null_with_lib_default", ] MIDDLEWARE = [ diff --git a/tests/unit/test_sql_analyser.py b/tests/unit/test_sql_analyser.py index 23b1f17..4b646ca 100644 --- a/tests/unit/test_sql_analyser.py +++ b/tests/unit/test_sql_analyser.py @@ -64,6 +64,25 @@ class MySqlAnalyserTestCase(SqlAnalyserTestCase): ] self.assertValidSql(sql) + def test_make_column_not_null_with_django_default(self): + sql = [ + "ALTER TABLE `app_drop_default_a` ALTER COLUMN `col` SET DEFAULT 'empty';", + "UPDATE `app_drop_default_a` SET `col` = 'empty' WHERE `col` IS NULL;", + "ALTER TABLE `app_drop_default_a` MODIFY `col` varchar(10) NOT NULL;", + "ALTER TABLE `app_drop_default_a` ALTER COLUMN `col` DROP DEFAULT;", + ] + self.assertBackwardIncompatibleSql(sql) + + def test_make_column_not_null_with_lib_default(self): + sql = [ + "ALTER TABLE `app_drop_default_a` ALTER COLUMN `col` SET DEFAULT 'empty';", + "UPDATE `app_drop_default_a` SET `col` = 'empty' WHERE `col` IS NULL;", + "ALTER TABLE `app_drop_default_a` MODIFY `col` varchar(10) NOT NULL;", + "ALTER TABLE `app_drop_default_a` ALTER COLUMN `col` DROP DEFAULT;", + "ALTER TABLE `app_drop_default_a` ALTER COLUMN `col` SET DEFAULT 'empty';", + ] + self.assertValidSql(sql) + class SqliteAnalyserTestCase(SqlAnalyserTestCase): database_vendor = "sqlite" @@ -165,3 +184,22 @@ class PostgresqlAnalyserTestCase(SqlAnalyserTestCase): 'CREATE INDEX "app_add_manytomany_field_b_many_to_many_a_id_4b44832a" ON "app_add_manytomany_field_b_many_to_many"("a_id");', ] self.assertValidSql(sql) + + def test_make_column_not_null_with_django_default(self): + sql = [ + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" SET DEFAULT \'empty\';', + 'UPDATE "app_drop_default_a" SET "col" = \'empty\' WHERE "col" IS NULL;', + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" SET NOT NULL;', + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" DROP DEFAULT;', + ] + self.assertBackwardIncompatibleSql(sql) + + def test_make_column_not_null_with_lib_default(self): + sql = [ + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" SET DEFAULT \'empty\';', + 'UPDATE "app_drop_default_a" SET "col" = \'empty\' WHERE "col" IS NULL;', + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" SET NOT NULL;', + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" DROP DEFAULT;', + 'ALTER TABLE "app_drop_default_a" ALTER COLUMN "col" SET DEFAULT `\'empty\';', + ] + self.assertValidSql(sql)