misc: do not silence failures of migration authentic2.0028 (#47699)

This commit is contained in:
Benjamin Dauvergne 2020-10-14 21:39:42 +02:00 committed by Paul Marillonnet
parent 762cba9a2d
commit 14883ae89c
2 changed files with 16 additions and 80 deletions

View File

@ -1,81 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.18 on 2020-09-17 15:38
from __future__ import unicode_literals
from django.db import migrations, transaction
from django.db.migrations.operations.base import Operation
from django.db.utils import InternalError, OperationalError, ProgrammingError
class SafeExtensionOperation(Operation):
reversible = True
def state_forwards(self, app_label, state):
pass
def database_forwards(self, app_label, schema_editor, from_state, to_state):
if schema_editor.connection.vendor != 'postgresql':
return
try:
with transaction.atomic():
try:
schema_editor.execute('CREATE EXTENSION IF NOT EXISTS %s SCHEMA public' % self.name)
except (OperationalError, ProgrammingError):
# OperationalError if the extension is not available
# ProgrammingError in case of denied permission
RunSQLIfExtension.extensions_installed = False
except InternalError:
# InternalError (current transaction is aborted, commands ignored
# until end of transaction block) would be raised when django-
# tenant-schemas set search_path.
RunSQLIfExtension.extensions_installed = False
def database_backwards(self, app_label, schema_editor, from_state, to_state):
try:
with transaction.atomic():
schema_editor.execute('DROP EXTENSION IF EXISTS %s' % self.name)
except InternalError:
# Raised when other objects depend on the extension. This happens in a multitenant
# context, where extension in installed in schema "public" but referenced in others (via
# public.gist_trgm_ops). In this case, do nothing, as the query should be successful
# when last tenant is processed.
pass
class RunSQLIfExtension(migrations.RunSQL):
extensions_installed = True
def __getattribute__(self, name):
if name == 'sql' and not self.extensions_installed:
return migrations.RunSQL.noop
return object.__getattribute__(self, name)
class UnaccentExtension(SafeExtensionOperation):
name = 'unaccent'
class TrigramExtension(SafeExtensionOperation):
name = 'pg_trgm'
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('authentic2', '0027_remove_deleteduser'),
]
operations = [
TrigramExtension(),
UnaccentExtension(),
RunSQLIfExtension(
sql=["CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ "
"SELECT public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE"],
reverse_sql=['DROP FUNCTION IF EXISTS public.immutable_unaccent(text)']
),
RunSQLIfExtension(
sql=["CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist "
"(LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)"],
reverse_sql=['DROP INDEX IF EXISTS custom_user_name_gist_idx'],
migrations.RunSQL(
sql=[
"CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA public",
"CREATE EXTENSION IF NOT EXISTS pg_trgm SCHEMA public",
"CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ "
"SELECT public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE",
"CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist "
"(LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)"
],
reverse_sql=[
"DROP INDEX IF EXISTS custom_user_name_gist_idx",
"DROP FUNCTION IF EXISTS public.immutable_unaccent(text)",
"DROP EXTENSION IF EXISTS pg_trgm",
"DROP EXTENSION IF EXISTS unaccent",
],
),
]

View File

@ -21,18 +21,6 @@ from django.db.utils import ProgrammingError
from django.utils.timezone import now
def test_migration_0028_trigram_unaccent_index(transactional_db, migration):
migration.before([('authentic2', '0027_remove_deleteduser')])
def programming_error(*args, **kwargs):
raise ProgrammingError
# when an error occurs, ensure migration runs anyway without complaining
with mock.patch('django.db.backends.postgresql.schema.DatabaseSchemaEditor.execute') as mocked:
mocked.side_effect = programming_error
migration.apply([('authentic2', '0028_trigram_unaccent_index')])
def test_migration_custom_user_0021_set_unusable_password(transactional_db, migration):
old_apps = migration.before([('custom_user', '0020_deleteduser')])