udata 12.0.2.dev17__py3-none-any.whl → 12.0.2.dev19__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.
- udata/commands/tests/test_fixtures.py +2 -3
- udata/core/badges/tests/test_commands.py +2 -4
- udata/core/badges/tests/test_model.py +2 -2
- udata/core/dataservices/models.py +4 -0
- udata/core/dataservices/search.py +1 -1
- udata/core/dataset/search.py +2 -2
- udata/core/organization/search.py +1 -1
- udata/core/pages/tests/test_api.py +0 -2
- udata/core/reuse/search.py +1 -1
- udata/core/spatial/tests/test_api.py +17 -20
- udata/core/spatial/tests/test_models.py +3 -3
- udata/core/user/tests/test_user_model.py +2 -6
- udata/features/identicon/tests/test_backends.py +3 -13
- udata/harvest/tests/ckan/test_ckan_backend.py +300 -337
- udata/harvest/tests/ckan/test_ckan_backend_errors.py +94 -99
- udata/harvest/tests/ckan/test_ckan_backend_filters.py +128 -122
- udata/harvest/tests/ckan/test_dkan_backend.py +39 -51
- udata/harvest/tests/test_actions.py +7 -7
- udata/harvest/tests/test_api.py +2 -4
- udata/harvest/tests/test_base_backend.py +3 -4
- udata/harvest/tests/test_dcat_backend.py +4 -6
- udata/harvest/tests/test_models.py +2 -4
- udata/harvest/tests/test_notifications.py +2 -4
- udata/harvest/tests/test_tasks.py +2 -3
- udata/tests/__init__.py +40 -58
- udata/tests/api/__init__.py +87 -2
- udata/tests/api/test_activities_api.py +17 -23
- udata/tests/api/test_auth_api.py +2 -4
- udata/tests/api/test_contact_points.py +48 -54
- udata/tests/api/test_dataservices_api.py +0 -2
- udata/tests/api/test_datasets_api.py +15 -29
- udata/tests/api/test_me_api.py +4 -6
- udata/tests/api/test_organizations_api.py +19 -38
- udata/tests/api/test_reports_api.py +0 -4
- udata/tests/api/test_reuses_api.py +9 -19
- udata/tests/api/test_swagger.py +2 -3
- udata/tests/api/test_tags_api.py +6 -7
- udata/tests/api/test_transfer_api.py +0 -2
- udata/tests/api/test_user_api.py +8 -10
- udata/tests/apiv2/test_datasets.py +0 -4
- udata/tests/apiv2/test_me_api.py +0 -2
- udata/tests/apiv2/test_organizations.py +0 -2
- udata/tests/apiv2/test_swagger.py +2 -3
- udata/tests/apiv2/test_topics.py +0 -2
- udata/tests/cli/test_cli_base.py +14 -12
- udata/tests/cli/test_db_cli.py +51 -54
- udata/tests/contact_point/test_contact_point_models.py +2 -2
- udata/tests/dataservice/test_csv_adapter.py +2 -5
- udata/tests/dataservice/test_dataservice_rdf.py +3 -6
- udata/tests/dataservice/test_dataservice_tasks.py +36 -38
- udata/tests/dataset/test_csv_adapter.py +2 -5
- udata/tests/dataset/test_dataset_actions.py +2 -4
- udata/tests/dataset/test_dataset_commands.py +2 -4
- udata/tests/dataset/test_dataset_events.py +3 -3
- udata/tests/dataset/test_dataset_model.py +6 -7
- udata/tests/dataset/test_dataset_rdf.py +6 -9
- udata/tests/dataset/test_dataset_recommendations.py +2 -2
- udata/tests/dataset/test_dataset_tasks.py +66 -68
- udata/tests/dataset/test_resource_preview.py +39 -48
- udata/tests/dataset/test_transport_tasks.py +2 -2
- udata/tests/features/territories/__init__.py +0 -6
- udata/tests/features/territories/test_territories_api.py +25 -24
- udata/tests/forms/test_current_user_field.py +2 -2
- udata/tests/forms/test_dict_field.py +2 -4
- udata/tests/forms/test_extras_fields.py +2 -3
- udata/tests/forms/test_image_field.py +2 -2
- udata/tests/forms/test_model_field.py +2 -4
- udata/tests/forms/test_publish_as_field.py +2 -4
- udata/tests/forms/test_user_forms.py +26 -29
- udata/tests/frontend/test_auth.py +2 -3
- udata/tests/frontend/test_csv.py +5 -6
- udata/tests/frontend/test_error_handlers.py +2 -3
- udata/tests/frontend/test_hooks.py +5 -7
- udata/tests/frontend/test_markdown.py +3 -4
- udata/tests/helpers.py +2 -7
- udata/tests/metrics/test_metrics.py +52 -48
- udata/tests/metrics/test_tasks.py +154 -150
- udata/tests/organization/test_csv_adapter.py +2 -5
- udata/tests/organization/test_notifications.py +2 -4
- udata/tests/organization/test_organization_model.py +3 -4
- udata/tests/organization/test_organization_rdf.py +2 -8
- udata/tests/plugin.py +6 -110
- udata/tests/reuse/test_reuse_model.py +3 -4
- udata/tests/site/test_site_api.py +0 -2
- udata/tests/site/test_site_csv_exports.py +0 -2
- udata/tests/site/test_site_metrics.py +2 -4
- udata/tests/site/test_site_model.py +2 -2
- udata/tests/site/test_site_rdf.py +3 -6
- udata/tests/test_activity.py +3 -3
- udata/tests/test_api_fields.py +6 -9
- udata/tests/test_cors.py +0 -2
- udata/tests/test_dcat_commands.py +2 -3
- udata/tests/test_discussions.py +2 -7
- udata/tests/test_mail.py +4 -10
- udata/tests/test_migrations.py +413 -419
- udata/tests/test_model.py +10 -11
- udata/tests/test_notifications.py +2 -3
- udata/tests/test_owned.py +3 -3
- udata/tests/test_routing.py +5 -5
- udata/tests/test_storages.py +6 -5
- udata/tests/test_tags.py +2 -1
- udata/tests/test_topics.py +2 -4
- udata/tests/test_transfer.py +4 -5
- udata/tests/topic/test_topic_tasks.py +25 -27
- udata/tests/user/test_user_rdf.py +2 -8
- udata/tests/workers/test_jobs_commands.py +2 -2
- udata/tests/workers/test_tasks_routing.py +27 -27
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/METADATA +1 -1
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/RECORD +113 -115
- udata/tests/frontend/__init__.py +0 -23
- udata/tests/metrics/conftest.py +0 -15
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/WHEEL +0 -0
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/entry_points.txt +0 -0
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/licenses/LICENSE +0 -0
- {udata-12.0.2.dev17.dist-info → udata-12.0.2.dev19.dist-info}/top_level.txt +0 -0
|
@@ -2,11 +2,7 @@ import pytest
|
|
|
2
2
|
|
|
3
3
|
from udata.harvest import actions
|
|
4
4
|
from udata.harvest.tests.factories import HarvestSourceFactory
|
|
5
|
-
|
|
6
|
-
pytestmark = [
|
|
7
|
-
pytest.mark.usefixtures("clean_db"),
|
|
8
|
-
pytest.mark.options(PLUGINS=["ckan"]),
|
|
9
|
-
]
|
|
5
|
+
from udata.tests.api import PytestOnlyDBTestCase
|
|
10
6
|
|
|
11
7
|
CKAN_URL = "https://harvest.me/"
|
|
12
8
|
API_URL = "{}api/3/action/package_list".format(CKAN_URL)
|
|
@@ -17,124 +13,123 @@ API_URL = "{}api/3/action/package_list".format(CKAN_URL)
|
|
|
17
13
|
STATUS_CODE = (400, 500)
|
|
18
14
|
|
|
19
15
|
|
|
20
|
-
@pytest.mark.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
actions.run(source)
|
|
29
|
-
|
|
30
|
-
source.reload()
|
|
31
|
-
|
|
32
|
-
job = source.get_last_job()
|
|
33
|
-
assert len(job.items) == 0
|
|
34
|
-
assert len(job.errors) == 1
|
|
35
|
-
error = job.errors[0]
|
|
36
|
-
# HTML is detected and does not clutter the message
|
|
37
|
-
assert html not in error.message
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@pytest.mark.parametrize("code", STATUS_CODE)
|
|
41
|
-
def test_plain_text_error(rmock, code):
|
|
42
|
-
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
43
|
-
|
|
44
|
-
rmock.get(
|
|
45
|
-
API_URL, text='"Some error"', status_code=code, headers={"Content-Type": "text/plain"}
|
|
46
|
-
)
|
|
16
|
+
@pytest.mark.options(PLUGINS=["ckan"])
|
|
17
|
+
class CkanBackendErrorsTest(PytestOnlyDBTestCase):
|
|
18
|
+
@pytest.mark.parametrize("code", STATUS_CODE)
|
|
19
|
+
def test_html_error(self, rmock, code):
|
|
20
|
+
# Happens with wrong source URL (html is returned instead of json)
|
|
21
|
+
html = "<html><body>Error</body></html>"
|
|
22
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
47
23
|
|
|
48
|
-
|
|
24
|
+
rmock.get(API_URL, text=html, status_code=code, headers={"Content-Type": "text/html"})
|
|
49
25
|
|
|
50
|
-
|
|
26
|
+
actions.run(source)
|
|
51
27
|
|
|
52
|
-
|
|
53
|
-
assert len(job.items) == 0
|
|
54
|
-
assert len(job.errors) == 1
|
|
55
|
-
error = job.errors[0]
|
|
56
|
-
# Raw quoted string is properly unquoted
|
|
57
|
-
http_message = "Server Error" if code == 500 else "Client Error"
|
|
58
|
-
assert (
|
|
59
|
-
error.message
|
|
60
|
-
== f"{code} {http_message}: None for url: https://harvest.me/api/3/action/package_list"
|
|
61
|
-
)
|
|
28
|
+
source.reload()
|
|
62
29
|
|
|
30
|
+
job = source.get_last_job()
|
|
31
|
+
assert len(job.items) == 0
|
|
32
|
+
assert len(job.errors) == 1
|
|
33
|
+
error = job.errors[0]
|
|
34
|
+
# HTML is detected and does not clutter the message
|
|
35
|
+
assert html not in error.message
|
|
63
36
|
|
|
64
|
-
|
|
65
|
-
|
|
37
|
+
@pytest.mark.parametrize("code", STATUS_CODE)
|
|
38
|
+
def test_plain_text_error(self, rmock, code):
|
|
39
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
66
40
|
|
|
67
|
-
|
|
41
|
+
rmock.get(
|
|
42
|
+
API_URL, text='"Some error"', status_code=code, headers={"Content-Type": "text/plain"}
|
|
43
|
+
)
|
|
68
44
|
|
|
69
|
-
|
|
45
|
+
actions.run(source)
|
|
70
46
|
|
|
71
|
-
|
|
47
|
+
source.reload()
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
49
|
+
job = source.get_last_job()
|
|
50
|
+
assert len(job.items) == 0
|
|
51
|
+
assert len(job.errors) == 1
|
|
52
|
+
error = job.errors[0]
|
|
53
|
+
# Raw quoted string is properly unquoted
|
|
54
|
+
http_message = "Server Error" if code == 500 else "Client Error"
|
|
55
|
+
assert (
|
|
56
|
+
error.message
|
|
57
|
+
== f"{code} {http_message}: None for url: https://harvest.me/api/3/action/package_list"
|
|
58
|
+
)
|
|
79
59
|
|
|
60
|
+
def test_200_plain_text_error(self, rmock):
|
|
61
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
rmock.get(
|
|
64
|
+
API_URL, text='"Some error"', status_code=200, headers={"Content-Type": "text/plain"}
|
|
65
|
+
)
|
|
84
66
|
|
|
85
|
-
|
|
67
|
+
actions.run(source)
|
|
86
68
|
|
|
87
|
-
|
|
69
|
+
source.reload()
|
|
88
70
|
|
|
89
|
-
|
|
71
|
+
job = source.get_last_job()
|
|
72
|
+
assert len(job.items) == 0
|
|
73
|
+
assert len(job.errors) == 1
|
|
74
|
+
error = job.errors[0]
|
|
75
|
+
# Raw quoted string is properly unquoted
|
|
76
|
+
assert error.message == "Some error"
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
error = job.errors[0]
|
|
95
|
-
assert error.message == "an error"
|
|
78
|
+
def test_standard_api_json_error(self, rmock):
|
|
79
|
+
json = {"success": False, "error": "an error"}
|
|
80
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
96
81
|
|
|
82
|
+
rmock.get(API_URL, json=json, status_code=200, headers={"Content-Type": "application/json"})
|
|
97
83
|
|
|
98
|
-
|
|
99
|
-
json = {
|
|
100
|
-
"success": False,
|
|
101
|
-
"error": {
|
|
102
|
-
"message": "an error",
|
|
103
|
-
},
|
|
104
|
-
}
|
|
105
|
-
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
84
|
+
actions.run(source)
|
|
106
85
|
|
|
107
|
-
|
|
86
|
+
source.reload()
|
|
108
87
|
|
|
109
|
-
|
|
88
|
+
job = source.get_last_job()
|
|
89
|
+
assert len(job.items) == 0
|
|
90
|
+
assert len(job.errors) == 1
|
|
91
|
+
error = job.errors[0]
|
|
92
|
+
assert error.message == "an error"
|
|
110
93
|
|
|
111
|
-
|
|
94
|
+
def test_standard_api_json_error_with_details(self, rmock):
|
|
95
|
+
json = {
|
|
96
|
+
"success": False,
|
|
97
|
+
"error": {
|
|
98
|
+
"message": "an error",
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
112
102
|
|
|
113
|
-
|
|
114
|
-
assert len(job.items) == 0
|
|
115
|
-
assert len(job.errors) == 1
|
|
116
|
-
error = job.errors[0]
|
|
117
|
-
assert error.message == "an error"
|
|
103
|
+
rmock.get(API_URL, json=json, status_code=200, headers={"Content-Type": "application/json"})
|
|
118
104
|
|
|
105
|
+
actions.run(source)
|
|
119
106
|
|
|
120
|
-
|
|
121
|
-
json = {
|
|
122
|
-
"success": False,
|
|
123
|
-
"error": {
|
|
124
|
-
"message": "Access denied",
|
|
125
|
-
"__type": "Authorization Error",
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
107
|
+
source.reload()
|
|
129
108
|
|
|
130
|
-
|
|
109
|
+
job = source.get_last_job()
|
|
110
|
+
assert len(job.items) == 0
|
|
111
|
+
assert len(job.errors) == 1
|
|
112
|
+
error = job.errors[0]
|
|
113
|
+
assert error.message == "an error"
|
|
131
114
|
|
|
132
|
-
|
|
115
|
+
def test_standard_api_json_error_with_details_and_type(self, rmock):
|
|
116
|
+
json = {
|
|
117
|
+
"success": False,
|
|
118
|
+
"error": {
|
|
119
|
+
"message": "Access denied",
|
|
120
|
+
"__type": "Authorization Error",
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
source = HarvestSourceFactory(backend="ckan", url=CKAN_URL)
|
|
133
124
|
|
|
134
|
-
|
|
125
|
+
rmock.get(API_URL, json=json, status_code=200, headers={"Content-Type": "application/json"})
|
|
135
126
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
127
|
+
actions.run(source)
|
|
128
|
+
|
|
129
|
+
source.reload()
|
|
130
|
+
|
|
131
|
+
job = source.get_last_job()
|
|
132
|
+
assert len(job.items) == 0
|
|
133
|
+
assert len(job.errors) == 1
|
|
134
|
+
error = job.errors[0]
|
|
135
|
+
assert error.message == "Authorization Error: Access denied"
|
|
@@ -4,127 +4,133 @@ import pytest
|
|
|
4
4
|
|
|
5
5
|
from udata.harvest import actions
|
|
6
6
|
from udata.harvest.tests.factories import HarvestSourceFactory
|
|
7
|
+
from udata.tests.api import PytestOnlyDBTestCase
|
|
7
8
|
from udata.utils import faker
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
10
|
+
|
|
11
|
+
@pytest.mark.options(PLUGINS=["ckan"])
|
|
12
|
+
class CkanBackendFilterTest(PytestOnlyDBTestCase):
|
|
13
|
+
def test_include_org_filter(self, ckan, rmock):
|
|
14
|
+
source = HarvestSourceFactory(
|
|
15
|
+
backend="ckan",
|
|
16
|
+
url=ckan.BASE_URL,
|
|
17
|
+
config={"filters": [{"key": "organization", "value": "organization_name"}]},
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
rmock.get(
|
|
21
|
+
ckan.PACKAGE_SEARCH_URL,
|
|
22
|
+
json={"success": True, "result": {"results": []}},
|
|
23
|
+
status_code=200,
|
|
24
|
+
headers={"Content-Type": "application/json"},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
actions.run(source)
|
|
28
|
+
source.reload()
|
|
29
|
+
|
|
30
|
+
assert rmock.call_count == 1
|
|
31
|
+
params = {"q": "organization:organization_name", "rows": 1000}
|
|
32
|
+
assert (
|
|
33
|
+
rmock.last_request.url == f"{ckan.PACKAGE_SEARCH_URL}?{urllib.parse.urlencode(params)}"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def test_exclude_org_filter(self, ckan, rmock):
|
|
37
|
+
source = HarvestSourceFactory(
|
|
38
|
+
backend="ckan",
|
|
39
|
+
url=ckan.BASE_URL,
|
|
40
|
+
config={
|
|
41
|
+
"filters": [
|
|
42
|
+
{"key": "organization", "value": "organization_name", "type": "exclude"}
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
rmock.get(
|
|
48
|
+
ckan.PACKAGE_SEARCH_URL,
|
|
49
|
+
json={"success": True, "result": {"results": []}},
|
|
50
|
+
status_code=200,
|
|
51
|
+
headers={"Content-Type": "application/json"},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
actions.run(source)
|
|
55
|
+
source.reload()
|
|
56
|
+
|
|
57
|
+
assert rmock.call_count == 1
|
|
58
|
+
|
|
59
|
+
params = {"q": "-organization:organization_name", "rows": 1000}
|
|
60
|
+
assert (
|
|
61
|
+
rmock.last_request.url == f"{ckan.PACKAGE_SEARCH_URL}?{urllib.parse.urlencode(params)}"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def test_tag_filter(self, ckan, rmock):
|
|
65
|
+
tag = faker.word()
|
|
66
|
+
source = HarvestSourceFactory(
|
|
67
|
+
backend="ckan", url=ckan.BASE_URL, config={"filters": [{"key": "tags", "value": tag}]}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
rmock.get(
|
|
71
|
+
ckan.PACKAGE_SEARCH_URL,
|
|
72
|
+
json={"success": True, "result": {"results": []}},
|
|
73
|
+
status_code=200,
|
|
74
|
+
headers={"Content-Type": "application/json"},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
actions.run(source)
|
|
78
|
+
source.reload()
|
|
79
|
+
|
|
80
|
+
assert rmock.call_count == 1
|
|
81
|
+
params = {"q": f"tags:{tag}", "rows": 1000}
|
|
82
|
+
assert (
|
|
83
|
+
rmock.last_request.url == f"{ckan.PACKAGE_SEARCH_URL}?{urllib.parse.urlencode(params)}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def test_exclude_tag_filter(self, ckan, rmock):
|
|
87
|
+
tag = faker.word()
|
|
88
|
+
source = HarvestSourceFactory(
|
|
89
|
+
backend="ckan",
|
|
90
|
+
url=ckan.BASE_URL,
|
|
91
|
+
config={"filters": [{"key": "tags", "value": tag, "type": "exclude"}]},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
rmock.get(
|
|
95
|
+
ckan.PACKAGE_SEARCH_URL,
|
|
96
|
+
json={"success": True, "result": {"results": []}},
|
|
97
|
+
status_code=200,
|
|
98
|
+
headers={"Content-Type": "application/json"},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
actions.run(source)
|
|
102
|
+
source.reload()
|
|
103
|
+
|
|
104
|
+
assert rmock.call_count == 1
|
|
105
|
+
params = {"q": f"-tags:{tag}", "rows": 1000}
|
|
106
|
+
assert (
|
|
107
|
+
rmock.last_request.url == f"{ckan.PACKAGE_SEARCH_URL}?{urllib.parse.urlencode(params)}"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def test_can_have_multiple_filters(self, ckan, rmock):
|
|
111
|
+
source = HarvestSourceFactory(
|
|
112
|
+
backend="ckan",
|
|
113
|
+
url=ckan.BASE_URL,
|
|
114
|
+
config={
|
|
115
|
+
"filters": [
|
|
116
|
+
{"key": "organization", "value": "organization_name"},
|
|
117
|
+
{"key": "tags", "value": "tag-2", "type": "exclude"},
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
rmock.get(
|
|
123
|
+
ckan.PACKAGE_SEARCH_URL,
|
|
124
|
+
json={"success": True, "result": {"results": []}},
|
|
125
|
+
status_code=200,
|
|
126
|
+
headers={"Content-Type": "application/json"},
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
actions.run(source)
|
|
130
|
+
source.reload()
|
|
131
|
+
|
|
132
|
+
assert rmock.call_count == 1
|
|
133
|
+
params = {"q": "organization:organization_name AND -tags:tag-2", "rows": 1000}
|
|
134
|
+
assert (
|
|
135
|
+
rmock.last_request.url == f"{ckan.PACKAGE_SEARCH_URL}?{urllib.parse.urlencode(params)}"
|
|
136
|
+
)
|
|
@@ -4,13 +4,11 @@ from datetime import datetime
|
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
7
|
-
from udata.app import create_app
|
|
8
7
|
from udata.core.organization.factories import OrganizationFactory
|
|
9
8
|
from udata.harvest import actions
|
|
10
9
|
from udata.harvest.tests.factories import HarvestSourceFactory
|
|
11
10
|
from udata.models import Dataset
|
|
12
|
-
from udata.
|
|
13
|
-
from udata.tests.plugin import drop_db
|
|
11
|
+
from udata.tests.api import PytestOnlyDBTestCase
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
def data_path(filename):
|
|
@@ -18,51 +16,41 @@ def data_path(filename):
|
|
|
18
16
|
return os.path.join(os.path.dirname(__file__), "data", filename)
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
assert source.get_last_job().status == "done"
|
|
60
|
-
|
|
61
|
-
datasets = Dataset.objects.filter(organization=org)
|
|
62
|
-
assert len(datasets) > 0
|
|
63
|
-
|
|
64
|
-
dataset = datasets.get(**{"harvest__remote_id": "04be6288-696d-4331-850d-a144871a7e3a"})
|
|
65
|
-
assert dataset.harvest.created_at == datetime(2019, 12, 10, 0, 0)
|
|
66
|
-
assert dataset.harvest.modified_at == datetime(2019, 9, 30, 0, 0)
|
|
67
|
-
assert len(dataset.resources) == 2
|
|
68
|
-
assert "xlsx" in [r.format for r in dataset.resources]
|
|
19
|
+
@pytest.mark.options(PLUGINS=["dkan"])
|
|
20
|
+
class DkanBackendTest(PytestOnlyDBTestCase):
|
|
21
|
+
def test_dkan_french_w_license(self, rmock):
|
|
22
|
+
"""CKAN Harvester should accept the minimum dataset payload"""
|
|
23
|
+
DKAN_URL = "https://harvest.me/"
|
|
24
|
+
API_URL = "{}api/3/action/".format(DKAN_URL)
|
|
25
|
+
PACKAGE_LIST_URL = "{}package_list".format(API_URL)
|
|
26
|
+
PACKAGE_SHOW_URL = "{}package_show".format(API_URL)
|
|
27
|
+
|
|
28
|
+
with open(data_path("dkan-french-w-license.json")) as ifile:
|
|
29
|
+
data = json.loads(ifile.read())
|
|
30
|
+
|
|
31
|
+
org = OrganizationFactory()
|
|
32
|
+
source = HarvestSourceFactory(backend="dkan", url=DKAN_URL, organization=org)
|
|
33
|
+
rmock.get(
|
|
34
|
+
PACKAGE_LIST_URL,
|
|
35
|
+
json={"success": True, "result": ["fake-name"]},
|
|
36
|
+
status_code=200,
|
|
37
|
+
headers={"Content-Type": "application/json"},
|
|
38
|
+
)
|
|
39
|
+
rmock.get(
|
|
40
|
+
PACKAGE_SHOW_URL,
|
|
41
|
+
json=data,
|
|
42
|
+
status_code=200,
|
|
43
|
+
headers={"Content-Type": "application/json"},
|
|
44
|
+
)
|
|
45
|
+
actions.run(source)
|
|
46
|
+
source.reload()
|
|
47
|
+
assert source.get_last_job().status == "done"
|
|
48
|
+
|
|
49
|
+
datasets = Dataset.objects.filter(organization=org)
|
|
50
|
+
assert len(datasets) > 0
|
|
51
|
+
|
|
52
|
+
dataset = datasets.get(**{"harvest__remote_id": "04be6288-696d-4331-850d-a144871a7e3a"})
|
|
53
|
+
assert dataset.harvest.created_at == datetime(2019, 12, 10, 0, 0)
|
|
54
|
+
assert dataset.harvest.modified_at == datetime(2019, 9, 30, 0, 0)
|
|
55
|
+
assert len(dataset.resources) == 2
|
|
56
|
+
assert "xlsx" in [r.format for r in dataset.resources]
|
|
@@ -16,6 +16,7 @@ from udata.core.dataset.models import HarvestDatasetMetadata
|
|
|
16
16
|
from udata.core.organization.factories import OrganizationFactory
|
|
17
17
|
from udata.core.user.factories import UserFactory
|
|
18
18
|
from udata.models import Dataset, PeriodicTask
|
|
19
|
+
from udata.tests.api import PytestOnlyDBTestCase
|
|
19
20
|
from udata.tests.helpers import assert_emit, assert_equal_dates, assert_not_emit
|
|
20
21
|
from udata.utils import faker
|
|
21
22
|
|
|
@@ -40,12 +41,8 @@ from .factories import (
|
|
|
40
41
|
|
|
41
42
|
log = logging.getLogger(__name__)
|
|
42
43
|
|
|
43
|
-
pytestmark = [
|
|
44
|
-
pytest.mark.usefixtures("clean_db"),
|
|
45
|
-
]
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
class HarvestActionsTest:
|
|
45
|
+
class HarvestActionsTest(PytestOnlyDBTestCase):
|
|
49
46
|
def test_list_backends(self):
|
|
50
47
|
for backend in actions.list_backends():
|
|
51
48
|
assert issubclass(backend, BaseBackend)
|
|
@@ -453,7 +450,10 @@ class HarvestActionsTest:
|
|
|
453
450
|
assert result.errors == 1
|
|
454
451
|
|
|
455
452
|
|
|
456
|
-
class ExecutionTestMixin(MockBackendsMixin):
|
|
453
|
+
class ExecutionTestMixin(MockBackendsMixin, PytestOnlyDBTestCase):
|
|
454
|
+
def action(self, *args, **kwargs):
|
|
455
|
+
raise NotImplementedError
|
|
456
|
+
|
|
457
457
|
def test_default(self):
|
|
458
458
|
org = OrganizationFactory()
|
|
459
459
|
source = HarvestSourceFactory(backend="factory", organization=org)
|
|
@@ -610,7 +610,7 @@ class HarvestRunTest(ExecutionTestMixin):
|
|
|
610
610
|
return actions.run(*args, **kwargs)
|
|
611
611
|
|
|
612
612
|
|
|
613
|
-
class HarvestPreviewTest(MockBackendsMixin):
|
|
613
|
+
class HarvestPreviewTest(MockBackendsMixin, PytestOnlyDBTestCase):
|
|
614
614
|
def test_preview(self):
|
|
615
615
|
org = OrganizationFactory()
|
|
616
616
|
source = HarvestSourceFactory(backend="factory", organization=org)
|
udata/harvest/tests/test_api.py
CHANGED
|
@@ -8,6 +8,7 @@ from pytest_mock import MockerFixture
|
|
|
8
8
|
from udata.core.organization.factories import OrganizationFactory
|
|
9
9
|
from udata.core.user.factories import AdminFactory, UserFactory
|
|
10
10
|
from udata.models import Member, PeriodicTask
|
|
11
|
+
from udata.tests.api import PytestOnlyAPITestCase
|
|
11
12
|
from udata.tests.helpers import assert200, assert201, assert204, assert400, assert403, assert404
|
|
12
13
|
from udata.tests.plugin import ApiClient
|
|
13
14
|
from udata.utils import faker
|
|
@@ -25,10 +26,7 @@ from .factories import HarvestSourceFactory, MockBackendsMixin
|
|
|
25
26
|
log = logging.getLogger(__name__)
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
class HarvestAPITest(MockBackendsMixin):
|
|
30
|
-
modules = []
|
|
31
|
-
|
|
29
|
+
class HarvestAPITest(MockBackendsMixin, PytestOnlyAPITestCase):
|
|
32
30
|
def test_list_backends(self, api):
|
|
33
31
|
"""It should fetch the harvest backends list from the API"""
|
|
34
32
|
response = api.get(url_for("api.harvest_backends"))
|