Skip to content

Commit 77da554

Browse files
committed
test&bugfix(all): start test of interface with ETS, fix a bug in DwCA export
1 parent 381b963 commit 77da554

File tree

8 files changed

+205
-92
lines changed

8 files changed

+205
-92
lines changed

QA/py/pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[pytest]
22
asyncio_mode = auto
3-
asyncio_default_fixture_loop_scope = function
3+
asyncio_default_fixture_loop_scope = module

QA/py/tests/api_wrappers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def api_file_import(
2727
return rsp
2828

2929

30-
def api_wait_for_stable_job(fastapi, job_id, max_wait=200):
30+
def api_wait_for_stable_job(fastapi, job_id, max_wait=300):
3131
url = JOB_QUERY_URL.format(job_id=job_id)
3232
waited = 0
3333
while True:

QA/py/tests/emodnet_ref.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,21 @@
252252
m106_mn04_n6_sml m106_mn04_n6_sml m106_mn04_n6_sml_78418 MachineObservation Oncaeidae urn:lsid:marinespecies.org:taxname:128586 Animalia present
253253
m106_mn04_n6_sml m106_mn04_n6_sml m106_mn04_n6_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia present
254254
"""
255-
_occurence_with_absent = ""
255+
_occurence_with_absent = r"""m106_mn01_n1_sml m106_mn01_n1_sml m106_mn01_n1_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
256+
m106_mn01_n2_sml m106_mn01_n2_sml m106_mn01_n2_sml_45072 MachineObservation Cyclopoida urn:lsid:marinespecies.org:taxname:1101 Animalia absent
257+
m106_mn01_n2_sml m106_mn01_n2_sml m106_mn01_n2_sml_78418 MachineObservation Oncaeidae urn:lsid:marinespecies.org:taxname:128586 Animalia absent
258+
m106_mn01_n2_sml m106_mn01_n2_sml m106_mn01_n2_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
259+
m106_mn01_n3_sml m106_mn01_n3_sml m106_mn01_n3_sml_45072 MachineObservation Cyclopoida urn:lsid:marinespecies.org:taxname:1101 Animalia absent
260+
m106_mn01_n3_sml m106_mn01_n3_sml m106_mn01_n3_sml_78418 MachineObservation Oncaeidae urn:lsid:marinespecies.org:taxname:128586 Animalia absent
261+
{p1}_m106_mn04_n4_sml {p1}_m106_mn04_n4_sml {p1}_m106_mn04_n4_sml_45072 MachineObservation Cyclopoida urn:lsid:marinespecies.org:taxname:1101 Animalia absent
262+
{p1}_m106_mn04_n4_sml {p1}_m106_mn04_n4_sml {p1}_m106_mn04_n4_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
263+
m106_mn04_n5_sml m106_mn04_n5_sml m106_mn04_n5_sml_45072 MachineObservation Cyclopoida urn:lsid:marinespecies.org:taxname:1101 Animalia absent
264+
m106_mn04_n5_sml m106_mn04_n5_sml m106_mn04_n5_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
265+
m106_mn04_n6_sml m106_mn04_n6_sml m106_mn04_n6_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
266+
{p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml_45072 MachineObservation Cyclopoida urn:lsid:marinespecies.org:taxname:1101 Animalia absent
267+
{p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml_78418 MachineObservation Oncaeidae urn:lsid:marinespecies.org:taxname:128586 Animalia absent
268+
{p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml {p2}_m106_mn04_n4_sml_56693 MachineObservation Actinopterygii urn:lsid:marinespecies.org:taxname:10194 Animalia absent
269+
"""
256270
_emofs = r"""
257271
id occurrenceID measurementValue measurementType measurementUnit measurementValueID measurementTypeID measurementUnitID
258272
m106_mn01_n1_sml m106_mn01_n1_sml_1 2 Count (in assayed sample) of biological entity specified elsewhere http://vocab.nerc.ac.uk/collection/P01/current/OCOUNT01/

QA/py/tests/test_export_emodnet.py

Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
# noinspection PyPackageRequirements
55
from io import BytesIO
6+
from typing import Any, Dict, List, Union
67
from zipfile import ZipFile
78

89
import pytest
910
from starlette import status
11+
from starlette.testclient import TestClient
1012

1113
from tests.api_wrappers import (
1214
api_wait_for_stable_job,
@@ -94,12 +96,7 @@ def exportable_collection(fastapi, admin_or_creator):
9496
"with_computations": ["ABO", "CNC", "BIV"],
9597
}
9698
)
97-
rsp = fastapi.post(
98-
COLLECTION_EXPORT_EMODNET_URL, headers=admin_or_creator, json=req
99-
)
100-
assert rsp.status_code == status.HTTP_200_OK
101-
job_id = rsp.json()["job_id"]
102-
api_wait_for_stable_job(fastapi, job_id)
99+
job_id = export_collection(fastapi, req, admin_or_creator)
103100
rsp = api_check_job_failed(fastapi, job_id, "5 error(s) during run")
104101
json = rsp.json()
105102
assert json["errors"] == [
@@ -139,58 +136,84 @@ def exportable_collection(fastapi, admin_or_creator):
139136
add_concentration_data(fastapi, prj_id, "mn04")
140137

141138
# Update the collection to fill in missing data
142-
url = COLLECTION_QUERY_URL.format(collection_id=coll_id)
143-
rsp = fastapi.get(url, headers=admin_or_creator)
144-
assert rsp.status_code == status.HTTP_200_OK
145-
the_coll = rsp.json()
146-
url = COLLECTION_UPDATE_URL.format(collection_id=coll_id)
147-
the_coll[
148-
"abstract"
149-
] = """
139+
def update_cb(the_coll):
140+
the_coll[
141+
"abstract"
142+
] = """
150143
This series is part of the long term planktonic monitoring of
151144
# Villefranche-sur-mer, which is one of the oldest and richest in the world.
152145
# The data collection and processing has been funded by several projects
153146
# over its lifetime. It is currently supported directly by the Institut de la Mer
154147
# de Villefranche (IMEV), as part of its long term monitoring effort.
155148
"""
156-
the_coll["license"] = (
157-
"CC BY 4.0" # Would do nothing as the license comes from the underlying project
149+
the_coll["license"] = (
150+
"CC BY 4.0" # Would do nothing as the license comes from the underlying project
151+
)
152+
user_doing_all = {
153+
"id": REAL_USER_ID,
154+
# TODO: below is redundant with ID and ignored, but fails validation (http 422) if not set
155+
"email": "creator",
156+
"name": "User Creating Projects",
157+
"organisation": "OrgTest",
158+
}
159+
the_coll["creator_users"] = [user_doing_all]
160+
the_coll["creator_organisations"] = [
161+
"Institut de la Mer de Villefranche (IMEV)"
162+
]
163+
the_coll["contact_user"] = {
164+
"id": ORDINARY_USER3_USER_ID,
165+
# TODO: below is redundant with ID and ignored, but fails validation (http 422) if not set
166+
"email": "?",
167+
"name": ".",
168+
"organisation": "OrgTest",
169+
}
170+
the_coll["provider_user"] = user_doing_all
171+
172+
the_coll = update_collection(fastapi, coll_id, admin_or_creator, update_cb)
173+
174+
# Read-back for org Ids, we cannot fix creators order without them
175+
def update_cb2(read):
176+
station_id = read["creator_organisations"][0]["id"]
177+
real_user_id = read["creator_users"][0]["id"]
178+
read["display_order"] = { # This is EML order
179+
"creators": [f"{real_user_id}_u", f"{station_id}_o"],
180+
}
181+
182+
update_collection(fastapi, coll_id, admin_or_creator, update_cb2)
183+
184+
# Store in ref
185+
all_colls[str(admin_or_creator)] = the_coll
186+
yield the_coll
187+
188+
189+
def export_collection(
190+
fastapi: TestClient,
191+
req: Dict[str, Union[None, bool, List[Any], Dict[str, str], List[str]]],
192+
admin_or_creator,
193+
) -> Any:
194+
rsp = fastapi.post(
195+
COLLECTION_EXPORT_EMODNET_URL, headers=admin_or_creator, json=req
158196
)
159-
user_doing_all = {
160-
"id": REAL_USER_ID,
161-
# TODO: below is redundant with ID and ignored, but fails validation (http 422) if not set
162-
"email": "creator",
163-
"name": "User Creating Projects",
164-
"organisation": "OrgTest",
165-
}
166-
the_coll["creator_users"] = [user_doing_all]
167-
the_coll["creator_organisations"] = ["Institut de la Mer de Villefranche (IMEV)"]
168-
the_coll["contact_user"] = {
169-
"id": ORDINARY_USER3_USER_ID,
170-
# TODO: below is redundant with ID and ignored, but fails validation (http 422) if not set
171-
"email": "?",
172-
"name": ".",
173-
"organisation": "OrgTest",
174-
}
175-
the_coll["provider_user"] = user_doing_all
176-
rsp = fastapi.put(url, headers=admin_or_creator, json=the_coll)
177197
assert rsp.status_code == status.HTTP_200_OK
178-
# Read-back for org Ids, we cannot fix creators order without them
198+
job_id = rsp.json()["job_id"]
199+
assert rsp.json()["errors"] == []
200+
api_wait_for_stable_job(fastapi, job_id)
201+
return job_id
202+
203+
204+
def update_collection(fastapi, coll_id, who, callback):
205+
# Query
179206
url = COLLECTION_QUERY_URL.format(collection_id=coll_id)
180-
rsp = fastapi.get(url, headers=admin_or_creator)
207+
rsp = fastapi.get(url, headers=who)
181208
assert rsp.status_code == status.HTTP_200_OK
182-
read = rsp.json()
183-
station_id = read["creator_organisations"][0]["id"]
184-
real_user_id = read["creator_users"][0]["id"]
209+
the_coll = rsp.json()
210+
# Update
211+
callback(the_coll)
212+
# Put
185213
url = COLLECTION_UPDATE_URL.format(collection_id=coll_id)
186-
read["display_order"] = { # This is EML order
187-
"creators": [f"{real_user_id}_u", f"{station_id}_o"],
188-
}
189-
rsp = fastapi.put(url, headers=admin_or_creator, json=read)
214+
rsp = fastapi.put(url, headers=who, json=the_coll)
190215
assert rsp.status_code == status.HTTP_200_OK
191-
# Store in ref
192-
all_colls[str(admin_or_creator)] = the_coll
193-
yield the_coll
216+
return the_coll
194217

195218

196219
def make_project_exportable(prj_id, fastapi, who):
@@ -211,11 +234,7 @@ def test_emodnet_export(fastapi, exportable_collection, admin_or_creator, fixed_
211234
prj_id, prj_id2 = sorted(exportable_collection["project_ids"])
212235
req = _req_tmpl.copy()
213236
req.update({"collection_id": coll_id, "with_computations": ["ABO", "CNC", "BIV"]})
214-
rsp = fastapi.post(
215-
COLLECTION_EXPORT_EMODNET_URL, headers=admin_or_creator, json=req
216-
)
217-
assert rsp.status_code == status.HTTP_200_OK
218-
job_id = rsp.json()["job_id"]
237+
job_id = export_collection(fastapi, req, admin_or_creator)
219238
api_wait_for_stable_job(fastapi, job_id)
220239
job_status = api_check_job_ok(fastapi, job_id)
221240

@@ -261,17 +280,12 @@ def test_emodnet_export(fastapi, exportable_collection, admin_or_creator, fixed_
261280
"Stats: predicted:2 validated:19 produced to zip:21 not produced (M):0 not produced (P):0",
262281
]
263282
assert warns == ref_warns
264-
assert rsp.json()["errors"] == []
265-
# job_id = rsp.json()["job_id"]
266283

267284
# Download the result zip
268285
url = JOB_DOWNLOAD_URL.format(job_id=job_id)
269286
# Ensure it's not public
270287
rsp = fastapi.get(url)
271288
assert rsp.status_code == status.HTTP_403_FORBIDDEN
272-
# But the creator can get it
273-
# rsp = fastapi.get(url, headers=REAL_USER_AUTH)
274-
# assert rsp.status_code == status.HTTP_200_OK
275289

276290
# Admin/owner can get it
277291
rsp = fastapi.get(url, headers=admin_or_creator)
@@ -292,10 +306,7 @@ def test_emodnet_export_with_absent(
292306
"with_computations": ["ABO", "CNC", "BIV"],
293307
}
294308
)
295-
rsp = fastapi.post(COLLECTION_EXPORT_EMODNET_URL, headers=ADMIN_AUTH, json=req)
296-
assert rsp.status_code == status.HTTP_200_OK
297-
job_id = rsp.json()["job_id"]
298-
api_wait_for_stable_job(fastapi, job_id)
309+
job_id = export_collection(fastapi, req, ADMIN_AUTH)
299310
api_check_job_ok(fastapi, job_id)
300311
dl_url = JOB_DOWNLOAD_URL.format(job_id=job_id)
301312
rsp = fastapi.get(dl_url, headers=ADMIN_AUTH)
@@ -309,10 +320,7 @@ def test_emodnet_export_no_comp(
309320
prj_id, prj_id2 = sorted(exportable_collection["project_ids"])
310321
req = _req_tmpl.copy()
311322
req.update({"collection_id": coll_id})
312-
rsp = fastapi.post(COLLECTION_EXPORT_EMODNET_URL, headers=ADMIN_AUTH, json=req)
313-
assert rsp.status_code == status.HTTP_200_OK
314-
job_id = rsp.json()["job_id"]
315-
api_wait_for_stable_job(fastapi, job_id)
323+
job_id = export_collection(fastapi, req, ADMIN_AUTH)
316324
api_check_job_ok(fastapi, job_id)
317325
dl_url = JOB_DOWNLOAD_URL.format(job_id=job_id)
318326
rsp = fastapi.get(dl_url, headers=ADMIN_AUTH)
@@ -338,10 +346,7 @@ def test_emodnet_export_recast1(
338346
},
339347
}
340348
)
341-
rsp = fastapi.post(COLLECTION_EXPORT_EMODNET_URL, headers=ADMIN_AUTH, json=req)
342-
assert rsp.status_code == status.HTTP_200_OK
343-
job_id = rsp.json()["job_id"]
344-
api_wait_for_stable_job(fastapi, job_id)
349+
job_id = export_collection(fastapi, req, ADMIN_AUTH)
345350
job_status = api_check_job_ok(fastapi, job_id)
346351
assert "wrns" in job_status["result"], job_status
347352
warns = job_status["result"]["wrns"]
@@ -370,10 +375,7 @@ def test_emodnet_export_recast2(
370375
},
371376
}
372377
)
373-
rsp = fastapi.post(COLLECTION_EXPORT_EMODNET_URL, headers=ADMIN_AUTH, json=req)
374-
assert rsp.status_code == status.HTTP_200_OK
375-
job_id = rsp.json()["job_id"]
376-
api_wait_for_stable_job(fastapi, job_id)
378+
job_id = export_collection(fastapi, req, ADMIN_AUTH)
377379
job_status = api_check_job_ok(fastapi, job_id)
378380
warns = job_status["result"]["wrns"]
379381
assert "Not produced due to non-match" not in str(warns)

QA/py/tests/test_taxoserver.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from starlette import status
2+
3+
SEARCH_WORMS_URL = "/searchworms/{}"
4+
5+
ACARTIA_RSP = [
6+
{
7+
"aphia_id": 104108,
8+
"name": "Acartia",
9+
"rank": "Genus",
10+
"status": "accepted",
11+
"lineage": {
12+
"104108": {
13+
"AphiaID": 104074,
14+
"rank": "Family",
15+
"scientificname": "Acartiidae",
16+
},
17+
"104074": {"AphiaID": 1100, "rank": "Order", "scientificname": "Calanoida"},
18+
"1100": {
19+
"AphiaID": 155877,
20+
"rank": "Superorder",
21+
"scientificname": "Gymnoplea",
22+
},
23+
"155877": {
24+
"AphiaID": 155876,
25+
"rank": "Infraclass",
26+
"scientificname": "Neocopepoda",
27+
},
28+
"155876": {"AphiaID": 1080, "rank": "Class", "scientificname": "Copepoda"},
29+
"1080": {
30+
"AphiaID": 845959,
31+
"rank": "Superclass",
32+
"scientificname": "Multicrustacea",
33+
},
34+
"845959": {
35+
"AphiaID": 1066,
36+
"rank": "Subphylum",
37+
"scientificname": "Crustacea",
38+
},
39+
"1066": {"AphiaID": 1065, "rank": "Phylum", "scientificname": "Arthropoda"},
40+
"1065": {"AphiaID": 2, "rank": "Kingdom", "scientificname": "Animalia"},
41+
"2": {"AphiaID": 1, "rank": "Superdomain", "scientificname": "Biota"},
42+
},
43+
"id": 80116,
44+
}
45+
]
46+
47+
48+
def test_search_worms_name(fastapi, mocker):
49+
# Mock the 'call' method of EcoTaxoServerClient
50+
mock_call = mocker.patch("providers.EcoTaxoServer.EcoTaxoServerClient.call")
51+
mock_response = mocker.Mock()
52+
mock_response.json.return_value = ACARTIA_RSP
53+
mock_call.return_value = mock_response
54+
55+
url = SEARCH_WORMS_URL.format("Acartia")
56+
# Unauthenticated call
57+
rsp = fastapi.get(url)
58+
assert rsp.status_code == status.HTTP_200_OK
59+
assert rsp.json() == ACARTIA_RSP
60+
61+
# Verify the mock was called correctly
62+
mock_call.assert_called_with("/wormstaxon/Acartia", {}, "get")

QA/py/tools/dbBuildSQL.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ def create(self):
248248
MAILSERVICE_SALT = "mailservice_salt"
249249
SENDER_ACCOUNT = senderemail@testsendermailtest.com,senderpwd,senderdns
250250
TAXOSERVER_URL = http://ecotaxoserver.dev.com
251+
TAXOSERVER_INSTANCE_ID = 123455
252+
TAXOSERVER_SHARED_SECRET = qsdf3fsdtre5665TY
251253
INSTANCE_ID = EcoTaxa.01
252254
USER_EMAIL_VERIFICATION = off
253255
ACCOUNT_VALIDATION = off

0 commit comments

Comments
 (0)