def test_linter_creation(self):
     with self.assertRaises(ValueError):
         MigrationLinter('foo/')
     with self.assertRaises(ValueError):
         MigrationLinter('/dev/null')
     with self.assertRaises(ValueError):
         MigrationLinter(fixtures.NOT_DJANGO_GIT_PROJECT)
class RunSQLMigrationTestCase(unittest.TestCase):
    def setUp(self):
        test_project_path = os.path.dirname(settings.BASE_DIR)
        self.linter = MigrationLinter(
            test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
        )

    def test_missing_reserve_migration(self):
        runsql = migrations.RunSQL("sql;")

        error, ignored, warning = self.linter.lint_runsql(runsql)
        self.assertEqual("RUNSQL_REVERSIBLE", warning[0]["code"])

    def test_sql_linting_error(self):
        runsql = migrations.RunSQL("ALTER TABLE t DROP COLUMN t;")

        error, ignored, warning = self.linter.lint_runsql(runsql)
        self.assertEqual("DROP_COLUMN", error[0]["code"])

    def test_sql_linting_error_array(self):
        runsql = migrations.RunSQL(
            ["ALTER TABLE t DROP COLUMN c;", "ALTER TABLE t RENAME COLUMN c;"])

        error, ignored, warning = self.linter.lint_runsql(runsql)
        self.assertEqual("DROP_COLUMN", error[0]["code"])
        self.assertEqual("RENAME_COLUMN", error[1]["code"])

    def test_sql_linting_error_args(self):
        runsql = migrations.RunSQL([("ALTER TABLE %s DROP COLUMN %s;", ("t",
                                                                        "c"))])

        error, ignored, warning = self.linter.lint_runsql(runsql)
        self.assertEqual("DROP_COLUMN", error[0]["code"])
Example #3
0
 def test_gather_migrations_with_list(self):
     linter = MigrationLinter()
     migrations = linter._gather_all_migrations(migrations_list=[
         ("app_add_not_null_column", "0001_create_table"),
         ("app_add_not_null_column", "0002_add_new_not_null_field"),
     ])
     self.assertEqual(2, len(list(migrations)))
 def test_get_sql(self):
     project_path = fixtures.ADD_NOT_NULL_COLUMN_PROJECT
     linter = MigrationLinter(project_path)
     sql_statements = linter.get_sql('test_app', '0001')
     self.assertEqual(len(sql_statements), 6)
     self.assertEqual(sql_statements[0], 'BEGIN;')
     self.assertEqual(sql_statements[-1], 'COMMIT;')
Example #5
0
 def _launch_linter(self, app=None, commit_id=None):
     linter = MigrationLinter(
         self.test_project_path,
         database=next(iter(self.databases)),
         no_cache=True,
     )
     linter.lint_all_migrations(app_label=app, git_commit_id=commit_id)
     return linter
 def test_include_migration_multiple_names(self):
     linter = MigrationLinter(include_name=("0002_foo", "0003_bar"))
     self.assertTrue(
         linter.should_ignore_migration("app_correct", "0001_initial"))
     self.assertFalse(
         linter.should_ignore_migration("app_correct", "0002_foo"))
     self.assertFalse(
         linter.should_ignore_migration("app_correct", "0003_bar"))
    def test_ignore_applied_migrations(self):
        linter = MigrationLinter(only_unapplied_migrations=True)
        linter.migration_loader.applied_migrations = {("app_correct",
                                                       "0002_foo")}

        self.assertFalse(
            linter.should_ignore_migration("app_correct", "0001_initial"))
        self.assertTrue(
            linter.should_ignore_migration("app_correct", "0002_foo"))
 def test_gather_all_migrations(self):
     linter = MigrationLinter(fixtures.CORRECT_PROJECT)
     migrations = linter._gather_all_migrations()
     self.assertEqual(len(migrations), 3)
     self.assertEqual(migrations[0][0], 'test_app1')
     self.assertEqual(migrations[0][1], '0001_initial')
     self.assertEqual(migrations[1][0], 'test_app1')
     self.assertEqual(migrations[1][1], '0002_a_new_null_field')
     self.assertEqual(migrations[2][0], 'test_app2')
     self.assertEqual(migrations[2][1], '0001_foo')
    def _launch_linter(self, app=None, commit_id=None):
        if app is not None:
            app = [app]

        linter = MigrationLinter(
            self.test_project_path,
            include_apps=app,
            database=next(iter(self.databases)),
            no_cache=True,
        )
        linter.lint_all_migrations(git_commit_id=commit_id)
        return linter
 def test_gather_all_migrations(self):
     linter = MigrationLinter(fixtures.CORRECT_PROJECT)
     migrations = linter._gather_all_migrations()
     self.assertEqual(len(migrations), 4)
     self.assertEqual(
         sorted([(m.app_name, m.name) for m in migrations]),
         sorted([
             ("test_app1", "0001_initial"),
             ("test_app1", "0002_a_new_null_field"),
             ("test_app2", "0001_foo"),
             ("test_app3", "0001_initial"),
         ])
     )
    def test_cache_ignored(self):
        cache_file = os.path.join(DEFAULT_CACHE_PATH,
                                  'test_project_ignore_migration.pickle')
        if os.path.exists(cache_file):
            os.remove(cache_file)
        linter = MigrationLinter(fixtures.IGNORE_MIGRATION_PROJECT)

        with mock.patch.object(MigrationLinter,
                               'get_sql',
                               wraps=linter.get_sql) as sql_mock:
            linter.lint_all_migrations()
            self.assertEqual(sql_mock.call_count, 2)

        cache = Cache(fixtures.IGNORE_MIGRATION_PROJECT, DEFAULT_CACHE_PATH)
        cache.load()

        self.assertEqual(cache['63230606af0eccaef7f1f78c537c624c']['result'],
                         'OK')
        self.assertEqual(cache['5c5ca1780a9f28439c1defc1f32af894']['result'],
                         'IGNORE')

        # Start the Linter again -> should use cache now.
        linter = MigrationLinter(fixtures.IGNORE_MIGRATION_PROJECT)

        with mock.patch.object(MigrationLinter,
                               'get_sql',
                               wraps=linter.get_sql) as sql_mock:
            linter.lint_all_migrations()
            self.assertEqual(sql_mock.call_count, 0)
    def test_exclude_warning_from_test(self):
        self.linter = MigrationLinter(
            self.test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
            exclude_migration_tests=("RUNPYTHON_REVERSIBLE", ),
        )

        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0002_missing_reverse")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(0, self.linter.nb_warnings)
        self.assertEqual(1, self.linter.nb_valid)
        self.assertFalse(self.linter.has_errors)
    def test_warnings_as_errors(self):
        self.linter = MigrationLinter(
            self.test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
            warnings_as_errors=True,
        )

        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0003_incorrect_arguments")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(0, self.linter.nb_warnings)
        self.assertEqual(1, self.linter.nb_erroneous)
        self.assertTrue(self.linter.has_errors)
Example #14
0
    def test_cache_ignored(self, *args):
        linter = MigrationLinter(self.test_project_path,
                                 ignore_name_contains="0001")
        linter.old_cache.clear()
        linter.old_cache.save()

        with mock.patch(
                "django_migration_linter.migration_linter.analyse_sql_statements",
                wraps=analyse_sql_statements,
        ) as analyse_sql_statements_mock:
            linter.lint_all_migrations()
            self.assertEqual(1, analyse_sql_statements_mock.call_count)

        cache = linter.new_cache
        cache.load()

        self.assertEqual("IGNORE",
                         cache["0fab48322ba76570da1a3c193abb77b5"]["result"])

        # Start the Linter again -> should use cache now.
        linter = MigrationLinter(self.test_project_path)

        with mock.patch(
                "django_migration_linter.migration_linter.analyse_sql_statements",
                wraps=analyse_sql_statements,
        ) as analyse_sql_statements_mock:
            linter.lint_all_migrations()
            self.assertEqual(1, analyse_sql_statements_mock.call_count)
Example #15
0
    def test_cache_ignored(self, *args):
        linter = MigrationLinter(self.test_project_path, ignore_name_contains="0001")
        linter.old_cache.clear()
        linter.old_cache.save()

        with mock.patch(
            "django_migration_linter.migration_linter.analyse_sql_statements",
            wraps=analyse_sql_statements,
        ) as analyse_sql_statements_mock:
            linter.lint_all_migrations()
            analyse_sql_statements_mock.assert_not_called()

        cache = linter.new_cache
        cache.load()

        self.assertFalse(cache)
    def test_correct_one_param_get_model_import(self):
        def forward_method(apps, schema_editor):
            User = apps.get_model("auth.User")

            User.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_import_issues(
            forward_method)
        self.assertEqual(0, len(issues))
    def test_different_variable_name_one_param(self):
        def forward_op(apps, schema_editor):
            mymodel = apps.get_model("app.MyModel")

            mymodel.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_variable_naming_issues(
            forward_op)
        self.assertEqual(1, len(issues))
    def test_same_variable_name(self):
        def forward_op(apps, schema_editor):
            MyModel = apps.get_model("app", "MyModel")

            MyModel.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_variable_naming_issues(
            forward_op)
        self.assertEqual(0, len(issues))
Example #19
0
    def test_correct_get_model_import(self):
        def correct_importing_model_forward(apps, schema_editor):
            MyModel = apps.get_model("app_data_migrations", "MyModel")

            MyModel.objects.filter(id=1).first()

        issues = MigrationLinter.get_data_migration_model_import_issues(
            correct_importing_model_forward)
        self.assertEqual(0, len(issues))
    def test_missing_get_model_import(self):
        def incorrect_importing_model_forward(apps, schema_editor):
            from tests.test_project.app_data_migrations.models import MyModel

            MyModel.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_import_issues(
            incorrect_importing_model_forward)
        self.assertEqual(1, len(issues))
Example #21
0
    def test_exclude_migration_tests(self):
        m = Migration("0002_add_new_not_null_field", "app_add_not_null_column")

        linter = MigrationLinter(exclude_migration_tests=[], database="mysql")
        linter.lint_migration(m)
        self.assertTrue(linter.has_errors)

        linter = MigrationLinter(exclude_migration_tests=["NOT_NULL"],
                                 database="mysql")
        linter.lint_migration(m)
        self.assertFalse(linter.has_errors)
class DataMigrationDetectionTestCase(unittest.TestCase):
    def setUp(self, *args, **kwargs):
        self.test_project_path = os.path.dirname(settings.BASE_DIR)
        self.linter = MigrationLinter(
            self.test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
        )

    def test_reverse_data_migration(self):
        self.assertEqual(0, self.linter.nb_warnings)
        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0002_missing_reverse")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(1, self.linter.nb_warnings)
        self.assertFalse(self.linter.has_errors)

    def test_reverse_data_migration_ignore(self):
        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0003_incorrect_arguments")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(1, self.linter.nb_warnings)
        self.assertFalse(self.linter.has_errors)

    def test_exclude_warning_from_test(self):
        self.linter = MigrationLinter(
            self.test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
            exclude_migration_tests=("RUNPYTHON_REVERSIBLE", ),
        )

        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0002_missing_reverse")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(0, self.linter.nb_warnings)
        self.assertEqual(1, self.linter.nb_valid)
        self.assertFalse(self.linter.has_errors)

    def test_warnings_as_errors(self):
        self.linter = MigrationLinter(
            self.test_project_path,
            include_apps=fixtures.DATA_MIGRATIONS,
            warnings_as_errors=True,
        )

        reverse_migration = self.linter.migration_loader.disk_migrations[(
            "app_data_migrations", "0003_incorrect_arguments")]
        self.linter.lint_migration(reverse_migration)

        self.assertEqual(0, self.linter.nb_warnings)
        self.assertEqual(1, self.linter.nb_erroneous)
        self.assertTrue(self.linter.has_errors)
    def test_diff_variable_name_multiline(self):
        def forward_op(apps, schema_editor):
            MyModelVeryLongLongLongLongLongNot = apps.get_model(
                "app", "MyModelVeryLongLongLongLongLong")

            MyModelVeryLongLongLongLongLongNot.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_variable_naming_issues(
            forward_op)
        self.assertEqual(1, len(issues))
    def test_different_variable_name_one_param_multiline(self):
        def forward_op(apps, schema_editor):
            m = apps.get_model(
                "quite_long_app_name_name_name.AVeryLongModelNameNameName")

            m.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_variable_naming_issues(
            forward_op)
        self.assertEqual(1, len(issues))
    def test_cache_ignored_command_line(self):
        cache_file = os.path.join(DEFAULT_CACHE_PATH,
                                  'test_project_ignore_migration.pickle')
        if os.path.exists(cache_file):
            os.remove(cache_file)
        linter = MigrationLinter(fixtures.IGNORE_MIGRATION_PROJECT,
                                 ignore_name_contains='0001')

        with mock.patch.object(MigrationLinter,
                               'get_sql',
                               wraps=linter.get_sql) as sql_mock:
            linter.lint_all_migrations()
            self.assertEqual(sql_mock.call_count, 1)

        cache = Cache(fixtures.IGNORE_MIGRATION_PROJECT, DEFAULT_CACHE_PATH)
        cache.load()

        self.assertNotIn('63230606af0eccaef7f1f78c537c624c', cache)
        self.assertEqual(cache['5c5ca1780a9f28439c1defc1f32af894']['result'],
                         'IGNORE')
    def test_has_errors(self):
        project_path = fixtures.MULTI_COMMIT_PROJECT
        linter = MigrationLinter(project_path)
        self.assertFalse(linter.has_errors)

        linter.lint_migration('test_app', '0001')
        self.assertFalse(linter.has_errors)

        linter.lint_migration('test_app', '0002')
        self.assertTrue(linter.has_errors)

        linter.lint_migration('test_app', '0001')
        self.assertTrue(linter.has_errors)
    def test_not_overlapping_model_name(self):
        """
        Correct for the import error, but should raise a warning
        """
        def forward_method(apps, schema_editor):
            User = apps.get_model("auth", "CustomUserModel")

            User.objects.filter(id=1).first()

        issues = MigrationLinter.get_runpython_model_import_issues(
            forward_method)
        self.assertEqual(0, len(issues))
    def test_has_errors(self):
        linter = MigrationLinter()
        self.assertFalse(linter.has_errors)

        m = Migration("0001_create_table", "app_add_not_null_column")
        linter.lint_migration(m)
        self.assertFalse(linter.has_errors)

        m = Migration("0002_add_new_not_null_field", "app_add_not_null_column")
        linter.lint_migration(m)
        self.assertTrue(linter.has_errors)

        m = Migration("0001_create_table", "app_add_not_null_column")
        linter.lint_migration(m)
        self.assertTrue(linter.has_errors)
Example #29
0
    def test_ignore_cached_migration(self, *args):
        linter = MigrationLinter(self.test_project_path)
        linter.old_cache.clear()
        linter.old_cache.save()

        with mock.patch(
                "django_migration_linter.migration_linter.analyse_sql_statements",
                wraps=analyse_sql_statements,
        ) as analyse_sql_statements_mock:
            linter.lint_all_migrations()
            self.assertEqual(2, analyse_sql_statements_mock.call_count)

        cache = linter.new_cache
        cache.load()

        self.assertEqual("OK",
                         cache["4a3770a405738d457e2d23e17fb1f3aa"]["result"])
        self.assertEqual("ERR",
                         cache["19fd3ea688fc05e2cc2a6e67c0b7aa17"]["result"])
        self.assertListEqual(
            cache["19fd3ea688fc05e2cc2a6e67c0b7aa17"]["errors"],
            [{
                "err_msg": "RENAMING tables",
                "code": "RENAME_TABLE",
                "table": None,
                "column": None,
            }],
        )

        # Start the Linter again -> should use cache now but ignore the erroneous
        linter = MigrationLinter(
            self.test_project_path,
            ignore_name_contains="0002_add_new_not_null_field")

        with mock.patch(
                "django_migration_linter.migration_linter.analyse_sql_statements",
                wraps=analyse_sql_statements,
        ) as analyse_sql_statements_mock:
            linter.lint_all_migrations()
            analyse_sql_statements_mock.assert_not_called()

        self.assertFalse(linter.has_errors)

        cache = linter.new_cache
        cache.load()
        self.assertEqual(1, len(cache))
        self.assertEqual("OK",
                         cache["4a3770a405738d457e2d23e17fb1f3aa"]["result"])
    def test_has_errors(self):
        project_path = fixtures.MULTI_COMMIT_PROJECT
        linter = MigrationLinter(project_path)
        self.assertFalse(linter.has_errors)

        m = Migration(os.path.join(project_path, 'test_app/migrations/0001_create_table.py'))
        linter.lint_migration(m)
        self.assertFalse(linter.has_errors)

        m = Migration(os.path.join(project_path, 'test_app/migrations/0002_add_new_not_null_field.py'))
        linter.lint_migration(m)
        self.assertTrue(linter.has_errors)

        m = Migration(os.path.join(project_path, 'test_app/migrations/0001_create_table.py'))
        linter.lint_migration(m)
        self.assertTrue(linter.has_errors)