From 5dd2eeb87cddadadf6030b168892a2f56e3c8781 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 14 Sep 2021 21:03:16 +0200 Subject: [PATCH 2/3] migrate issuer data (#56819) --- mellon/migrations/0004_migrate_issuer.py | 31 ++++++++++++++ tests/conftest.py | 51 ++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 mellon/migrations/0004_migrate_issuer.py diff --git a/mellon/migrations/0004_migrate_issuer.py b/mellon/migrations/0004_migrate_issuer.py new file mode 100644 index 0000000..a09c996 --- /dev/null +++ b/mellon/migrations/0004_migrate_issuer.py @@ -0,0 +1,31 @@ +# Generated by Django 2.2.19 on 2021-09-14 18:54 + +from django.db import migrations +from django.db.models import Count + + +def migrate_issuer_forward(apps, schema_editor): + UserSAMLIdentifier = apps.get_model('mellon', 'UserSAMLIdentifier') + Issuer = apps.get_model('mellon', 'Issuer') + issuers = UserSAMLIdentifier.objects.values_list('issuer').annotate(total=Count('id')) + for issuer, total in issuers: + issuer_instance = Issuer.objects.create(entity_id=issuer) + UserSAMLIdentifier.objects.filter(issuer=issuer).update(issuer_fk=issuer_instance) + + +def migrate_issuer_backward(apps, schema_editor): + UserSAMLIdentifier = apps.get_model('mellon', 'UserSAMLIdentifier') + Issuer = apps.get_model('mellon', 'Issuer') + for issuer in Issuer.objects.all(): + UserSAMLIdentifier.objects.filter(issuer_fk=issuer).update(isuer=issuer.entity_id) + + +class Migration(migrations.Migration): + dependencies = [ + ('mellon', '0003_add_issuer_model'), + ] + + operations = [] + operations = [ + migrations.RunPython(migrate_issuer_forward, migrate_issuer_backward), + ] diff --git a/tests/conftest.py b/tests/conftest.py index 2e668be..b8df92e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -18,6 +18,9 @@ import os import django_webtest import pytest +from django.core.management import call_command +from django.db import connection +from django.db.migrations.executor import MigrationExecutor @pytest.fixture(autouse=True) @@ -82,3 +85,51 @@ def metadata_path(tmpdir, metadata): with metadata_path.open('w') as fd: fd.write(metadata) yield str(metadata_path) + + +@pytest.fixture() +def migration(request, transactional_db): + # see https://gist.github.com/asfaltboy/b3e6f9b5d95af8ba2cc46f2ba6eae5e2 + """ + This fixture returns a helper object to test Django data migrations. + The fixture returns an object with two methods; + - `before` to initialize db to the state before the migration under test + - `after` to execute the migration and bring db to the state after the migration + The methods return `old_apps` and `new_apps` respectively; these can + be used to initiate the ORM models as in the migrations themselves. + For example: + def test_foo_set_to_bar(migration): + old_apps = migration.before([('my_app', '0001_inital')]) + Foo = old_apps.get_model('my_app', 'foo') + Foo.objects.create(bar=False) + assert Foo.objects.count() == 1 + assert Foo.objects.filter(bar=False).count() == Foo.objects.count() + # executing migration + new_apps = migration.apply([('my_app', '0002_set_foo_bar')]) + Foo = new_apps.get_model('my_app', 'foo') + + assert Foo.objects.filter(bar=False).count() == 0 + assert Foo.objects.filter(bar=True).count() == Foo.objects.count() + Based on: https://gist.github.com/blueyed/4fb0a807104551f103e6 + """ + + class Migrator: + def before(self, targets, at_end=True): + """Specify app and starting migration names as in: + before([('app', '0001_before')]) => app/migrations/0001_before.py + """ + executor = MigrationExecutor(connection) + executor.migrate(targets) + executor.loader.build_graph() + return executor._create_project_state(with_applied_migrations=True).apps + + def apply(self, targets): + """Migrate forwards to the "targets" migration""" + executor = MigrationExecutor(connection) + executor.migrate(targets) + executor.loader.build_graph() + return executor._create_project_state(with_applied_migrations=True).apps + + yield Migrator() + + call_command('migrate', verbosity=0) -- 2.33.0