Skip to content

Commit cf89e6e

Browse files
committed
test: update and add unit tests aligned with new score set update flow
Revise existing tests and introduce new ones to cover optional update model and multipart handling. Ensures regression coverage for newly added endpoint behaviors.
1 parent 7fe4ed8 commit cf89e6e

File tree

8 files changed

+195
-15
lines changed

8 files changed

+195
-15
lines changed

src/mavedb/view_models/score_set_dataset_columns.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ class DatasetColumnsBase(BaseModel):
2525
def validate_dataset_columns_metadata(cls, v: Optional[dict[str, DatasetColumnMetadata]]) -> Optional[dict[str, DatasetColumnMetadata]]:
2626
if not v:
2727
return None
28-
DatasetColumnMetadata.model_validate(v)
28+
for val in v.values():
29+
DatasetColumnMetadata.model_validate(val)
2930
return v
3031

3132
@model_validator(mode="after")

tests/helpers/constants.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@
696696
SAVED_MINIMAL_DATASET_COLUMNS = {
697697
"recordType": "DatasetColumns",
698698
"countColumns": [],
699-
"scoreColumns": ["score"],
699+
"scoreColumns": ["score", "s_0", "s_1"],
700700
}
701701

702702
TEST_SEQ_SCORESET = {
@@ -1082,6 +1082,19 @@
10821082
"officialCollections": [],
10831083
}
10841084

1085+
TEST_SCORE_SET_DATASET_COLUMNS = {
1086+
"score_columns": ["score", "s_0", "s_1"],
1087+
"count_columns": ["c_0", "c_1"],
1088+
"score_columns_metadata": {
1089+
"s_0": {"description": "s_0 description", "details": "s_0 details"},
1090+
"s_1": {"description": "s_1 description", "details": "s_1 details"},
1091+
},
1092+
"count_columns_metadata": {
1093+
"c_0": {"description": "c_0 description", "details": "c_0 details"},
1094+
"c_1": {"description": "c_1 description", "details": "c_1 details"},
1095+
},
1096+
}
1097+
10851098
TEST_NT_CDOT_TRANSCRIPT = {
10861099
"start_codon": 0,
10871100
"stop_codon": 18,

tests/helpers/util/score_set.py

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,18 @@ def create_multi_target_score_set(
8888

8989

9090
def create_seq_score_set_with_mapped_variants(
91-
client, db, data_provider, experiment_urn, scores_csv_path, update=None, counts_csv_path=None
91+
client,
92+
db,
93+
data_provider,
94+
experiment_urn,
95+
scores_csv_path,
96+
update=None,
97+
counts_csv_path=None,
98+
score_columns_metadata_json_path=None,
99+
count_columns_metadata_json_path=None
92100
):
93101
score_set = create_seq_score_set_with_variants(
94-
client, db, data_provider, experiment_urn, scores_csv_path, update, counts_csv_path
102+
client, db, data_provider, experiment_urn, scores_csv_path, update, counts_csv_path, score_columns_metadata_json_path, count_columns_metadata_json_path
95103
)
96104
score_set = mock_worker_vrs_mapping(client, db, score_set)
97105

@@ -100,10 +108,18 @@ def create_seq_score_set_with_mapped_variants(
100108

101109

102110
def create_acc_score_set_with_mapped_variants(
103-
client, db, data_provider, experiment_urn, scores_csv_path, update=None, counts_csv_path=None
111+
client,
112+
db,
113+
data_provider,
114+
experiment_urn,
115+
scores_csv_path,
116+
update=None,
117+
counts_csv_path=None,
118+
score_columns_metadata_json_path=None,
119+
count_columns_metadata_json_path=None
104120
):
105121
score_set = create_acc_score_set_with_variants(
106-
client, db, data_provider, experiment_urn, scores_csv_path, update, counts_csv_path
122+
client, db, data_provider, experiment_urn, scores_csv_path, update, counts_csv_path, score_columns_metadata_json_path, count_columns_metadata_json_path
107123
)
108124
score_set = mock_worker_vrs_mapping(client, db, score_set)
109125

@@ -112,10 +128,20 @@ def create_acc_score_set_with_mapped_variants(
112128

113129

114130
def create_seq_score_set_with_variants(
115-
client, db, data_provider, experiment_urn, scores_csv_path, update=None, counts_csv_path=None
131+
client,
132+
db,
133+
data_provider,
134+
experiment_urn,
135+
scores_csv_path,
136+
update=None,
137+
counts_csv_path=None,
138+
score_columns_metadata_json_path=None,
139+
count_columns_metadata_json_path=None
116140
):
117141
score_set = create_seq_score_set(client, experiment_urn, update)
118-
score_set = mock_worker_variant_insertion(client, db, data_provider, score_set, scores_csv_path, counts_csv_path)
142+
score_set = mock_worker_variant_insertion(
143+
client, db, data_provider, score_set, scores_csv_path, counts_csv_path, score_columns_metadata_json_path, count_columns_metadata_json_path
144+
)
119145

120146
assert (
121147
score_set["numVariants"] == 3
@@ -126,10 +152,20 @@ def create_seq_score_set_with_variants(
126152

127153

128154
def create_acc_score_set_with_variants(
129-
client, db, data_provider, experiment_urn, scores_csv_path, update=None, counts_csv_path=None
155+
client,
156+
db,
157+
data_provider,
158+
experiment_urn,
159+
scores_csv_path,
160+
update=None,
161+
counts_csv_path=None,
162+
score_columns_metadata_json_path=None,
163+
count_columns_metadata_json_path=None
130164
):
131165
score_set = create_acc_score_set(client, experiment_urn, update)
132-
score_set = mock_worker_variant_insertion(client, db, data_provider, score_set, scores_csv_path, counts_csv_path)
166+
score_set = mock_worker_variant_insertion(
167+
client, db, data_provider, score_set, scores_csv_path, counts_csv_path, score_columns_metadata_json_path, count_columns_metadata_json_path
168+
)
133169

134170
assert (
135171
score_set["numVariants"] == 3
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"c_0": {
3+
"description": "c_0 description",
4+
"details": "c_0 details"
5+
},
6+
"c_1": {
7+
"description": "c_1 description",
8+
"details": "c_1 details"
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"s_0": {
3+
"description": "s_0 description",
4+
"details": "s_0 details"
5+
},
6+
"s_1": {
7+
"description": "s_0 description",
8+
"details": "s_0 details"
9+
}
10+
}

tests/routers/data/scores.csv

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
hgvs_nt,hgvs_pro,score
2-
c.1A>T,p.Thr1Ser,0.3
3-
c.2C>T,p.Thr1Met,1.0
4-
c.6T>A,p.Phe2Leu,-1.65
1+
hgvs_nt,hgvs_pro,score,s_0,s_1
2+
c.1A>T,p.Thr1Ser,0.3,val1,val1
3+
c.2C>T,p.Thr1Met,1.0,val2,val2
4+
c.6T>A,p.Phe2Leu,-1.65,val3,val3

tests/routers/test_score_set.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# ruff: noqa: E402
22

3+
import json
34
import re
45
from copy import deepcopy
56
import csv
@@ -400,6 +401,98 @@ def test_can_update_score_set_data_before_publication(
400401

401402
assert expected_response_data == response_data[camelize(attribute)]
402403

404+
@pytest.mark.parametrize(
405+
"attribute,updated_data,expected_response_data",
406+
[
407+
("title", "Updated Title", "Updated Title"),
408+
("method_text", "Updated Method Text", "Updated Method Text"),
409+
("abstract_text", "Updated Abstract Text", "Updated Abstract Text"),
410+
("short_description", "Updated Abstract Text", "Updated Abstract Text"),
411+
("extra_metadata", {"updated": "metadata"}, {"updated": "metadata"}),
412+
("data_usage_policy", "data_usage_policy", "data_usage_policy"),
413+
("contributors", [{"orcid_id": EXTRA_USER["username"]}], [SAVED_EXTRA_CONTRIBUTOR]),
414+
("primary_publication_identifiers", [{"identifier": TEST_PUBMED_IDENTIFIER}], [SAVED_PUBMED_PUBLICATION]),
415+
("secondary_publication_identifiers", [{"identifier": TEST_PUBMED_IDENTIFIER}], [SAVED_PUBMED_PUBLICATION]),
416+
("doi_identifiers", [{"identifier": TEST_CROSSREF_IDENTIFIER}], [SAVED_DOI_IDENTIFIER]),
417+
("license_id", EXTRA_LICENSE["id"], SAVED_SHORT_EXTRA_LICENSE),
418+
("target_genes", TEST_MINIMAL_ACC_SCORESET["targetGenes"], TEST_MINIMAL_ACC_SCORESET_RESPONSE["targetGenes"]),
419+
("score_ranges", TEST_SCORE_SET_RANGES_ALL_SCHEMAS_PRESENT, TEST_SAVED_SCORE_SET_RANGES_ALL_SCHEMAS_PRESENT),
420+
],
421+
)
422+
@pytest.mark.parametrize(
423+
"mock_publication_fetch",
424+
[({"dbName": "PubMed", "identifier": f"{TEST_PUBMED_IDENTIFIER}"})],
425+
indirect=["mock_publication_fetch"],
426+
)
427+
def test_can_patch_score_set_data_before_publication(
428+
client, setup_router_db, attribute, updated_data, expected_response_data, mock_publication_fetch
429+
):
430+
experiment = create_experiment(client)
431+
score_set = create_seq_score_set(client, experiment["urn"])
432+
expected_response = update_expected_response_for_created_resources(
433+
deepcopy(TEST_MINIMAL_SEQ_SCORESET_RESPONSE), experiment, score_set
434+
)
435+
expected_response["experiment"].update({"numScoreSets": 1})
436+
437+
response = client.get(f"/api/v1/score-sets/{score_set['urn']}")
438+
assert response.status_code == 200
439+
response_data = response.json()
440+
441+
assert sorted(expected_response.keys()) == sorted(response_data.keys())
442+
for key in expected_response:
443+
assert (key, expected_response[key]) == (key, response_data[key])
444+
445+
data = {}
446+
if isinstance(updated_data, (dict, list)):
447+
form_value = json.dumps(updated_data)
448+
else:
449+
form_value = str(updated_data)
450+
data[attribute] = form_value
451+
452+
response = client.patch(f"/api/v1/score-sets-with-variants/{score_set['urn']}", data=data)
453+
assert response.status_code == 200
454+
455+
response = client.get(f"/api/v1/score-sets/{score_set['urn']}")
456+
assert response.status_code == 200
457+
response_data = response.json()
458+
459+
# Although the client provides the license id, the response includes the full license.
460+
if attribute == "license_id":
461+
attribute = "license"
462+
463+
assert expected_response_data == response_data[camelize(attribute)]
464+
465+
@pytest.mark.parametrize(
466+
"form_field,filename,mime_type",
467+
[
468+
("scores_file", "scores.csv", "text/csv"),
469+
("counts_file", "counts.csv", "text/csv"),
470+
("score_columns_metadata_file", "score_columns_metadata.json", "application/json"),
471+
("count_columns_metadata_file", "count_columns_metadata.json", "application/json"),
472+
]
473+
)
474+
@pytest.mark.parametrize(
475+
"mock_publication_fetch",
476+
[({"dbName": "PubMed", "identifier": f"{TEST_PUBMED_IDENTIFIER}"})],
477+
indirect=["mock_publication_fetch"],
478+
)
479+
def test_can_patch_score_set_data_with_files_before_publication(
480+
client, setup_router_db, form_field, filename, mime_type,data_files, mock_publication_fetch
481+
):
482+
experiment = create_experiment(client)
483+
score_set = create_seq_score_set(client, experiment["urn"])
484+
expected_response = update_expected_response_for_created_resources(
485+
deepcopy(TEST_MINIMAL_SEQ_SCORESET_RESPONSE), experiment, score_set
486+
)
487+
expected_response["experiment"].update({"numScoreSets": 1})
488+
489+
data_file_path = data_files / filename
490+
files = {form_field: (filename, open(data_file_path, "rb"), mime_type)}
491+
with patch.object(arq.ArqRedis, "enqueue_job", return_value=None) as worker_queue:
492+
response = client.patch(f"/api/v1/score-sets-with-variants/{score_set['urn']}", files=files)
493+
worker_queue.assert_called_once()
494+
assert response.status_code == 200
495+
403496

404497
@pytest.mark.parametrize(
405498
"attribute,updated_data,expected_response_data",
@@ -415,7 +508,7 @@ def test_can_update_score_set_data_before_publication(
415508
("secondary_publication_identifiers", [{"identifier": TEST_PUBMED_IDENTIFIER}], [SAVED_PUBMED_PUBLICATION]),
416509
("doi_identifiers", [{"identifier": TEST_CROSSREF_IDENTIFIER}], [SAVED_DOI_IDENTIFIER]),
417510
("license_id", EXTRA_LICENSE["id"], SAVED_SHORT_EXTRA_LICENSE),
418-
("dataset_columns", {"countColumns": [], "scoreColumns": ["score"]}, SAVED_MINIMAL_DATASET_COLUMNS)
511+
("dataset_columns", None, SAVED_MINIMAL_DATASET_COLUMNS)
419512
],
420513
)
421514
@pytest.mark.parametrize(
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from mavedb.view_models.score_set_dataset_columns import DatasetColumnMetadata, SavedDatasetColumns
2+
from tests.helpers.constants import TEST_SCORE_SET_DATASET_COLUMNS
3+
4+
def test_score_set_dataset_columns():
5+
score_set_dataset_columns = TEST_SCORE_SET_DATASET_COLUMNS.copy()
6+
7+
for k, v in score_set_dataset_columns['score_columns_metadata'].items():
8+
score_set_dataset_columns['score_columns_metadata'][k] = DatasetColumnMetadata.model_validate(v)
9+
for k, v in score_set_dataset_columns['count_columns_metadata'].items():
10+
score_set_dataset_columns['count_columns_metadata'][k] = DatasetColumnMetadata.model_validate(v)
11+
12+
saved_score_set_dataset_columns = SavedDatasetColumns.model_validate(score_set_dataset_columns)
13+
14+
assert saved_score_set_dataset_columns.score_columns_metadata == score_set_dataset_columns['score_columns_metadata']
15+
assert saved_score_set_dataset_columns.count_columns_metadata == score_set_dataset_columns['count_columns_metadata']
16+
assert saved_score_set_dataset_columns.score_columns == score_set_dataset_columns['score_columns']
17+
assert saved_score_set_dataset_columns.count_columns == score_set_dataset_columns['count_columns']

0 commit comments

Comments
 (0)