udata 9.1.2.dev30355__py2.py3-none-any.whl → 9.1.2.dev30382__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of udata might be problematic. Click here for more details.
- tasks/__init__.py +109 -107
- tasks/helpers.py +18 -18
- udata/__init__.py +4 -4
- udata/admin/views.py +5 -5
- udata/api/__init__.py +135 -124
- udata/api/commands.py +45 -37
- udata/api/errors.py +5 -4
- udata/api/fields.py +23 -21
- udata/api/oauth2.py +55 -74
- udata/api/parsers.py +15 -15
- udata/api/signals.py +1 -1
- udata/api_fields.py +137 -89
- udata/app.py +56 -54
- udata/assets.py +5 -5
- udata/auth/__init__.py +37 -26
- udata/auth/forms.py +23 -15
- udata/auth/helpers.py +1 -1
- udata/auth/mails.py +3 -3
- udata/auth/password_validation.py +19 -15
- udata/auth/views.py +94 -68
- udata/commands/__init__.py +71 -69
- udata/commands/cache.py +7 -7
- udata/commands/db.py +201 -140
- udata/commands/dcat.py +36 -30
- udata/commands/fixtures.py +100 -84
- udata/commands/images.py +21 -20
- udata/commands/info.py +17 -20
- udata/commands/init.py +10 -10
- udata/commands/purge.py +12 -13
- udata/commands/serve.py +41 -29
- udata/commands/static.py +16 -18
- udata/commands/test.py +20 -20
- udata/commands/tests/fixtures.py +26 -24
- udata/commands/worker.py +31 -33
- udata/core/__init__.py +12 -12
- udata/core/activity/__init__.py +0 -1
- udata/core/activity/api.py +59 -49
- udata/core/activity/models.py +28 -26
- udata/core/activity/signals.py +1 -1
- udata/core/activity/tasks.py +16 -10
- udata/core/badges/api.py +6 -6
- udata/core/badges/commands.py +14 -13
- udata/core/badges/fields.py +8 -5
- udata/core/badges/forms.py +7 -4
- udata/core/badges/models.py +16 -31
- udata/core/badges/permissions.py +1 -3
- udata/core/badges/signals.py +2 -2
- udata/core/badges/tasks.py +3 -2
- udata/core/badges/tests/test_commands.py +10 -10
- udata/core/badges/tests/test_model.py +24 -31
- udata/core/contact_point/api.py +19 -18
- udata/core/contact_point/api_fields.py +21 -14
- udata/core/contact_point/factories.py +2 -2
- udata/core/contact_point/forms.py +7 -6
- udata/core/contact_point/models.py +3 -5
- udata/core/dataservices/api.py +26 -21
- udata/core/dataservices/factories.py +13 -11
- udata/core/dataservices/models.py +35 -40
- udata/core/dataservices/permissions.py +4 -4
- udata/core/dataservices/rdf.py +40 -17
- udata/core/dataservices/tasks.py +4 -3
- udata/core/dataset/actions.py +10 -10
- udata/core/dataset/activities.py +21 -23
- udata/core/dataset/api.py +321 -298
- udata/core/dataset/api_fields.py +443 -271
- udata/core/dataset/apiv2.py +305 -229
- udata/core/dataset/commands.py +38 -36
- udata/core/dataset/constants.py +61 -54
- udata/core/dataset/csv.py +70 -74
- udata/core/dataset/events.py +39 -32
- udata/core/dataset/exceptions.py +8 -4
- udata/core/dataset/factories.py +57 -65
- udata/core/dataset/forms.py +87 -63
- udata/core/dataset/models.py +336 -280
- udata/core/dataset/permissions.py +9 -6
- udata/core/dataset/preview.py +15 -17
- udata/core/dataset/rdf.py +156 -122
- udata/core/dataset/search.py +92 -77
- udata/core/dataset/signals.py +1 -1
- udata/core/dataset/tasks.py +63 -54
- udata/core/discussions/actions.py +5 -5
- udata/core/discussions/api.py +124 -120
- udata/core/discussions/factories.py +2 -2
- udata/core/discussions/forms.py +9 -7
- udata/core/discussions/metrics.py +1 -3
- udata/core/discussions/models.py +25 -24
- udata/core/discussions/notifications.py +18 -14
- udata/core/discussions/permissions.py +3 -3
- udata/core/discussions/signals.py +4 -4
- udata/core/discussions/tasks.py +24 -28
- udata/core/followers/api.py +32 -33
- udata/core/followers/models.py +9 -9
- udata/core/followers/signals.py +3 -3
- udata/core/jobs/actions.py +7 -7
- udata/core/jobs/api.py +99 -92
- udata/core/jobs/commands.py +48 -49
- udata/core/jobs/forms.py +11 -11
- udata/core/jobs/models.py +6 -6
- udata/core/metrics/__init__.py +2 -2
- udata/core/metrics/commands.py +34 -30
- udata/core/metrics/models.py +2 -4
- udata/core/metrics/signals.py +1 -1
- udata/core/metrics/tasks.py +3 -3
- udata/core/organization/activities.py +12 -15
- udata/core/organization/api.py +167 -174
- udata/core/organization/api_fields.py +183 -124
- udata/core/organization/apiv2.py +32 -32
- udata/core/organization/commands.py +20 -22
- udata/core/organization/constants.py +11 -11
- udata/core/organization/csv.py +17 -15
- udata/core/organization/factories.py +8 -11
- udata/core/organization/forms.py +32 -26
- udata/core/organization/metrics.py +2 -1
- udata/core/organization/models.py +87 -67
- udata/core/organization/notifications.py +18 -14
- udata/core/organization/permissions.py +10 -11
- udata/core/organization/rdf.py +14 -14
- udata/core/organization/search.py +30 -28
- udata/core/organization/signals.py +7 -7
- udata/core/organization/tasks.py +42 -61
- udata/core/owned.py +38 -27
- udata/core/post/api.py +82 -81
- udata/core/post/constants.py +8 -5
- udata/core/post/factories.py +4 -4
- udata/core/post/forms.py +13 -14
- udata/core/post/models.py +20 -22
- udata/core/post/tests/test_api.py +30 -32
- udata/core/reports/api.py +8 -7
- udata/core/reports/constants.py +1 -3
- udata/core/reports/models.py +10 -10
- udata/core/reuse/activities.py +15 -19
- udata/core/reuse/api.py +123 -126
- udata/core/reuse/api_fields.py +120 -85
- udata/core/reuse/apiv2.py +11 -10
- udata/core/reuse/constants.py +23 -23
- udata/core/reuse/csv.py +18 -18
- udata/core/reuse/factories.py +5 -9
- udata/core/reuse/forms.py +24 -21
- udata/core/reuse/models.py +55 -51
- udata/core/reuse/permissions.py +2 -2
- udata/core/reuse/search.py +49 -46
- udata/core/reuse/signals.py +1 -1
- udata/core/reuse/tasks.py +4 -5
- udata/core/site/api.py +47 -50
- udata/core/site/factories.py +2 -2
- udata/core/site/forms.py +4 -5
- udata/core/site/models.py +94 -63
- udata/core/site/rdf.py +14 -14
- udata/core/spam/api.py +16 -9
- udata/core/spam/constants.py +4 -4
- udata/core/spam/fields.py +13 -7
- udata/core/spam/models.py +27 -20
- udata/core/spam/signals.py +1 -1
- udata/core/spam/tests/test_spam.py +6 -5
- udata/core/spatial/api.py +72 -80
- udata/core/spatial/api_fields.py +73 -58
- udata/core/spatial/commands.py +67 -64
- udata/core/spatial/constants.py +3 -3
- udata/core/spatial/factories.py +37 -54
- udata/core/spatial/forms.py +27 -26
- udata/core/spatial/geoids.py +17 -17
- udata/core/spatial/models.py +43 -47
- udata/core/spatial/tasks.py +2 -1
- udata/core/spatial/tests/test_api.py +115 -130
- udata/core/spatial/tests/test_fields.py +74 -77
- udata/core/spatial/tests/test_geoid.py +22 -22
- udata/core/spatial/tests/test_models.py +5 -7
- udata/core/spatial/translations.py +16 -16
- udata/core/storages/__init__.py +16 -18
- udata/core/storages/api.py +66 -64
- udata/core/storages/tasks.py +7 -7
- udata/core/storages/utils.py +15 -15
- udata/core/storages/views.py +5 -6
- udata/core/tags/api.py +17 -14
- udata/core/tags/csv.py +4 -4
- udata/core/tags/models.py +8 -5
- udata/core/tags/tasks.py +11 -13
- udata/core/tags/views.py +4 -4
- udata/core/topic/api.py +84 -73
- udata/core/topic/apiv2.py +157 -127
- udata/core/topic/factories.py +3 -4
- udata/core/topic/forms.py +12 -14
- udata/core/topic/models.py +14 -19
- udata/core/topic/parsers.py +26 -26
- udata/core/user/activities.py +30 -29
- udata/core/user/api.py +151 -152
- udata/core/user/api_fields.py +132 -100
- udata/core/user/apiv2.py +7 -7
- udata/core/user/commands.py +38 -38
- udata/core/user/factories.py +8 -9
- udata/core/user/forms.py +14 -11
- udata/core/user/metrics.py +2 -2
- udata/core/user/models.py +68 -69
- udata/core/user/permissions.py +4 -5
- udata/core/user/rdf.py +7 -8
- udata/core/user/tasks.py +2 -2
- udata/core/user/tests/test_user_model.py +24 -16
- udata/db/tasks.py +2 -1
- udata/entrypoints.py +35 -31
- udata/errors.py +2 -1
- udata/event/values.py +6 -6
- udata/factories.py +2 -2
- udata/features/identicon/api.py +5 -6
- udata/features/identicon/backends.py +48 -55
- udata/features/identicon/tests/test_backends.py +4 -5
- udata/features/notifications/__init__.py +0 -1
- udata/features/notifications/actions.py +9 -9
- udata/features/notifications/api.py +17 -13
- udata/features/territories/__init__.py +12 -10
- udata/features/territories/api.py +14 -15
- udata/features/territories/models.py +23 -28
- udata/features/transfer/actions.py +8 -11
- udata/features/transfer/api.py +84 -77
- udata/features/transfer/factories.py +2 -1
- udata/features/transfer/models.py +11 -12
- udata/features/transfer/notifications.py +19 -15
- udata/features/transfer/permissions.py +5 -5
- udata/forms/__init__.py +5 -2
- udata/forms/fields.py +164 -172
- udata/forms/validators.py +19 -22
- udata/forms/widgets.py +9 -13
- udata/frontend/__init__.py +31 -26
- udata/frontend/csv.py +68 -58
- udata/frontend/markdown.py +40 -44
- udata/harvest/actions.py +89 -77
- udata/harvest/api.py +294 -238
- udata/harvest/backends/__init__.py +4 -4
- udata/harvest/backends/base.py +128 -111
- udata/harvest/backends/dcat.py +80 -66
- udata/harvest/commands.py +56 -60
- udata/harvest/csv.py +8 -8
- udata/harvest/exceptions.py +6 -3
- udata/harvest/filters.py +24 -23
- udata/harvest/forms.py +27 -28
- udata/harvest/models.py +88 -80
- udata/harvest/notifications.py +15 -10
- udata/harvest/signals.py +13 -13
- udata/harvest/tasks.py +11 -10
- udata/harvest/tests/factories.py +23 -24
- udata/harvest/tests/test_actions.py +136 -166
- udata/harvest/tests/test_api.py +220 -214
- udata/harvest/tests/test_base_backend.py +117 -112
- udata/harvest/tests/test_dcat_backend.py +380 -308
- udata/harvest/tests/test_filters.py +33 -22
- udata/harvest/tests/test_models.py +11 -14
- udata/harvest/tests/test_notifications.py +6 -7
- udata/harvest/tests/test_tasks.py +7 -6
- udata/i18n.py +237 -78
- udata/linkchecker/backends.py +5 -11
- udata/linkchecker/checker.py +23 -22
- udata/linkchecker/commands.py +4 -6
- udata/linkchecker/models.py +6 -6
- udata/linkchecker/tasks.py +18 -20
- udata/mail.py +21 -21
- udata/migrations/2020-07-24-remove-s-from-scope-oauth.py +9 -8
- udata/migrations/2020-08-24-add-fs-filename.py +9 -8
- udata/migrations/2020-09-28-update-reuses-datasets-metrics.py +5 -4
- udata/migrations/2020-10-16-migrate-ods-resources.py +9 -10
- udata/migrations/2021-04-08-update-schema-with-new-structure.py +8 -7
- udata/migrations/2021-05-27-fix-default-schema-name.py +7 -6
- udata/migrations/2021-07-05-remove-unused-badges.py +17 -15
- udata/migrations/2021-07-07-update-schema-for-community-resources.py +7 -6
- udata/migrations/2021-08-17-follow-integrity.py +5 -4
- udata/migrations/2021-08-17-harvest-integrity.py +13 -12
- udata/migrations/2021-08-17-oauth2client-integrity.py +5 -4
- udata/migrations/2021-08-17-transfer-integrity.py +5 -4
- udata/migrations/2021-08-17-users-integrity.py +9 -8
- udata/migrations/2021-12-14-reuse-topics.py +7 -6
- udata/migrations/2022-04-21-improve-extension-detection.py +8 -7
- udata/migrations/2022-09-22-clean-inactive-harvest-datasets.py +16 -14
- udata/migrations/2022-10-10-add-fs_uniquifier-to-user-model.py +6 -6
- udata/migrations/2022-10-10-migrate-harvest-extras.py +36 -26
- udata/migrations/2023-02-08-rename-internal-dates.py +46 -28
- udata/migrations/2024-01-29-fix-reuse-and-dataset-with-private-None.py +10 -8
- udata/migrations/2024-03-22-migrate-activity-kwargs-to-extras.py +6 -4
- udata/migrations/2024-06-11-fix-reuse-datasets-references.py +7 -6
- udata/migrations/__init__.py +123 -105
- udata/models/__init__.py +4 -4
- udata/mongo/__init__.py +13 -11
- udata/mongo/badges_field.py +3 -2
- udata/mongo/datetime_fields.py +13 -12
- udata/mongo/document.py +17 -16
- udata/mongo/engine.py +15 -16
- udata/mongo/errors.py +2 -1
- udata/mongo/extras_fields.py +30 -20
- udata/mongo/queryset.py +12 -12
- udata/mongo/slug_fields.py +38 -28
- udata/mongo/taglist_field.py +1 -2
- udata/mongo/url_field.py +5 -5
- udata/mongo/uuid_fields.py +4 -3
- udata/notifications/__init__.py +1 -1
- udata/notifications/mattermost.py +10 -9
- udata/rdf.py +167 -188
- udata/routing.py +40 -45
- udata/search/__init__.py +18 -19
- udata/search/adapter.py +17 -16
- udata/search/commands.py +44 -51
- udata/search/fields.py +13 -20
- udata/search/query.py +23 -18
- udata/search/result.py +9 -10
- udata/sentry.py +21 -19
- udata/settings.py +262 -198
- udata/sitemap.py +8 -6
- udata/static/chunks/{11.e9b9ca1f3e03d4020377.js → 11.52e531c19f8de80c00cf.js} +3 -3
- udata/static/chunks/{11.e9b9ca1f3e03d4020377.js.map → 11.52e531c19f8de80c00cf.js.map} +1 -1
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js → 13.c3343a7f1070061c0e10.js} +2 -2
- udata/static/chunks/{13.038c0d9aa0dfa0181c4b.js.map → 13.c3343a7f1070061c0e10.js.map} +1 -1
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js → 16.8fa42440ad75ca172e6d.js} +2 -2
- udata/static/chunks/{16.0baa2b64a74a2dcde25c.js.map → 16.8fa42440ad75ca172e6d.js.map} +1 -1
- udata/static/chunks/{19.350a9f150b074b4ecefa.js → 19.9c6c8412729cd6d59cfa.js} +3 -3
- udata/static/chunks/{19.350a9f150b074b4ecefa.js.map → 19.9c6c8412729cd6d59cfa.js.map} +1 -1
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js → 5.71d15c2e4f21feee2a9a.js} +3 -3
- udata/static/chunks/{5.6ebbce2b9b3e696d3da5.js.map → 5.71d15c2e4f21feee2a9a.js.map} +1 -1
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js → 6.9139dc098b8ea640b890.js} +3 -3
- udata/static/chunks/{6.d8a5f7b017bcbd083641.js.map → 6.9139dc098b8ea640b890.js.map} +1 -1
- udata/static/common.js +1 -1
- udata/static/common.js.map +1 -1
- udata/storage/s3.py +20 -13
- udata/tags.py +4 -5
- udata/tasks.py +43 -42
- udata/tests/__init__.py +9 -6
- udata/tests/api/__init__.py +5 -6
- udata/tests/api/test_auth_api.py +395 -321
- udata/tests/api/test_base_api.py +31 -33
- udata/tests/api/test_contact_points.py +7 -9
- udata/tests/api/test_dataservices_api.py +211 -158
- udata/tests/api/test_datasets_api.py +823 -812
- udata/tests/api/test_follow_api.py +13 -15
- udata/tests/api/test_me_api.py +95 -112
- udata/tests/api/test_organizations_api.py +301 -339
- udata/tests/api/test_reports_api.py +35 -25
- udata/tests/api/test_reuses_api.py +134 -139
- udata/tests/api/test_swagger.py +5 -5
- udata/tests/api/test_tags_api.py +18 -25
- udata/tests/api/test_topics_api.py +94 -94
- udata/tests/api/test_transfer_api.py +53 -48
- udata/tests/api/test_user_api.py +128 -141
- udata/tests/apiv2/test_datasets.py +290 -198
- udata/tests/apiv2/test_me_api.py +10 -11
- udata/tests/apiv2/test_organizations.py +56 -74
- udata/tests/apiv2/test_swagger.py +5 -5
- udata/tests/apiv2/test_topics.py +69 -87
- udata/tests/cli/test_cli_base.py +8 -8
- udata/tests/cli/test_db_cli.py +21 -19
- udata/tests/dataservice/test_dataservice_tasks.py +8 -12
- udata/tests/dataset/test_csv_adapter.py +44 -35
- udata/tests/dataset/test_dataset_actions.py +2 -3
- udata/tests/dataset/test_dataset_commands.py +7 -8
- udata/tests/dataset/test_dataset_events.py +36 -29
- udata/tests/dataset/test_dataset_model.py +224 -217
- udata/tests/dataset/test_dataset_rdf.py +142 -131
- udata/tests/dataset/test_dataset_tasks.py +15 -15
- udata/tests/dataset/test_resource_preview.py +10 -13
- udata/tests/features/territories/__init__.py +9 -13
- udata/tests/features/territories/test_territories_api.py +71 -91
- udata/tests/forms/test_basic_fields.py +7 -7
- udata/tests/forms/test_current_user_field.py +39 -66
- udata/tests/forms/test_daterange_field.py +31 -39
- udata/tests/forms/test_dict_field.py +28 -26
- udata/tests/forms/test_extras_fields.py +102 -76
- udata/tests/forms/test_form_field.py +8 -8
- udata/tests/forms/test_image_field.py +33 -26
- udata/tests/forms/test_model_field.py +134 -123
- udata/tests/forms/test_model_list_field.py +7 -7
- udata/tests/forms/test_nested_model_list_field.py +117 -79
- udata/tests/forms/test_publish_as_field.py +36 -65
- udata/tests/forms/test_reference_field.py +34 -53
- udata/tests/forms/test_user_forms.py +23 -21
- udata/tests/forms/test_uuid_field.py +6 -10
- udata/tests/frontend/__init__.py +9 -6
- udata/tests/frontend/test_auth.py +7 -6
- udata/tests/frontend/test_csv.py +81 -96
- udata/tests/frontend/test_hooks.py +43 -43
- udata/tests/frontend/test_markdown.py +211 -191
- udata/tests/helpers.py +32 -37
- udata/tests/models.py +2 -2
- udata/tests/organization/test_csv_adapter.py +21 -16
- udata/tests/organization/test_notifications.py +11 -18
- udata/tests/organization/test_organization_model.py +13 -13
- udata/tests/organization/test_organization_rdf.py +29 -22
- udata/tests/organization/test_organization_tasks.py +16 -17
- udata/tests/plugin.py +76 -73
- udata/tests/reuse/test_reuse_model.py +21 -21
- udata/tests/reuse/test_reuse_task.py +11 -13
- udata/tests/search/__init__.py +11 -12
- udata/tests/search/test_adapter.py +60 -70
- udata/tests/search/test_query.py +16 -16
- udata/tests/search/test_results.py +10 -7
- udata/tests/site/test_site_api.py +11 -16
- udata/tests/site/test_site_metrics.py +20 -30
- udata/tests/site/test_site_model.py +4 -5
- udata/tests/site/test_site_rdf.py +94 -78
- udata/tests/test_activity.py +17 -17
- udata/tests/test_discussions.py +292 -299
- udata/tests/test_i18n.py +37 -40
- udata/tests/test_linkchecker.py +91 -85
- udata/tests/test_mail.py +13 -17
- udata/tests/test_migrations.py +219 -180
- udata/tests/test_model.py +164 -157
- udata/tests/test_notifications.py +17 -17
- udata/tests/test_owned.py +14 -14
- udata/tests/test_rdf.py +25 -23
- udata/tests/test_routing.py +89 -93
- udata/tests/test_storages.py +137 -128
- udata/tests/test_tags.py +44 -46
- udata/tests/test_topics.py +7 -7
- udata/tests/test_transfer.py +42 -49
- udata/tests/test_uris.py +160 -161
- udata/tests/test_utils.py +79 -71
- udata/tests/user/test_user_rdf.py +5 -9
- udata/tests/workers/test_jobs_commands.py +57 -58
- udata/tests/workers/test_tasks_routing.py +23 -29
- udata/tests/workers/test_workers_api.py +125 -131
- udata/tests/workers/test_workers_helpers.py +6 -6
- udata/tracking.py +4 -6
- udata/uris.py +45 -46
- udata/utils.py +68 -66
- udata/wsgi.py +1 -1
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/METADATA +3 -2
- udata-9.1.2.dev30382.dist-info/RECORD +704 -0
- udata-9.1.2.dev30355.dist-info/RECORD +0 -704
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/LICENSE +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/WHEEL +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/entry_points.txt +0 -0
- {udata-9.1.2.dev30355.dist-info → udata-9.1.2.dev30382.dist-info}/top_level.txt +0 -0
udata/tests/test_migrations.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import importlib.util
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
2
|
from datetime import datetime
|
|
5
3
|
from textwrap import dedent
|
|
6
4
|
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
7
|
from udata import migrations
|
|
8
8
|
from udata.tests.helpers import assert_equal_dates
|
|
9
9
|
|
|
@@ -13,23 +13,23 @@ class MigrationsMock:
|
|
|
13
13
|
self.root = root
|
|
14
14
|
self.plugins = set()
|
|
15
15
|
self.enabled = set()
|
|
16
|
-
self.build_module(
|
|
16
|
+
self.build_module("udata")
|
|
17
17
|
|
|
18
|
-
def add_migration(self, plugin, filename, content=
|
|
18
|
+
def add_migration(self, plugin, filename, content="", enable=True):
|
|
19
19
|
module = self.ensure_plugin(plugin, enabled=enable)
|
|
20
|
-
module.ensure_dir(
|
|
21
|
-
migration = module /
|
|
20
|
+
module.ensure_dir("migrations")
|
|
21
|
+
migration = module / "migrations" / filename
|
|
22
22
|
migration.write(dedent(content))
|
|
23
23
|
|
|
24
24
|
def build_module(self, name):
|
|
25
25
|
root = self.root.ensure_dir(name)
|
|
26
|
-
root.ensure(
|
|
26
|
+
root.ensure("__init__.py")
|
|
27
27
|
|
|
28
28
|
def ensure_plugin(self, plugin, enabled=True):
|
|
29
|
-
if plugin not in self.plugins and plugin !=
|
|
29
|
+
if plugin not in self.plugins and plugin != "udata":
|
|
30
30
|
self.build_module(plugin)
|
|
31
31
|
self.plugins.add(plugin)
|
|
32
|
-
if enabled and plugin !=
|
|
32
|
+
if enabled and plugin != "udata":
|
|
33
33
|
self.enabled.add(plugin)
|
|
34
34
|
else:
|
|
35
35
|
self.enabled.discard(plugin)
|
|
@@ -37,7 +37,7 @@ class MigrationsMock:
|
|
|
37
37
|
|
|
38
38
|
def _load_module(self, name, path):
|
|
39
39
|
# See: https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly
|
|
40
|
-
spec = importlib.util.spec_from_file_location(name, str(path /
|
|
40
|
+
spec = importlib.util.spec_from_file_location(name, str(path / "__init__.py"))
|
|
41
41
|
module = importlib.util.module_from_spec(spec)
|
|
42
42
|
return module
|
|
43
43
|
|
|
@@ -59,10 +59,7 @@ class MigrationsMock:
|
|
|
59
59
|
return self._resource_path(name, dirname).check(dir=1, exists=1)
|
|
60
60
|
|
|
61
61
|
def mock_get_enabled_entrypoints(self, entrypoint, app):
|
|
62
|
-
return {
|
|
63
|
-
plugin: self._load_module(plugin, self.root / plugin)
|
|
64
|
-
for plugin in self.enabled
|
|
65
|
-
}
|
|
62
|
+
return {plugin: self._load_module(plugin, self.root / plugin) for plugin in self.enabled}
|
|
66
63
|
|
|
67
64
|
def mock_get_plugin_module(self, entrypoint, app, plugin):
|
|
68
65
|
return self._load_module(plugin, self.root / plugin)
|
|
@@ -70,83 +67,94 @@ class MigrationsMock:
|
|
|
70
67
|
|
|
71
68
|
@pytest.fixture
|
|
72
69
|
def mock(app, tmpdir, mocker):
|
|
73
|
-
|
|
70
|
+
"""
|
|
74
71
|
Mock migrations files
|
|
75
|
-
|
|
72
|
+
"""
|
|
76
73
|
m = MigrationsMock(tmpdir)
|
|
77
|
-
mocker.patch(
|
|
78
|
-
mocker.patch(
|
|
79
|
-
mocker.patch(
|
|
80
|
-
mocker.patch(
|
|
81
|
-
mocker.patch(
|
|
82
|
-
mocker.patch(
|
|
74
|
+
mocker.patch("udata.migrations.resource_listdir", side_effect=m.mock_resource_listdir)
|
|
75
|
+
mocker.patch("udata.migrations.resource_isdir", side_effect=m.mock_resource_isdir)
|
|
76
|
+
mocker.patch("udata.migrations.resource_string", side_effect=m.mock_resource_string)
|
|
77
|
+
mocker.patch("udata.migrations.resource_filename", side_effect=m.mock_resource_filename)
|
|
78
|
+
mocker.patch("udata.entrypoints.get_enabled", side_effect=m.mock_get_enabled_entrypoints)
|
|
79
|
+
mocker.patch("udata.entrypoints.get_plugin_module", side_effect=m.mock_get_plugin_module)
|
|
83
80
|
yield m
|
|
84
81
|
|
|
85
82
|
|
|
86
|
-
@pytest.mark.parametrize(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
@pytest.mark.parametrize(
|
|
84
|
+
"args",
|
|
85
|
+
[
|
|
86
|
+
("udata", "test.py"),
|
|
87
|
+
("udata", "test"),
|
|
88
|
+
("udata:test.py", None),
|
|
89
|
+
("udata:test.py", None),
|
|
90
|
+
],
|
|
91
|
+
)
|
|
92
92
|
def test_get_migration(args):
|
|
93
93
|
migration = migrations.get(*args)
|
|
94
94
|
|
|
95
95
|
assert isinstance(migration, migrations.Migration)
|
|
96
|
-
assert migration.plugin ==
|
|
97
|
-
assert migration.filename ==
|
|
96
|
+
assert migration.plugin == "udata"
|
|
97
|
+
assert migration.filename == "test.py"
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
def test_list_available_migrations(mock):
|
|
101
|
-
mock.add_migration(
|
|
102
|
-
mock.add_migration(
|
|
103
|
-
mock.add_migration(
|
|
101
|
+
mock.add_migration("udata", "01_core_migration.py")
|
|
102
|
+
mock.add_migration("test", "02_test_migration.py")
|
|
103
|
+
mock.add_migration("other", "03_other_migration.py")
|
|
104
104
|
# Should not list `__*.py` files
|
|
105
|
-
mock.add_migration(
|
|
105
|
+
mock.add_migration("test", "__private.py")
|
|
106
106
|
# Should not list migrations for disabled plugin
|
|
107
|
-
mock.add_migration(
|
|
107
|
+
mock.add_migration("disabled", "should_not_be_there.py", enable=False)
|
|
108
108
|
# Should not fail on plugins without migrations dir
|
|
109
|
-
mock.ensure_plugin(
|
|
109
|
+
mock.ensure_plugin("nomigrations")
|
|
110
110
|
|
|
111
111
|
availables = migrations.list_available()
|
|
112
112
|
|
|
113
113
|
assert len(availables) == 3
|
|
114
|
-
assert availables == [
|
|
115
|
-
(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
assert availables == [
|
|
115
|
+
migrations.Migration(p, f)
|
|
116
|
+
for p, f in (
|
|
117
|
+
("udata", "01_core_migration.py"),
|
|
118
|
+
("test", "02_test_migration.py"),
|
|
119
|
+
("other", "03_other_migration.py"),
|
|
120
|
+
)
|
|
121
|
+
]
|
|
119
122
|
|
|
120
123
|
|
|
121
124
|
def test_get_record(db):
|
|
122
125
|
inserted = {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
"plugin": "test",
|
|
127
|
+
"filename": "filename.py",
|
|
128
|
+
"ops": [
|
|
129
|
+
{
|
|
130
|
+
"date": datetime.utcnow(),
|
|
131
|
+
"type": "migrate",
|
|
132
|
+
"script": "script",
|
|
133
|
+
"output": "output",
|
|
134
|
+
"success": True,
|
|
135
|
+
}
|
|
136
|
+
],
|
|
132
137
|
}
|
|
133
138
|
db.migrations.insert_one(inserted)
|
|
134
139
|
|
|
135
|
-
record = migrations.get(
|
|
140
|
+
record = migrations.get("test", "filename.py").record
|
|
136
141
|
|
|
137
|
-
assert record[
|
|
138
|
-
assert record[
|
|
142
|
+
assert record["plugin"] == inserted["plugin"]
|
|
143
|
+
assert record["filename"] == inserted["filename"]
|
|
139
144
|
|
|
140
|
-
op = record[
|
|
141
|
-
assert op[
|
|
142
|
-
assert op[
|
|
143
|
-
assert op[
|
|
144
|
-
assert op[
|
|
145
|
-
assert_equal_dates(op[
|
|
145
|
+
op = record["ops"][0]
|
|
146
|
+
assert op["script"] == inserted["ops"][0]["script"]
|
|
147
|
+
assert op["output"] == inserted["ops"][0]["output"]
|
|
148
|
+
assert op["type"] == inserted["ops"][0]["type"]
|
|
149
|
+
assert op["success"]
|
|
150
|
+
assert_equal_dates(op["date"], inserted["ops"][0]["date"])
|
|
146
151
|
|
|
147
152
|
|
|
148
153
|
def test_migration_execute(mock, db):
|
|
149
|
-
mock.add_migration(
|
|
154
|
+
mock.add_migration(
|
|
155
|
+
"udata",
|
|
156
|
+
"migration.py",
|
|
157
|
+
"""\
|
|
150
158
|
import logging
|
|
151
159
|
|
|
152
160
|
log = logging.getLogger(__name__)
|
|
@@ -154,94 +162,106 @@ def test_migration_execute(mock, db):
|
|
|
154
162
|
def migrate(db):
|
|
155
163
|
db.test.insert_one({'key': 'value'})
|
|
156
164
|
log.info('test')
|
|
157
|
-
|
|
165
|
+
""",
|
|
166
|
+
)
|
|
158
167
|
|
|
159
|
-
output = migrations.get(
|
|
168
|
+
output = migrations.get("udata", "migration.py").execute()
|
|
160
169
|
|
|
161
170
|
inserted = db.test.find_one()
|
|
162
171
|
assert inserted is not None
|
|
163
|
-
assert inserted[
|
|
164
|
-
assert output == [[
|
|
172
|
+
assert inserted["key"] == "value"
|
|
173
|
+
assert output == [["info", "test"]]
|
|
165
174
|
|
|
166
175
|
assert db.migrations.count_documents({}) == 1
|
|
167
176
|
record = db.migrations.find_one()
|
|
168
|
-
assert record[
|
|
169
|
-
assert record[
|
|
170
|
-
assert len(record[
|
|
177
|
+
assert record["plugin"] == "udata"
|
|
178
|
+
assert record["filename"] == "migration.py"
|
|
179
|
+
assert len(record["ops"]) == 1
|
|
171
180
|
|
|
172
|
-
op = record[
|
|
173
|
-
assert op[
|
|
174
|
-
assert op[
|
|
175
|
-
assert op[
|
|
176
|
-
assert isinstance(op[
|
|
177
|
-
assert op[
|
|
181
|
+
op = record["ops"][0]
|
|
182
|
+
assert op["type"] == "migrate"
|
|
183
|
+
assert op["output"] == [["info", "test"]]
|
|
184
|
+
assert op["state"] == {}
|
|
185
|
+
assert isinstance(op["date"], datetime)
|
|
186
|
+
assert op["success"]
|
|
178
187
|
|
|
179
188
|
|
|
180
189
|
def test_migration_add_record(mock, db):
|
|
181
|
-
mock.add_migration(
|
|
190
|
+
mock.add_migration(
|
|
191
|
+
"test",
|
|
192
|
+
"filename.py",
|
|
193
|
+
"""\
|
|
182
194
|
# whatever
|
|
183
195
|
|
|
184
196
|
def migrate():
|
|
185
197
|
pass
|
|
186
|
-
|
|
198
|
+
""",
|
|
199
|
+
)
|
|
187
200
|
|
|
188
|
-
expected_output = [[
|
|
201
|
+
expected_output = [["info", "Recorded only"]]
|
|
189
202
|
|
|
190
|
-
output = migrations.get(
|
|
203
|
+
output = migrations.get("test", "filename.py").execute(recordonly=True)
|
|
191
204
|
|
|
192
205
|
assert output == expected_output
|
|
193
206
|
|
|
194
207
|
migration = db.migrations.find_one()
|
|
195
|
-
assert migration[
|
|
196
|
-
assert migration[
|
|
208
|
+
assert migration["plugin"] == "test"
|
|
209
|
+
assert migration["filename"] == "filename.py"
|
|
197
210
|
|
|
198
|
-
op = migration[
|
|
199
|
-
assert op[
|
|
200
|
-
assert op[
|
|
201
|
-
assert op[
|
|
202
|
-
assert op[
|
|
211
|
+
op = migration["ops"][0]
|
|
212
|
+
assert op["script"].startswith("# whatever\n")
|
|
213
|
+
assert op["output"] == expected_output
|
|
214
|
+
assert op["type"] == "migrate"
|
|
215
|
+
assert op["success"]
|
|
203
216
|
|
|
204
217
|
|
|
205
218
|
def test_record_migration(mock, db):
|
|
206
|
-
mock.add_migration(
|
|
219
|
+
mock.add_migration(
|
|
220
|
+
"test",
|
|
221
|
+
"filename.py",
|
|
222
|
+
"""\
|
|
207
223
|
# whatever
|
|
208
224
|
|
|
209
225
|
def migrate():
|
|
210
226
|
pass
|
|
211
|
-
|
|
227
|
+
""",
|
|
228
|
+
)
|
|
212
229
|
|
|
213
|
-
expected_output = [[
|
|
230
|
+
expected_output = [["info", "Recorded only"]]
|
|
214
231
|
|
|
215
|
-
output = migrations.get(
|
|
232
|
+
output = migrations.get("test", "filename.py").execute(recordonly=True)
|
|
216
233
|
|
|
217
234
|
assert output == expected_output
|
|
218
235
|
|
|
219
236
|
migration = db.migrations.find_one()
|
|
220
|
-
assert migration[
|
|
221
|
-
assert migration[
|
|
237
|
+
assert migration["plugin"] == "test"
|
|
238
|
+
assert migration["filename"] == "filename.py"
|
|
222
239
|
|
|
223
|
-
op = migration[
|
|
224
|
-
assert op[
|
|
225
|
-
assert op[
|
|
226
|
-
assert op[
|
|
227
|
-
assert op[
|
|
240
|
+
op = migration["ops"][0]
|
|
241
|
+
assert op["script"].startswith("# whatever\n")
|
|
242
|
+
assert op["output"] == expected_output
|
|
243
|
+
assert op["type"] == "migrate"
|
|
244
|
+
assert op["success"]
|
|
228
245
|
|
|
229
246
|
|
|
230
247
|
def test_execute_missing_plugin(db):
|
|
231
248
|
with pytest.raises(migrations.MigrationError):
|
|
232
|
-
migrations.get(
|
|
249
|
+
migrations.get("test", "filename.py").execute()
|
|
233
250
|
assert db.migrations.find_one() is None
|
|
234
251
|
|
|
235
252
|
|
|
236
253
|
def test_execute_missing_migration(db, mock):
|
|
237
|
-
mock.ensure_plugin(
|
|
254
|
+
mock.ensure_plugin("test")
|
|
238
255
|
with pytest.raises(migrations.MigrationError):
|
|
239
|
-
migrations.get(
|
|
256
|
+
migrations.get("test", "filename.py").execute()
|
|
240
257
|
assert db.migrations.find_one() is None
|
|
241
258
|
|
|
242
259
|
|
|
243
260
|
def test_execute_migration_error(mock, db):
|
|
244
|
-
mock.add_migration(
|
|
261
|
+
mock.add_migration(
|
|
262
|
+
"udata",
|
|
263
|
+
"migration.py",
|
|
264
|
+
"""\
|
|
245
265
|
import logging
|
|
246
266
|
|
|
247
267
|
log = logging.getLogger(__name__)
|
|
@@ -250,50 +270,55 @@ def test_execute_migration_error(mock, db):
|
|
|
250
270
|
db.test.insert_one({'key': 'value'})
|
|
251
271
|
log.info('test')
|
|
252
272
|
raise ValueError('error')
|
|
253
|
-
|
|
273
|
+
""",
|
|
274
|
+
)
|
|
254
275
|
|
|
255
276
|
with pytest.raises(migrations.MigrationError) as excinfo:
|
|
256
|
-
migrations.get(
|
|
277
|
+
migrations.get("udata", "migration.py").execute()
|
|
257
278
|
|
|
258
279
|
exc = excinfo.value
|
|
259
280
|
assert isinstance(exc, migrations.MigrationError)
|
|
260
281
|
assert isinstance(exc.exc, ValueError)
|
|
261
282
|
assert exc.msg == "Error while executing migration"
|
|
262
|
-
assert exc.output == [[
|
|
283
|
+
assert exc.output == [["info", "test"]]
|
|
263
284
|
|
|
264
285
|
# Without rollback DB is left as it is
|
|
265
286
|
assert db.test.count_documents({}) == 1
|
|
266
287
|
inserted = db.test.find_one()
|
|
267
288
|
assert inserted is not None
|
|
268
|
-
assert inserted[
|
|
289
|
+
assert inserted["key"] == "value"
|
|
269
290
|
|
|
270
291
|
# Failed migration is recorded
|
|
271
292
|
assert db.migrations.count_documents({}) == 1
|
|
272
293
|
record = db.migrations.find_one()
|
|
273
|
-
assert record[
|
|
274
|
-
assert record[
|
|
275
|
-
assert len(record[
|
|
294
|
+
assert record["plugin"] == "udata"
|
|
295
|
+
assert record["filename"] == "migration.py"
|
|
296
|
+
assert len(record["ops"]) == 1
|
|
276
297
|
|
|
277
|
-
op = record[
|
|
278
|
-
assert op[
|
|
279
|
-
assert op[
|
|
280
|
-
assert op[
|
|
281
|
-
assert isinstance(op[
|
|
282
|
-
assert not op[
|
|
298
|
+
op = record["ops"][0]
|
|
299
|
+
assert op["type"] == "migrate"
|
|
300
|
+
assert op["output"] == [["info", "test"]]
|
|
301
|
+
assert op["state"] == {}
|
|
302
|
+
assert isinstance(op["date"], datetime)
|
|
303
|
+
assert not op["success"]
|
|
283
304
|
|
|
284
305
|
|
|
285
306
|
def test_execute_migration_error_with_rollback(mock, db):
|
|
286
|
-
mock.add_migration(
|
|
307
|
+
mock.add_migration(
|
|
308
|
+
"udata",
|
|
309
|
+
"migration.py",
|
|
310
|
+
"""\
|
|
287
311
|
def migrate(db):
|
|
288
312
|
db.test.insert_one({'key': 'value'})
|
|
289
313
|
raise ValueError('error')
|
|
290
314
|
|
|
291
315
|
def rollback(db):
|
|
292
316
|
db.rollback_test.insert_one({'key': 'value'})
|
|
293
|
-
|
|
317
|
+
""",
|
|
318
|
+
)
|
|
294
319
|
|
|
295
320
|
with pytest.raises(migrations.MigrationError) as excinfo:
|
|
296
|
-
migrations.get(
|
|
321
|
+
migrations.get("udata", "migration.py").execute()
|
|
297
322
|
|
|
298
323
|
exc = excinfo.value
|
|
299
324
|
assert isinstance(exc, migrations.RollbackError)
|
|
@@ -312,30 +337,33 @@ def test_execute_migration_error_with_rollback(mock, db):
|
|
|
312
337
|
# DB is rollbacked if possible
|
|
313
338
|
assert db.migrations.count_documents({}) == 1
|
|
314
339
|
record = db.migrations.find_one()
|
|
315
|
-
assert record[
|
|
316
|
-
assert record[
|
|
340
|
+
assert record["plugin"] == "udata"
|
|
341
|
+
assert record["filename"] == "migration.py"
|
|
317
342
|
# Both failed migration and rollback are recorded
|
|
318
|
-
assert len(record[
|
|
343
|
+
assert len(record["ops"]) == 2
|
|
319
344
|
|
|
320
345
|
# First the migration
|
|
321
|
-
op = record[
|
|
322
|
-
assert op[
|
|
323
|
-
assert op[
|
|
324
|
-
assert op[
|
|
325
|
-
assert isinstance(op[
|
|
326
|
-
assert not op[
|
|
346
|
+
op = record["ops"][0]
|
|
347
|
+
assert op["type"] == "migrate"
|
|
348
|
+
assert op["output"] == []
|
|
349
|
+
assert op["state"] == {}
|
|
350
|
+
assert isinstance(op["date"], datetime)
|
|
351
|
+
assert not op["success"]
|
|
327
352
|
|
|
328
353
|
# Then the rollback
|
|
329
|
-
op = record[
|
|
330
|
-
assert op[
|
|
331
|
-
assert op[
|
|
332
|
-
assert op[
|
|
333
|
-
assert isinstance(op[
|
|
334
|
-
assert op[
|
|
354
|
+
op = record["ops"][1]
|
|
355
|
+
assert op["type"] == "rollback"
|
|
356
|
+
assert op["output"] == []
|
|
357
|
+
assert op["state"] == {}
|
|
358
|
+
assert isinstance(op["date"], datetime)
|
|
359
|
+
assert op["success"]
|
|
335
360
|
|
|
336
361
|
|
|
337
362
|
def test_execute_migration_error_with_state_rollback(mock, db):
|
|
338
|
-
mock.add_migration(
|
|
363
|
+
mock.add_migration(
|
|
364
|
+
"udata",
|
|
365
|
+
"migration.py",
|
|
366
|
+
"""\
|
|
339
367
|
def migrate(db):
|
|
340
368
|
db.test.insert_one({'key': 'first'})
|
|
341
369
|
db._state['first'] = True
|
|
@@ -348,10 +376,11 @@ def test_execute_migration_error_with_state_rollback(mock, db):
|
|
|
348
376
|
db.rollback_test.insert_one({'key': 'first'})
|
|
349
377
|
if db._state.get('second', False):
|
|
350
378
|
db.rollback_test.insert_one({'key': 'second'})
|
|
351
|
-
|
|
379
|
+
""",
|
|
380
|
+
)
|
|
352
381
|
|
|
353
382
|
with pytest.raises(migrations.MigrationError) as excinfo:
|
|
354
|
-
migrations.get(
|
|
383
|
+
migrations.get("udata", "migration.py").execute()
|
|
355
384
|
|
|
356
385
|
exc = excinfo.value
|
|
357
386
|
assert isinstance(exc, migrations.RollbackError)
|
|
@@ -370,30 +399,33 @@ def test_execute_migration_error_with_state_rollback(mock, db):
|
|
|
370
399
|
# DB is rollbacked if possible
|
|
371
400
|
assert db.migrations.count_documents({}) == 1
|
|
372
401
|
record = db.migrations.find_one()
|
|
373
|
-
assert record[
|
|
374
|
-
assert record[
|
|
402
|
+
assert record["plugin"] == "udata"
|
|
403
|
+
assert record["filename"] == "migration.py"
|
|
375
404
|
# Both failed migration and rollback are recorded
|
|
376
|
-
assert len(record[
|
|
405
|
+
assert len(record["ops"]) == 2
|
|
377
406
|
|
|
378
407
|
# First the migration
|
|
379
|
-
op = record[
|
|
380
|
-
assert op[
|
|
381
|
-
assert op[
|
|
382
|
-
assert op[
|
|
383
|
-
assert isinstance(op[
|
|
384
|
-
assert not op[
|
|
408
|
+
op = record["ops"][0]
|
|
409
|
+
assert op["type"] == "migrate"
|
|
410
|
+
assert op["output"] == []
|
|
411
|
+
assert op["state"] == {"first": True}
|
|
412
|
+
assert isinstance(op["date"], datetime)
|
|
413
|
+
assert not op["success"]
|
|
385
414
|
|
|
386
415
|
# Then the rollback
|
|
387
|
-
op = record[
|
|
388
|
-
assert op[
|
|
389
|
-
assert op[
|
|
390
|
-
assert op[
|
|
391
|
-
assert isinstance(op[
|
|
392
|
-
assert op[
|
|
416
|
+
op = record["ops"][1]
|
|
417
|
+
assert op["type"] == "rollback"
|
|
418
|
+
assert op["output"] == []
|
|
419
|
+
assert op["state"] == {"first": True}
|
|
420
|
+
assert isinstance(op["date"], datetime)
|
|
421
|
+
assert op["success"]
|
|
393
422
|
|
|
394
423
|
|
|
395
424
|
def test_execute_migration_error_with_rollback_error(mock, db):
|
|
396
|
-
mock.add_migration(
|
|
425
|
+
mock.add_migration(
|
|
426
|
+
"udata",
|
|
427
|
+
"migration.py",
|
|
428
|
+
"""\
|
|
397
429
|
def migrate(db):
|
|
398
430
|
db.test.insert_one({'key': 'value'})
|
|
399
431
|
raise ValueError('error')
|
|
@@ -401,10 +433,11 @@ def test_execute_migration_error_with_rollback_error(mock, db):
|
|
|
401
433
|
def rollback(db):
|
|
402
434
|
db.rollback_test.insert_one({'key': 'value'})
|
|
403
435
|
raise ValueError('error')
|
|
404
|
-
|
|
436
|
+
""",
|
|
437
|
+
)
|
|
405
438
|
|
|
406
439
|
with pytest.raises(migrations.MigrationError) as excinfo:
|
|
407
|
-
migrations.get(
|
|
440
|
+
migrations.get("udata", "migration.py").execute()
|
|
408
441
|
|
|
409
442
|
exc = excinfo.value
|
|
410
443
|
assert isinstance(exc, migrations.RollbackError)
|
|
@@ -423,30 +456,33 @@ def test_execute_migration_error_with_rollback_error(mock, db):
|
|
|
423
456
|
# DB is rollbacked if possible
|
|
424
457
|
assert db.migrations.count_documents({}) == 1
|
|
425
458
|
record = db.migrations.find_one()
|
|
426
|
-
assert record[
|
|
427
|
-
assert record[
|
|
459
|
+
assert record["plugin"] == "udata"
|
|
460
|
+
assert record["filename"] == "migration.py"
|
|
428
461
|
# Both failed migration and rollback are recorded
|
|
429
|
-
assert len(record[
|
|
462
|
+
assert len(record["ops"]) == 2
|
|
430
463
|
|
|
431
464
|
# First the migration
|
|
432
|
-
op = record[
|
|
433
|
-
assert op[
|
|
434
|
-
assert op[
|
|
435
|
-
assert op[
|
|
436
|
-
assert isinstance(op[
|
|
437
|
-
assert not op[
|
|
465
|
+
op = record["ops"][0]
|
|
466
|
+
assert op["type"] == "migrate"
|
|
467
|
+
assert op["output"] == []
|
|
468
|
+
assert op["state"] == {}
|
|
469
|
+
assert isinstance(op["date"], datetime)
|
|
470
|
+
assert not op["success"]
|
|
438
471
|
|
|
439
472
|
# Then the rollback
|
|
440
|
-
op = record[
|
|
441
|
-
assert op[
|
|
442
|
-
assert op[
|
|
443
|
-
assert op[
|
|
444
|
-
assert isinstance(op[
|
|
445
|
-
assert not op[
|
|
473
|
+
op = record["ops"][1]
|
|
474
|
+
assert op["type"] == "rollback"
|
|
475
|
+
assert op["output"] == []
|
|
476
|
+
assert op["state"] == {}
|
|
477
|
+
assert isinstance(op["date"], datetime)
|
|
478
|
+
assert not op["success"]
|
|
446
479
|
|
|
447
480
|
|
|
448
481
|
def test_execute_migration_dry_run(mock, db):
|
|
449
|
-
mock.add_migration(
|
|
482
|
+
mock.add_migration(
|
|
483
|
+
"udata",
|
|
484
|
+
"migration.py",
|
|
485
|
+
"""\
|
|
450
486
|
import logging
|
|
451
487
|
|
|
452
488
|
log = logging.getLogger(__name__)
|
|
@@ -454,9 +490,10 @@ def test_execute_migration_dry_run(mock, db):
|
|
|
454
490
|
def migrate(db):
|
|
455
491
|
db.test.insert_one({'key': 'value'})
|
|
456
492
|
log.info('test')
|
|
457
|
-
|
|
493
|
+
""",
|
|
494
|
+
)
|
|
458
495
|
|
|
459
|
-
output = migrations.get(
|
|
496
|
+
output = migrations.get("udata", "migration.py").execute(dryrun=True)
|
|
460
497
|
|
|
461
498
|
assert output == []
|
|
462
499
|
assert db.test.find_one() is None
|
|
@@ -465,20 +502,22 @@ def test_execute_migration_dry_run(mock, db):
|
|
|
465
502
|
|
|
466
503
|
def test_unrecord_migration(db):
|
|
467
504
|
inserted = {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
505
|
+
"plugin": "test",
|
|
506
|
+
"filename": "filename.py",
|
|
507
|
+
"ops": [
|
|
508
|
+
{
|
|
509
|
+
"date": datetime.utcnow(),
|
|
510
|
+
"type": "migrate",
|
|
511
|
+
"script": "script",
|
|
512
|
+
"output": "output",
|
|
513
|
+
"state": {},
|
|
514
|
+
"success": True,
|
|
515
|
+
}
|
|
516
|
+
],
|
|
478
517
|
}
|
|
479
518
|
db.migrations.insert_one(inserted)
|
|
480
519
|
|
|
481
|
-
migration = migrations.get(
|
|
520
|
+
migration = migrations.get("test", "filename.py")
|
|
482
521
|
|
|
483
522
|
# Remove the migration record, return True
|
|
484
523
|
assert migration.unrecord()
|