0002-migrate-issuer-data-56819.patch
mellon/migrations/0004_migrate_issuer.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2021-09-14 18:54 |
|
2 | ||
3 |
from django.db import migrations |
|
4 |
from django.db.models import Count |
|
5 | ||
6 | ||
7 |
def migrate_issuer_forward(apps, schema_editor): |
|
8 |
UserSAMLIdentifier = apps.get_model('mellon', 'UserSAMLIdentifier') |
|
9 |
Issuer = apps.get_model('mellon', 'Issuer') |
|
10 |
issuers = UserSAMLIdentifier.objects.values_list('issuer').annotate(total=Count('id')) |
|
11 |
for issuer, total in issuers: |
|
12 |
issuer_instance = Issuer.objects.create(entity_id=issuer) |
|
13 |
UserSAMLIdentifier.objects.filter(issuer=issuer).update(issuer_fk=issuer_instance) |
|
14 | ||
15 | ||
16 |
def migrate_issuer_backward(apps, schema_editor): |
|
17 |
UserSAMLIdentifier = apps.get_model('mellon', 'UserSAMLIdentifier') |
|
18 |
Issuer = apps.get_model('mellon', 'Issuer') |
|
19 |
for issuer in Issuer.objects.all(): |
|
20 |
UserSAMLIdentifier.objects.filter(issuer_fk=issuer).update(issuer=issuer.entity_id) |
|
21 | ||
22 | ||
23 |
class Migration(migrations.Migration): |
|
24 |
dependencies = [ |
|
25 |
('mellon', '0003_add_issuer_model'), |
|
26 |
] |
|
27 | ||
28 |
operations = [] |
|
29 |
operations = [ |
|
30 |
migrations.RunPython(migrate_issuer_forward, migrate_issuer_backward), |
|
31 |
] |
tests/conftest.py | ||
---|---|---|
18 | 18 | |
19 | 19 |
import django_webtest |
20 | 20 |
import pytest |
21 |
from django.core.management import call_command |
|
22 |
from django.db import connection |
|
23 |
from django.db.migrations.executor import MigrationExecutor |
|
21 | 24 | |
22 | 25 | |
23 | 26 |
@pytest.fixture(autouse=True) |
... | ... | |
82 | 85 |
with metadata_path.open('w') as fd: |
83 | 86 |
fd.write(metadata) |
84 | 87 |
yield str(metadata_path) |
88 | ||
89 | ||
90 |
@pytest.fixture() |
|
91 |
def migration(request, transactional_db): |
|
92 |
# see https://gist.github.com/asfaltboy/b3e6f9b5d95af8ba2cc46f2ba6eae5e2 |
|
93 |
""" |
|
94 |
This fixture returns a helper object to test Django data migrations. |
|
95 |
The fixture returns an object with two methods; |
|
96 |
- `before` to initialize db to the state before the migration under test |
|
97 |
- `after` to execute the migration and bring db to the state after the migration |
|
98 |
The methods return `old_apps` and `new_apps` respectively; these can |
|
99 |
be used to initiate the ORM models as in the migrations themselves. |
|
100 |
For example: |
|
101 |
def test_foo_set_to_bar(migration): |
|
102 |
old_apps = migration.before([('my_app', '0001_inital')]) |
|
103 |
Foo = old_apps.get_model('my_app', 'foo') |
|
104 |
Foo.objects.create(bar=False) |
|
105 |
assert Foo.objects.count() == 1 |
|
106 |
assert Foo.objects.filter(bar=False).count() == Foo.objects.count() |
|
107 |
# executing migration |
|
108 |
new_apps = migration.apply([('my_app', '0002_set_foo_bar')]) |
|
109 |
Foo = new_apps.get_model('my_app', 'foo') |
|
110 | ||
111 |
assert Foo.objects.filter(bar=False).count() == 0 |
|
112 |
assert Foo.objects.filter(bar=True).count() == Foo.objects.count() |
|
113 |
Based on: https://gist.github.com/blueyed/4fb0a807104551f103e6 |
|
114 |
""" |
|
115 | ||
116 |
class Migrator: |
|
117 |
def before(self, targets, at_end=True): |
|
118 |
"""Specify app and starting migration names as in: |
|
119 |
before([('app', '0001_before')]) => app/migrations/0001_before.py |
|
120 |
""" |
|
121 |
executor = MigrationExecutor(connection) |
|
122 |
executor.migrate(targets) |
|
123 |
executor.loader.build_graph() |
|
124 |
return executor._create_project_state(with_applied_migrations=True).apps |
|
125 | ||
126 |
def apply(self, targets): |
|
127 |
"""Migrate forwards to the "targets" migration""" |
|
128 |
executor = MigrationExecutor(connection) |
|
129 |
executor.migrate(targets) |
|
130 |
executor.loader.build_graph() |
|
131 |
return executor._create_project_state(with_applied_migrations=True).apps |
|
132 | ||
133 |
yield Migrator() |
|
134 | ||
135 |
call_command('migrate', verbosity=0) |
tests/test_migrations.py | ||
---|---|---|
1 |
# django-mellon - SAML2 authentication for Django |
|
2 |
# Copyright (C) 2014-2021 Entr'ouvert |
|
3 |
# This program is free software: you can redistribute it and/or modify |
|
4 |
# it under the terms of the GNU Affero General Public License as |
|
5 |
# published by the Free Software Foundation, either version 3 of the |
|
6 |
# License, or (at your option) any later version. |
|
7 | ||
8 |
# This program is distributed in the hope that it will be useful, |
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 |
# GNU Affero General Public License for more details. |
|
12 | ||
13 |
# You should have received a copy of the GNU Affero General Public License |
|
14 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
15 | ||
16 |
import pytest |
|
17 |
from django.contrib.auth.models import User |
|
18 | ||
19 |
from mellon.models import Issuer, UserSAMLIdentifier |
|
20 | ||
21 | ||
22 |
@pytest.fixture |
|
23 |
def user_and_issuers(db): |
|
24 |
user1 = User.objects.create(username='user1') |
|
25 |
user2 = User.objects.create(username='user2') |
|
26 |
issuer1 = Issuer.objects.create(entity_id='https://idp1') |
|
27 |
issuer2 = Issuer.objects.create(entity_id='https://idp2') |
|
28 |
UserSAMLIdentifier.objects.create(user=user1, issuer=issuer1, name_id='xxx') |
|
29 |
UserSAMLIdentifier.objects.create(user=user2, issuer=issuer2, name_id='yyy') |
|
30 | ||
31 | ||
32 |
def test_migration_0004_migrate_issuer_back_and_forward(transactional_db, user_and_issuers, migration): |
|
33 |
migration.before([('mellon', '0002_sessionindex')]) |
|
34 |
new_apps = migration.apply([('mellon', '0004_migrate_issuer')]) |
|
35 | ||
36 |
UserSAMLIdentifier = new_apps.get_model('mellon', 'UserSAMLIdentifier') |
|
37 |
Issuer = new_apps.get_model('mellon', 'Issuer') |
|
38 |
User = new_apps.get_model('auth', 'User') |
|
39 | ||
40 |
user1 = User.objects.get(username='user1') |
|
41 |
user2 = User.objects.get(username='user2') |
|
42 | ||
43 |
assert UserSAMLIdentifier.objects.count() == 2 |
|
44 |
assert Issuer.objects.count() == 2 |
|
45 |
assert UserSAMLIdentifier.objects.get(user=user1, issuer_fk__entity_id='https://idp1', name_id='xxx') |
|
46 |
assert UserSAMLIdentifier.objects.get(user=user2, issuer_fk__entity_id='https://idp2', name_id='yyy') |
|
47 | ||
48 | ||
49 |
def test_migration_0004_migrate_issuer(transactional_db, migration): |
|
50 |
old_apps = migration.before([('mellon', '0003_add_issuer_model')]) |
|
51 | ||
52 |
UserSAMLIdentifier = old_apps.get_model('mellon', 'UserSAMLIdentifier') |
|
53 |
User = old_apps.get_model('auth', 'User') |
|
54 | ||
55 |
user1 = User.objects.create(username='user1') |
|
56 |
user2 = User.objects.create(username='user2') |
|
57 | ||
58 |
UserSAMLIdentifier.objects.create(user=user1, issuer='https://idp1', name_id='xxx') |
|
59 |
UserSAMLIdentifier.objects.create(user=user2, issuer='https://idp2', name_id='yyy') |
|
60 | ||
61 |
new_apps = migration.apply([('mellon', '0004_migrate_issuer')]) |
|
62 | ||
63 |
UserSAMLIdentifier = new_apps.get_model('mellon', 'UserSAMLIdentifier') |
|
64 |
Issuer = new_apps.get_model('mellon', 'Issuer') |
|
65 |
User = new_apps.get_model('auth', 'User') |
|
66 | ||
67 |
user1 = User.objects.get(username='user1') |
|
68 |
user2 = User.objects.get(username='user2') |
|
69 | ||
70 |
assert UserSAMLIdentifier.objects.count() == 2 |
|
71 |
assert Issuer.objects.count() == 2 |
|
72 |
assert UserSAMLIdentifier.objects.get(user=user1, issuer_fk__entity_id='https://idp1', name_id='xxx') |
|
73 |
assert UserSAMLIdentifier.objects.get(user=user2, issuer_fk__entity_id='https://idp2', name_id='yyy') |
|
0 |
- |