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
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
import csv
|
|
2
2
|
import logging
|
|
3
|
-
import pytest
|
|
4
|
-
|
|
5
3
|
from datetime import datetime, timedelta
|
|
6
4
|
from tempfile import NamedTemporaryFile
|
|
7
5
|
|
|
6
|
+
import pytest
|
|
8
7
|
from mock import patch
|
|
9
8
|
|
|
10
|
-
from udata.models import Dataset, PeriodicTask
|
|
11
|
-
|
|
12
|
-
from udata.core.organization.factories import OrganizationFactory
|
|
13
|
-
from udata.core.user.factories import UserFactory
|
|
14
9
|
from udata.core.dataset.factories import DatasetFactory
|
|
15
10
|
from udata.core.dataset.models import HarvestDatasetMetadata
|
|
11
|
+
from udata.core.organization.factories import OrganizationFactory
|
|
12
|
+
from udata.core.user.factories import UserFactory
|
|
13
|
+
from udata.models import Dataset, PeriodicTask
|
|
16
14
|
from udata.tests.helpers import assert_emit, assert_equal_dates
|
|
17
|
-
from udata.utils import
|
|
15
|
+
from udata.utils import Paginable, faker
|
|
18
16
|
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
mock_initialize, mock_process, DEFAULT_COUNT as COUNT
|
|
22
|
-
)
|
|
17
|
+
from .. import actions, signals
|
|
18
|
+
from ..backends import BaseBackend
|
|
23
19
|
from ..models import (
|
|
24
|
-
|
|
25
|
-
VALIDATION_PENDING,
|
|
20
|
+
VALIDATION_ACCEPTED,
|
|
21
|
+
VALIDATION_PENDING,
|
|
22
|
+
VALIDATION_REFUSED,
|
|
23
|
+
HarvestError,
|
|
24
|
+
HarvestJob,
|
|
25
|
+
HarvestSource,
|
|
26
|
+
)
|
|
27
|
+
from .factories import DEFAULT_COUNT as COUNT
|
|
28
|
+
from .factories import (
|
|
29
|
+
HarvestJobFactory,
|
|
30
|
+
HarvestSourceFactory,
|
|
31
|
+
MockBackendsMixin,
|
|
32
|
+
mock_initialize,
|
|
33
|
+
mock_process,
|
|
26
34
|
)
|
|
27
|
-
from ..backends import BaseBackend
|
|
28
|
-
from .. import actions, signals
|
|
29
|
-
|
|
30
35
|
|
|
31
36
|
log = logging.getLogger(__name__)
|
|
32
37
|
|
|
33
38
|
pytestmark = [
|
|
34
|
-
pytest.mark.usefixtures(
|
|
39
|
+
pytest.mark.usefixtures("clean_db"),
|
|
35
40
|
]
|
|
36
41
|
|
|
37
42
|
|
|
@@ -163,15 +168,13 @@ class HarvestActionsTest:
|
|
|
163
168
|
source_url = faker.url()
|
|
164
169
|
|
|
165
170
|
with assert_emit(signals.harvest_source_created):
|
|
166
|
-
source = actions.create_source(
|
|
167
|
-
source_url,
|
|
168
|
-
'factory')
|
|
171
|
+
source = actions.create_source("Test source", source_url, "factory")
|
|
169
172
|
|
|
170
|
-
assert source.name ==
|
|
171
|
-
assert source.slug ==
|
|
173
|
+
assert source.name == "Test source"
|
|
174
|
+
assert source.slug == "test-source"
|
|
172
175
|
assert source.url == source_url
|
|
173
|
-
assert source.backend ==
|
|
174
|
-
assert source.frequency ==
|
|
176
|
+
assert source.backend == "factory"
|
|
177
|
+
assert source.frequency == "manual"
|
|
175
178
|
assert source.active
|
|
176
179
|
assert source.owner is None
|
|
177
180
|
assert source.organization is None
|
|
@@ -184,15 +187,12 @@ class HarvestActionsTest:
|
|
|
184
187
|
def test_create_source_with_config(self):
|
|
185
188
|
source_url = faker.url()
|
|
186
189
|
config = {
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
"filters": [{"key": "test", "value": 42}],
|
|
191
|
+
"features": {"key": True},
|
|
189
192
|
}
|
|
190
193
|
|
|
191
194
|
with assert_emit(signals.harvest_source_created):
|
|
192
|
-
source = actions.create_source(
|
|
193
|
-
source_url,
|
|
194
|
-
'factory',
|
|
195
|
-
config=config)
|
|
195
|
+
source = actions.create_source("Test source", source_url, "factory", config=config)
|
|
196
196
|
|
|
197
197
|
assert source.config == config
|
|
198
198
|
|
|
@@ -200,7 +200,7 @@ class HarvestActionsTest:
|
|
|
200
200
|
source = HarvestSourceFactory()
|
|
201
201
|
data = source.to_dict()
|
|
202
202
|
new_url = faker.url()
|
|
203
|
-
data[
|
|
203
|
+
data["url"] = new_url
|
|
204
204
|
|
|
205
205
|
with assert_emit(signals.harvest_source_updated):
|
|
206
206
|
source = actions.update_source(source.id, data)
|
|
@@ -209,7 +209,7 @@ class HarvestActionsTest:
|
|
|
209
209
|
source.reload()
|
|
210
210
|
assert source.url == new_url
|
|
211
211
|
|
|
212
|
-
@patch(
|
|
212
|
+
@patch("udata.harvest.actions.launch")
|
|
213
213
|
def test_validate_source(self, mock):
|
|
214
214
|
source = HarvestSourceFactory()
|
|
215
215
|
|
|
@@ -224,30 +224,30 @@ class HarvestActionsTest:
|
|
|
224
224
|
|
|
225
225
|
assert source.periodic_task is not None
|
|
226
226
|
|
|
227
|
-
@patch(
|
|
227
|
+
@patch("udata.harvest.actions.launch")
|
|
228
228
|
def test_validate_source_with_comment(self, mock):
|
|
229
229
|
source = HarvestSourceFactory()
|
|
230
230
|
|
|
231
|
-
actions.validate_source(source.id,
|
|
231
|
+
actions.validate_source(source.id, "comment")
|
|
232
232
|
|
|
233
233
|
source.reload()
|
|
234
234
|
|
|
235
235
|
assert source.validation.state == VALIDATION_ACCEPTED
|
|
236
236
|
assert source.validation.on is not None
|
|
237
237
|
assert source.validation.by is None
|
|
238
|
-
assert source.validation.comment ==
|
|
238
|
+
assert source.validation.comment == "comment"
|
|
239
239
|
mock.assert_called_once_with(source.id)
|
|
240
240
|
|
|
241
241
|
def test_reject_source(self):
|
|
242
242
|
source = HarvestSourceFactory()
|
|
243
243
|
|
|
244
|
-
actions.reject_source(source.id,
|
|
244
|
+
actions.reject_source(source.id, "comment")
|
|
245
245
|
|
|
246
246
|
source.reload()
|
|
247
247
|
assert source.validation.state == VALIDATION_REFUSED
|
|
248
248
|
assert source.validation.on is not None
|
|
249
249
|
assert source.validation.by is None
|
|
250
|
-
assert source.validation.comment ==
|
|
250
|
+
assert source.validation.comment == "comment"
|
|
251
251
|
|
|
252
252
|
def test_get_source_by_slug(self):
|
|
253
253
|
source = HarvestSourceFactory()
|
|
@@ -291,7 +291,7 @@ class HarvestActionsTest:
|
|
|
291
291
|
deleted_sources = HarvestSource.objects(deleted__exists=True)
|
|
292
292
|
assert len(deleted_sources) == 1
|
|
293
293
|
|
|
294
|
-
@pytest.mark.parametrize(
|
|
294
|
+
@pytest.mark.parametrize("by_attr", ["source.id", "str(source.id)", "source.slug"])
|
|
295
295
|
def test_clean_source(self, by_attr):
|
|
296
296
|
source = HarvestSourceFactory()
|
|
297
297
|
for _ in range(5):
|
|
@@ -319,30 +319,30 @@ class HarvestActionsTest:
|
|
|
319
319
|
periodic_task = source.periodic_task
|
|
320
320
|
assert periodic_task == PeriodicTask.objects.first()
|
|
321
321
|
assert periodic_task.args == [str(source.id)]
|
|
322
|
-
assert periodic_task.crontab.hour ==
|
|
323
|
-
assert periodic_task.crontab.minute ==
|
|
324
|
-
assert periodic_task.crontab.day_of_week ==
|
|
325
|
-
assert periodic_task.crontab.day_of_month ==
|
|
326
|
-
assert periodic_task.crontab.month_of_year ==
|
|
322
|
+
assert periodic_task.crontab.hour == "0"
|
|
323
|
+
assert periodic_task.crontab.minute == "*"
|
|
324
|
+
assert periodic_task.crontab.day_of_week == "*"
|
|
325
|
+
assert periodic_task.crontab.day_of_month == "*"
|
|
326
|
+
assert periodic_task.crontab.month_of_year == "*"
|
|
327
327
|
assert periodic_task.enabled
|
|
328
|
-
assert periodic_task.name ==
|
|
328
|
+
assert periodic_task.name == "Harvest {0}".format(source.name)
|
|
329
329
|
|
|
330
330
|
def test_schedule_from_cron(self):
|
|
331
331
|
source = HarvestSourceFactory()
|
|
332
332
|
with assert_emit(signals.harvest_source_scheduled):
|
|
333
|
-
source = actions.schedule(str(source.id),
|
|
333
|
+
source = actions.schedule(str(source.id), "0 1 2 3 sunday")
|
|
334
334
|
|
|
335
335
|
assert len(PeriodicTask.objects) == 1
|
|
336
336
|
periodic_task = source.periodic_task
|
|
337
337
|
assert periodic_task == PeriodicTask.objects.first()
|
|
338
338
|
assert periodic_task.args == [str(source.id)]
|
|
339
|
-
assert periodic_task.crontab.minute ==
|
|
340
|
-
assert periodic_task.crontab.hour ==
|
|
341
|
-
assert periodic_task.crontab.day_of_month ==
|
|
342
|
-
assert periodic_task.crontab.month_of_year ==
|
|
343
|
-
assert periodic_task.crontab.day_of_week ==
|
|
339
|
+
assert periodic_task.crontab.minute == "0"
|
|
340
|
+
assert periodic_task.crontab.hour == "1"
|
|
341
|
+
assert periodic_task.crontab.day_of_month == "2"
|
|
342
|
+
assert periodic_task.crontab.month_of_year == "3"
|
|
343
|
+
assert periodic_task.crontab.day_of_week == "sunday"
|
|
344
344
|
assert periodic_task.enabled
|
|
345
|
-
assert periodic_task.name ==
|
|
345
|
+
assert periodic_task.name == "Harvest {0}".format(source.name)
|
|
346
346
|
|
|
347
347
|
def test_reschedule(self):
|
|
348
348
|
source = HarvestSourceFactory()
|
|
@@ -356,21 +356,21 @@ class HarvestActionsTest:
|
|
|
356
356
|
periodic_task = source.periodic_task
|
|
357
357
|
assert periodic_task == PeriodicTask.objects.first()
|
|
358
358
|
assert periodic_task.args == [str(source.id)]
|
|
359
|
-
assert periodic_task.crontab.hour ==
|
|
360
|
-
assert periodic_task.crontab.minute ==
|
|
361
|
-
assert periodic_task.crontab.day_of_week ==
|
|
362
|
-
assert periodic_task.crontab.day_of_month ==
|
|
363
|
-
assert periodic_task.crontab.month_of_year ==
|
|
359
|
+
assert periodic_task.crontab.hour == "*"
|
|
360
|
+
assert periodic_task.crontab.minute == "0"
|
|
361
|
+
assert periodic_task.crontab.day_of_week == "*"
|
|
362
|
+
assert periodic_task.crontab.day_of_month == "*"
|
|
363
|
+
assert periodic_task.crontab.month_of_year == "*"
|
|
364
364
|
assert periodic_task.enabled
|
|
365
|
-
assert periodic_task.name ==
|
|
365
|
+
assert periodic_task.name == "Harvest {0}".format(source.name)
|
|
366
366
|
|
|
367
367
|
def test_unschedule(self):
|
|
368
368
|
periodic_task = PeriodicTask.objects.create(
|
|
369
|
-
task=
|
|
369
|
+
task="harvest",
|
|
370
370
|
name=faker.name(),
|
|
371
371
|
description=faker.sentence(),
|
|
372
372
|
enabled=True,
|
|
373
|
-
crontab=PeriodicTask.Crontab()
|
|
373
|
+
crontab=PeriodicTask.Crontab(),
|
|
374
374
|
)
|
|
375
375
|
source = HarvestSourceFactory(periodic_task=periodic_task)
|
|
376
376
|
with assert_emit(signals.harvest_source_unscheduled):
|
|
@@ -382,17 +382,15 @@ class HarvestActionsTest:
|
|
|
382
382
|
|
|
383
383
|
def test_purge_sources(self):
|
|
384
384
|
periodic_task = PeriodicTask.objects.create(
|
|
385
|
-
task=
|
|
385
|
+
task="harvest",
|
|
386
386
|
name=faker.name(),
|
|
387
387
|
description=faker.sentence(),
|
|
388
388
|
enabled=True,
|
|
389
|
-
crontab=PeriodicTask.Crontab()
|
|
389
|
+
crontab=PeriodicTask.Crontab(),
|
|
390
390
|
)
|
|
391
391
|
now = datetime.utcnow()
|
|
392
392
|
to_delete = HarvestSourceFactory.create_batch(2, deleted=now)
|
|
393
|
-
to_delete.append(
|
|
394
|
-
HarvestSourceFactory(periodic_task=periodic_task, deleted=now)
|
|
395
|
-
)
|
|
393
|
+
to_delete.append(HarvestSourceFactory(periodic_task=periodic_task, deleted=now))
|
|
396
394
|
to_keep = HarvestSourceFactory.create_batch(2)
|
|
397
395
|
harvest_job = HarvestJobFactory(source=to_delete[0])
|
|
398
396
|
dataset_to_archive = DatasetFactory(
|
|
@@ -406,7 +404,7 @@ class HarvestActionsTest:
|
|
|
406
404
|
assert len(HarvestSource.objects) == len(to_keep)
|
|
407
405
|
assert PeriodicTask.objects.filter(id=periodic_task.id).count() == 0
|
|
408
406
|
assert HarvestJob.objects(id=harvest_job.id).count() == 0
|
|
409
|
-
assert dataset_to_archive.harvest.archived ==
|
|
407
|
+
assert dataset_to_archive.harvest.archived == "harvester-deleted"
|
|
410
408
|
assert_equal_dates(dataset_to_archive.archived, now)
|
|
411
409
|
|
|
412
410
|
@pytest.mark.options(HARVEST_JOBS_RETENTION_DAYS=2)
|
|
@@ -428,91 +426,71 @@ class HarvestActionsTest:
|
|
|
428
426
|
def test_attach(self):
|
|
429
427
|
datasets = DatasetFactory.create_batch(3)
|
|
430
428
|
|
|
431
|
-
with NamedTemporaryFile(mode=
|
|
432
|
-
writer = csv.DictWriter(
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
quotechar='"')
|
|
429
|
+
with NamedTemporaryFile(mode="w") as csvfile:
|
|
430
|
+
writer = csv.DictWriter(
|
|
431
|
+
csvfile, fieldnames=["local", "remote"], delimiter=";", quotechar='"'
|
|
432
|
+
)
|
|
436
433
|
|
|
437
434
|
writer.writeheader()
|
|
438
435
|
for index, dataset in enumerate(datasets):
|
|
439
|
-
writer.writerow({
|
|
440
|
-
'local': str(dataset.id),
|
|
441
|
-
'remote': str(index)
|
|
442
|
-
})
|
|
436
|
+
writer.writerow({"local": str(dataset.id), "remote": str(index)})
|
|
443
437
|
csvfile.flush()
|
|
444
438
|
|
|
445
|
-
result = actions.attach(
|
|
439
|
+
result = actions.attach("test.org", csvfile.name)
|
|
446
440
|
|
|
447
441
|
assert result.success == len(datasets)
|
|
448
442
|
assert result.errors == 0
|
|
449
443
|
for index, dataset in enumerate(datasets):
|
|
450
444
|
dataset.reload()
|
|
451
|
-
assert dataset.harvest.domain ==
|
|
445
|
+
assert dataset.harvest.domain == "test.org"
|
|
452
446
|
assert dataset.harvest.remote_id == str(index)
|
|
453
447
|
|
|
454
448
|
def test_attach_does_not_duplicate(self):
|
|
455
449
|
attached_datasets = []
|
|
456
450
|
for i in range(2):
|
|
457
451
|
dataset = DatasetFactory.build()
|
|
458
|
-
dataset.harvest = HarvestDatasetMetadata(
|
|
459
|
-
domain='test.org',
|
|
460
|
-
remote_id=str(i)
|
|
461
|
-
)
|
|
452
|
+
dataset.harvest = HarvestDatasetMetadata(domain="test.org", remote_id=str(i))
|
|
462
453
|
dataset.last_modified_internal = datetime.utcnow()
|
|
463
454
|
dataset.save()
|
|
464
455
|
attached_datasets.append(dataset)
|
|
465
456
|
|
|
466
457
|
datasets = DatasetFactory.create_batch(3)
|
|
467
458
|
|
|
468
|
-
with NamedTemporaryFile(mode=
|
|
469
|
-
writer = csv.DictWriter(
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
quotechar='"')
|
|
459
|
+
with NamedTemporaryFile(mode="w") as csvfile:
|
|
460
|
+
writer = csv.DictWriter(
|
|
461
|
+
csvfile, fieldnames=["local", "remote"], delimiter=";", quotechar='"'
|
|
462
|
+
)
|
|
473
463
|
|
|
474
464
|
writer.writeheader()
|
|
475
465
|
for index, dataset in enumerate(datasets):
|
|
476
|
-
writer.writerow({
|
|
477
|
-
'local': str(dataset.id),
|
|
478
|
-
'remote': str(index)
|
|
479
|
-
})
|
|
466
|
+
writer.writerow({"local": str(dataset.id), "remote": str(index)})
|
|
480
467
|
csvfile.flush()
|
|
481
468
|
|
|
482
|
-
result = actions.attach(
|
|
469
|
+
result = actions.attach("test.org", csvfile.name)
|
|
483
470
|
|
|
484
|
-
dbcount = Dataset.objects(**{
|
|
485
|
-
'harvest__remote_id__exists': True
|
|
486
|
-
}).count()
|
|
471
|
+
dbcount = Dataset.objects(**{"harvest__remote_id__exists": True}).count()
|
|
487
472
|
assert result.success == len(datasets)
|
|
488
473
|
assert dbcount == result.success
|
|
489
474
|
for index, dataset in enumerate(datasets):
|
|
490
475
|
dataset.reload()
|
|
491
|
-
assert dataset.harvest.domain ==
|
|
476
|
+
assert dataset.harvest.domain == "test.org"
|
|
492
477
|
assert dataset.harvest.remote_id == str(index)
|
|
493
478
|
|
|
494
479
|
def test_attach_skip_not_found(self):
|
|
495
480
|
datasets = DatasetFactory.create_batch(3)
|
|
496
481
|
|
|
497
|
-
with NamedTemporaryFile(mode=
|
|
498
|
-
writer = csv.DictWriter(
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
quotechar='"')
|
|
482
|
+
with NamedTemporaryFile(mode="w") as csvfile:
|
|
483
|
+
writer = csv.DictWriter(
|
|
484
|
+
csvfile, fieldnames=["local", "remote"], delimiter=";", quotechar='"'
|
|
485
|
+
)
|
|
502
486
|
|
|
503
487
|
writer.writeheader()
|
|
504
|
-
writer.writerow({
|
|
505
|
-
'local': 'not-found',
|
|
506
|
-
'remote': '42'
|
|
507
|
-
})
|
|
488
|
+
writer.writerow({"local": "not-found", "remote": "42"})
|
|
508
489
|
for index, dataset in enumerate(datasets):
|
|
509
|
-
writer.writerow({
|
|
510
|
-
'local': str(dataset.id),
|
|
511
|
-
'remote': str(index)
|
|
512
|
-
})
|
|
490
|
+
writer.writerow({"local": str(dataset.id), "remote": str(index)})
|
|
513
491
|
csvfile.flush()
|
|
514
492
|
|
|
515
|
-
result = actions.attach(
|
|
493
|
+
result = actions.attach("test.org", csvfile.name)
|
|
516
494
|
|
|
517
495
|
assert result.success == len(datasets)
|
|
518
496
|
assert result.errors == 1
|
|
@@ -521,9 +499,8 @@ class HarvestActionsTest:
|
|
|
521
499
|
class ExecutionTestMixin(MockBackendsMixin):
|
|
522
500
|
def test_default(self):
|
|
523
501
|
org = OrganizationFactory()
|
|
524
|
-
source = HarvestSourceFactory(backend=
|
|
525
|
-
with assert_emit(signals.before_harvest_job,
|
|
526
|
-
signals.after_harvest_job):
|
|
502
|
+
source = HarvestSourceFactory(backend="factory", organization=org)
|
|
503
|
+
with assert_emit(signals.before_harvest_job, signals.after_harvest_job):
|
|
527
504
|
self.action(source.slug)
|
|
528
505
|
|
|
529
506
|
source.reload()
|
|
@@ -531,14 +508,14 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
531
508
|
|
|
532
509
|
job = source.get_last_job()
|
|
533
510
|
|
|
534
|
-
assert job.status ==
|
|
511
|
+
assert job.status == "done"
|
|
535
512
|
assert job.errors == []
|
|
536
513
|
assert job.started is not None
|
|
537
514
|
assert job.ended is not None
|
|
538
515
|
assert len(job.items) == COUNT
|
|
539
516
|
|
|
540
517
|
for item in job.items:
|
|
541
|
-
assert item.status ==
|
|
518
|
+
assert item.status == "done"
|
|
542
519
|
assert item.errors == []
|
|
543
520
|
assert item.started is not None
|
|
544
521
|
assert item.ended is not None
|
|
@@ -547,27 +524,26 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
547
524
|
dataset = item.dataset
|
|
548
525
|
assert Dataset.objects(id=dataset.id).first() is not None
|
|
549
526
|
assert dataset.organization == org
|
|
550
|
-
assert
|
|
551
|
-
assert
|
|
552
|
-
assert
|
|
527
|
+
assert "remote_id" in dataset.harvest
|
|
528
|
+
assert "last_update" in dataset.harvest
|
|
529
|
+
assert "source_id" in dataset.harvest
|
|
553
530
|
|
|
554
531
|
assert len(HarvestJob.objects) == 1
|
|
555
532
|
assert len(Dataset.objects) == COUNT
|
|
556
533
|
|
|
557
534
|
def test_error_on_initialize(self):
|
|
558
535
|
def init(self):
|
|
559
|
-
raise ValueError(
|
|
536
|
+
raise ValueError("test")
|
|
560
537
|
|
|
561
|
-
source = HarvestSourceFactory(backend=
|
|
562
|
-
with assert_emit(signals.before_harvest_job)
|
|
563
|
-
mock_initialize.connected_to(init):
|
|
538
|
+
source = HarvestSourceFactory(backend="factory")
|
|
539
|
+
with assert_emit(signals.before_harvest_job), mock_initialize.connected_to(init):
|
|
564
540
|
self.action(source.slug)
|
|
565
541
|
|
|
566
542
|
source.reload()
|
|
567
543
|
assert len(HarvestJob.objects(source=source)) == 1
|
|
568
544
|
|
|
569
545
|
job = source.get_last_job()
|
|
570
|
-
assert job.status ==
|
|
546
|
+
assert job.status == "failed"
|
|
571
547
|
assert len(job.errors) == 1
|
|
572
548
|
error = job.errors[0]
|
|
573
549
|
assert isinstance(error, HarvestError)
|
|
@@ -580,20 +556,21 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
580
556
|
|
|
581
557
|
def test_error_on_item(self):
|
|
582
558
|
def process(self, item):
|
|
583
|
-
if item ==
|
|
584
|
-
raise ValueError(
|
|
585
|
-
|
|
586
|
-
source = HarvestSourceFactory(backend=
|
|
587
|
-
with
|
|
588
|
-
|
|
589
|
-
|
|
559
|
+
if item == "1":
|
|
560
|
+
raise ValueError("test")
|
|
561
|
+
|
|
562
|
+
source = HarvestSourceFactory(backend="factory")
|
|
563
|
+
with (
|
|
564
|
+
assert_emit(signals.before_harvest_job, signals.after_harvest_job),
|
|
565
|
+
mock_process.connected_to(process),
|
|
566
|
+
):
|
|
590
567
|
self.action(source.slug)
|
|
591
568
|
|
|
592
569
|
source.reload()
|
|
593
570
|
assert len(HarvestJob.objects(source=source)) == 1
|
|
594
571
|
|
|
595
572
|
job = source.get_last_job()
|
|
596
|
-
assert job.status ==
|
|
573
|
+
assert job.status == "done-errors"
|
|
597
574
|
assert job.started is not None
|
|
598
575
|
assert job.ended is not None
|
|
599
576
|
assert len(job.errors) == 0
|
|
@@ -605,13 +582,13 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
605
582
|
for item in items_ok:
|
|
606
583
|
assert item.started is not None
|
|
607
584
|
assert item.ended is not None
|
|
608
|
-
assert item.status ==
|
|
585
|
+
assert item.status == "done"
|
|
609
586
|
assert item.errors == []
|
|
610
587
|
|
|
611
588
|
item_ko = next(i for i in job.items if i.errors)
|
|
612
589
|
assert item_ko.started is not None
|
|
613
590
|
assert item_ko.ended is not None
|
|
614
|
-
assert item_ko.status ==
|
|
591
|
+
assert item_ko.status == "failed"
|
|
615
592
|
assert len(item_ko.errors) == 1
|
|
616
593
|
|
|
617
594
|
error = item_ko.errors[0]
|
|
@@ -621,9 +598,8 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
621
598
|
assert len(Dataset.objects) == COUNT - 1
|
|
622
599
|
|
|
623
600
|
def test_empty(self):
|
|
624
|
-
source = HarvestSourceFactory(backend=
|
|
625
|
-
with assert_emit(signals.before_harvest_job,
|
|
626
|
-
signals.after_harvest_job):
|
|
601
|
+
source = HarvestSourceFactory(backend="factory", config={"count": 0})
|
|
602
|
+
with assert_emit(signals.before_harvest_job, signals.after_harvest_job):
|
|
627
603
|
self.action(source.slug)
|
|
628
604
|
|
|
629
605
|
source.reload()
|
|
@@ -631,7 +607,7 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
631
607
|
|
|
632
608
|
job = source.get_last_job()
|
|
633
609
|
|
|
634
|
-
assert job.status ==
|
|
610
|
+
assert job.status == "done"
|
|
635
611
|
assert job.errors == []
|
|
636
612
|
assert job.started is not None
|
|
637
613
|
assert job.ended is not None
|
|
@@ -643,9 +619,7 @@ class ExecutionTestMixin(MockBackendsMixin):
|
|
|
643
619
|
@pytest.mark.options(HARVEST_MAX_ITEMS=5)
|
|
644
620
|
def test_harvest_max_items(self):
|
|
645
621
|
org = OrganizationFactory()
|
|
646
|
-
source = HarvestSourceFactory(backend=
|
|
647
|
-
organization=org,
|
|
648
|
-
config={'count': 10})
|
|
622
|
+
source = HarvestSourceFactory(backend="factory", organization=org, config={"count": 10})
|
|
649
623
|
|
|
650
624
|
self.action(source.slug)
|
|
651
625
|
assert len(Dataset.objects) == 5
|
|
@@ -664,18 +638,18 @@ class HarvestRunTest(ExecutionTestMixin):
|
|
|
664
638
|
class HarvestPreviewTest(MockBackendsMixin):
|
|
665
639
|
def test_preview(self):
|
|
666
640
|
org = OrganizationFactory()
|
|
667
|
-
source = HarvestSourceFactory(backend=
|
|
641
|
+
source = HarvestSourceFactory(backend="factory", organization=org)
|
|
668
642
|
|
|
669
643
|
job = actions.preview(source.slug)
|
|
670
644
|
|
|
671
|
-
assert job.status ==
|
|
645
|
+
assert job.status == "done"
|
|
672
646
|
assert job.errors == []
|
|
673
647
|
assert job.started is not None
|
|
674
648
|
assert job.ended is not None
|
|
675
649
|
assert len(job.items) == COUNT
|
|
676
650
|
|
|
677
651
|
for item in job.items:
|
|
678
|
-
assert item.status ==
|
|
652
|
+
assert item.status == "done"
|
|
679
653
|
assert item.errors == []
|
|
680
654
|
assert item.started is not None
|
|
681
655
|
assert item.ended is not None
|
|
@@ -683,9 +657,9 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
683
657
|
|
|
684
658
|
dataset = item.dataset
|
|
685
659
|
assert dataset.organization == org
|
|
686
|
-
assert
|
|
687
|
-
assert
|
|
688
|
-
assert
|
|
660
|
+
assert "remote_id" in dataset.harvest
|
|
661
|
+
assert "last_update" in dataset.harvest
|
|
662
|
+
assert "source_id" in dataset.harvest
|
|
689
663
|
|
|
690
664
|
assert len(HarvestJob.objects) == 0
|
|
691
665
|
assert len(Dataset.objects) == 0
|
|
@@ -693,9 +667,7 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
693
667
|
@pytest.mark.options(HARVEST_PREVIEW_MAX_ITEMS=5)
|
|
694
668
|
def test_preview_max_items(self):
|
|
695
669
|
org = OrganizationFactory()
|
|
696
|
-
source = HarvestSourceFactory(backend=
|
|
697
|
-
organization=org,
|
|
698
|
-
config={'count': 10})
|
|
670
|
+
source = HarvestSourceFactory(backend="factory", organization=org, config={"count": 10})
|
|
699
671
|
|
|
700
672
|
job = actions.preview(source.slug)
|
|
701
673
|
|
|
@@ -703,14 +675,14 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
703
675
|
|
|
704
676
|
def test_preview_with_error_on_initialize(self):
|
|
705
677
|
def init(self):
|
|
706
|
-
raise ValueError(
|
|
678
|
+
raise ValueError("test")
|
|
707
679
|
|
|
708
|
-
source = HarvestSourceFactory(backend=
|
|
680
|
+
source = HarvestSourceFactory(backend="factory")
|
|
709
681
|
|
|
710
682
|
with mock_initialize.connected_to(init):
|
|
711
683
|
job = actions.preview(source.slug)
|
|
712
684
|
|
|
713
|
-
assert job.status ==
|
|
685
|
+
assert job.status == "failed"
|
|
714
686
|
assert len(job.errors) == 1
|
|
715
687
|
error = job.errors[0]
|
|
716
688
|
assert isinstance(error, HarvestError)
|
|
@@ -723,15 +695,15 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
723
695
|
|
|
724
696
|
def test_preview_with_error_on_item(self):
|
|
725
697
|
def process(self, item):
|
|
726
|
-
if item ==
|
|
727
|
-
raise ValueError(
|
|
698
|
+
if item == "1":
|
|
699
|
+
raise ValueError("test")
|
|
728
700
|
|
|
729
|
-
source = HarvestSourceFactory(backend=
|
|
701
|
+
source = HarvestSourceFactory(backend="factory")
|
|
730
702
|
|
|
731
703
|
with mock_process.connected_to(process):
|
|
732
704
|
job = actions.preview(source.slug)
|
|
733
705
|
|
|
734
|
-
assert job.status ==
|
|
706
|
+
assert job.status == "done-errors"
|
|
735
707
|
assert job.started is not None
|
|
736
708
|
assert job.ended is not None
|
|
737
709
|
assert len(job.errors) == 0
|
|
@@ -743,13 +715,13 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
743
715
|
for item in items_ok:
|
|
744
716
|
assert item.started is not None
|
|
745
717
|
assert item.ended is not None
|
|
746
|
-
assert item.status ==
|
|
718
|
+
assert item.status == "done"
|
|
747
719
|
assert item.errors == []
|
|
748
720
|
|
|
749
721
|
item_ko = next(i for i in job.items if i.errors)
|
|
750
722
|
assert item_ko.started is not None
|
|
751
723
|
assert item_ko.ended is not None
|
|
752
|
-
assert item_ko.status ==
|
|
724
|
+
assert item_ko.status == "failed"
|
|
753
725
|
assert len(item_ko.errors) == 1
|
|
754
726
|
|
|
755
727
|
error = item_ko.errors[0]
|
|
@@ -762,20 +734,18 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
762
734
|
org = OrganizationFactory()
|
|
763
735
|
source_url = faker.url()
|
|
764
736
|
count = 10
|
|
765
|
-
job = actions.preview_from_config(
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
organization=org,
|
|
769
|
-
config={'count': count})
|
|
737
|
+
job = actions.preview_from_config(
|
|
738
|
+
"Test source", source_url, "factory", organization=org, config={"count": count}
|
|
739
|
+
)
|
|
770
740
|
|
|
771
|
-
assert job.status ==
|
|
741
|
+
assert job.status == "done"
|
|
772
742
|
assert job.errors == []
|
|
773
743
|
assert job.started is not None
|
|
774
744
|
assert job.ended is not None
|
|
775
745
|
assert len(job.items) == count
|
|
776
746
|
|
|
777
747
|
for item in job.items:
|
|
778
|
-
assert item.status ==
|
|
748
|
+
assert item.status == "done"
|
|
779
749
|
assert item.errors == []
|
|
780
750
|
assert item.started is not None
|
|
781
751
|
assert item.ended is not None
|
|
@@ -783,9 +753,9 @@ class HarvestPreviewTest(MockBackendsMixin):
|
|
|
783
753
|
|
|
784
754
|
dataset = item.dataset
|
|
785
755
|
assert dataset.organization == org
|
|
786
|
-
assert
|
|
787
|
-
assert
|
|
788
|
-
assert
|
|
756
|
+
assert "remote_id" in dataset.harvest
|
|
757
|
+
assert "last_update" in dataset.harvest
|
|
758
|
+
assert "source_id" in dataset.harvest
|
|
789
759
|
|
|
790
760
|
assert len(HarvestJob.objects) == 0
|
|
791
761
|
assert len(Dataset.objects) == 0
|