From 59d71832fdaad896e57274f8823a2a704949bb7f Mon Sep 17 00:00:00 2001 From: glass-ships Date: Wed, 8 Nov 2023 12:26:37 -0700 Subject: [PATCH] update fixtures, add mapping tests --- backend/src/monarch_py/api/main.py | 4 +- .../implementations/solr/solr_parsers.py | 2 +- backend/tests/api/test_mapping_endpoint.py | 18 ++++ .../fixtures/association_counts_response.py | 2 +- backend/tests/fixtures/histopheno_response.py | 2 +- backend/tests/fixtures/mapping_query.py | 21 +++++ backend/tests/fixtures/mapping_response.py | 87 +++++++++++++++++++ backend/tests/fixtures/mappings.py | 75 ++++++++++++++++ backend/tests/fixtures/search_response.py | 2 +- backend/tests/unit/test_solr_parsers.py | 10 +++ backend/tests/unit/test_solr_queries.py | 7 ++ frontend/fixtures/mappings.json | 70 +++++++++++++++ scripts/generate_fixtures.py | 9 +- 13 files changed, 301 insertions(+), 8 deletions(-) create mode 100644 backend/tests/api/test_mapping_endpoint.py create mode 100644 backend/tests/fixtures/mapping_query.py create mode 100644 backend/tests/fixtures/mapping_response.py create mode 100644 backend/tests/fixtures/mappings.py create mode 100644 frontend/fixtures/mappings.json diff --git a/backend/src/monarch_py/api/main.py b/backend/src/monarch_py/api/main.py index 7bba7265a..1e0cbe98d 100644 --- a/backend/src/monarch_py/api/main.py +++ b/backend/src/monarch_py/api/main.py @@ -22,10 +22,10 @@ async def initialize_app(): CurieService() -app.include_router(entity.router, prefix=f"{PREFIX}/entity") app.include_router(association.router, prefix=f"{PREFIX}/association") -app.include_router(search.router, prefix=PREFIX) +app.include_router(entity.router, prefix=f"{PREFIX}/entity") app.include_router(histopheno.router, prefix=f"{PREFIX}/histopheno") +app.include_router(search.router, prefix=PREFIX) app.include_router(semsim.router, prefix=f"{PREFIX}/semsim") # Allow CORS diff --git a/backend/src/monarch_py/implementations/solr/solr_parsers.py b/backend/src/monarch_py/implementations/solr/solr_parsers.py index de054b77e..f2dcbae2a 100644 --- a/backend/src/monarch_py/implementations/solr/solr_parsers.py +++ b/backend/src/monarch_py/implementations/solr/solr_parsers.py @@ -170,7 +170,7 @@ def parse_autocomplete(query_result: SolrQueryResult) -> SearchResults: return SearchResults(limit=10, offset=0, total=total, items=items) -def parse_mappings(query_result: SolrQueryResult, offset: int, limit: int) -> MappingResults: +def parse_mappings(query_result: SolrQueryResult, offset: int = 0, limit: int = 20) -> MappingResults: total = query_result.response.num_found items = [] for doc in query_result.response.docs: diff --git a/backend/tests/api/test_mapping_endpoint.py b/backend/tests/api/test_mapping_endpoint.py new file mode 100644 index 000000000..6752c1a06 --- /dev/null +++ b/backend/tests/api/test_mapping_endpoint.py @@ -0,0 +1,18 @@ +from unittest.mock import MagicMock, patch + +from fastapi.testclient import TestClient +from httpx import Response +from monarch_py.api.search import router + +client = TestClient(router) + + +def test_mappings(search): + with patch.object( + client, "get", MagicMock(return_value=Response(200, json=search, headers={"content-type": "application/json"})) + ): + response = client.get("/mappings?entity_id=MONDO:0000015") + assert response.status_code == 200 + assert response.headers["content-type"] == "application/json" + assert response.json() == search + diff --git a/backend/tests/fixtures/association_counts_response.py b/backend/tests/fixtures/association_counts_response.py index b223b0016..8878112b5 100644 --- a/backend/tests/fixtures/association_counts_response.py +++ b/backend/tests/fixtures/association_counts_response.py @@ -5,7 +5,7 @@ def association_counts_response(): return { "responseHeader": { - "QTime": 1, + "QTime": 0, "params": { "facet.query": [ '(category:"biolink:DiseaseToPhenotypicFeatureAssociation") AND (subject:"MONDO:0020121" OR subject_closure:"MONDO:0020121")', diff --git a/backend/tests/fixtures/histopheno_response.py b/backend/tests/fixtures/histopheno_response.py index 44789afcf..67fb5632e 100644 --- a/backend/tests/fixtures/histopheno_response.py +++ b/backend/tests/fixtures/histopheno_response.py @@ -5,7 +5,7 @@ def histopheno_response(): return { "responseHeader": { - "QTime": 1, + "QTime": 2, "params": { "facet.query": [ 'object_closure:"HP:0000924"', diff --git a/backend/tests/fixtures/mapping_query.py b/backend/tests/fixtures/mapping_query.py new file mode 100644 index 000000000..10c157459 --- /dev/null +++ b/backend/tests/fixtures/mapping_query.py @@ -0,0 +1,21 @@ +import pytest + + +@pytest.fixture +def mapping_query(): + return { + "q": "*:*", + "rows": 20, + "start": 0, + "facet": True, + "facet_fields": [], + "facet_queries": [], + "filter_queries": ['subject_id:"MONDO\\:0020121" OR object_id:"MONDO\\:0020121"'], + "query_fields": None, + "def_type": "edismax", + "q_op": "AND", + "mm": "100%", + "boost": None, + "sort": None, + "facet_min_count": 1, + } diff --git a/backend/tests/fixtures/mapping_response.py b/backend/tests/fixtures/mapping_response.py new file mode 100644 index 000000000..7515868ce --- /dev/null +++ b/backend/tests/fixtures/mapping_response.py @@ -0,0 +1,87 @@ +import pytest + + +@pytest.fixture +def mapping_response(): + return { + "responseHeader": { + "QTime": 0, + "params": { + "mm": "100%", + "q": "*:*", + "defType": "edismax", + "facet_min_count": "1", + "start": "0", + "q.op": "AND", + "fq": 'subject_id:"MONDO\\:0020121" OR object_id:"MONDO\\:0020121"', + "rows": "20", + "facet": "true", + }, + }, + "response": { + "num_found": 7, + "start": 0, + "docs": [ + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "DOID:9884", + "object_label": "muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "cda26856-16a7-499c-956f-119cbaac5b96", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "ICD10CM:G71.0", + "object_label": "Muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "25777569-b997-4c8f-a1f3-5af352a16ee1", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "MESH:D009136", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "819ab197-2ab1-4b73-8d0f-d7d4ec14d8a7", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "NCIT:C84910", + "object_label": "Muscular Dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "adb4b8ed-c4dc-4353-a08e-a4cb02b1826e", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "SCTID:73297009", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "f6417283-c9d1-4289-aee6-16d30a4445b1", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "UMLS:C0026850", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "93968631-eedb-448b-b58a-e31e3e411dde", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "Orphanet:98473", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "e39e8ba9-8d7e-4b33-9f46-3867b652bdb5", + }, + ], + }, + "facet_counts": {"facet_fields": {}, "facet_queries": {}}, + } diff --git a/backend/tests/fixtures/mappings.py b/backend/tests/fixtures/mappings.py new file mode 100644 index 000000000..7d3e92885 --- /dev/null +++ b/backend/tests/fixtures/mappings.py @@ -0,0 +1,75 @@ +import pytest + + +@pytest.fixture +def mappings(): + return { + "limit": 20, + "offset": 0, + "total": 7, + "items": [ + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "DOID:9884", + "object_label": "muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "cda26856-16a7-499c-956f-119cbaac5b96", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "ICD10CM:G71.0", + "object_label": "Muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "25777569-b997-4c8f-a1f3-5af352a16ee1", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "MESH:D009136", + "object_label": None, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "819ab197-2ab1-4b73-8d0f-d7d4ec14d8a7", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "NCIT:C84910", + "object_label": "Muscular Dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "adb4b8ed-c4dc-4353-a08e-a4cb02b1826e", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "SCTID:73297009", + "object_label": None, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "f6417283-c9d1-4289-aee6-16d30a4445b1", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "UMLS:C0026850", + "object_label": None, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "93968631-eedb-448b-b58a-e31e3e411dde", + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "Orphanet:98473", + "object_label": None, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "e39e8ba9-8d7e-4b33-9f46-3867b652bdb5", + }, + ], + } diff --git a/backend/tests/fixtures/search_response.py b/backend/tests/fixtures/search_response.py index 5fbe50b82..c2791ef80 100644 --- a/backend/tests/fixtures/search_response.py +++ b/backend/tests/fixtures/search_response.py @@ -5,7 +5,7 @@ def search_response(): return { "responseHeader": { - "QTime": 1, + "QTime": 0, "params": { "mm": "100%", "q": "fanconi", diff --git a/backend/tests/unit/test_solr_parsers.py b/backend/tests/unit/test_solr_parsers.py index 352bbffce..cda34ac6b 100644 --- a/backend/tests/unit/test_solr_parsers.py +++ b/backend/tests/unit/test_solr_parsers.py @@ -7,6 +7,7 @@ parse_autocomplete, parse_entity, parse_histopheno, + parse_mappings, parse_search, ) from monarch_py.utils.utils import dict_diff @@ -65,3 +66,12 @@ def test_parse_autocomplete(autocomplete_response, autocomplete): assert ( parsed == autocomplete ), f"Parsed result is not as expected. Difference: {dict_diff(parsed.dict(), autocomplete)}" + + +def test_parse_mappings(mapping_response, mappings): + mapping_response["response"]["numFound"] = mapping_response["response"].pop("num_found") + solr_response = SolrQueryResult(**mapping_response) + parsed = parse_mappings(solr_response) + assert ( + parsed == mappings + ), f"Parsed result is not as expected. Difference: {dict_diff(parsed.dict(), mappings)}" \ No newline at end of file diff --git a/backend/tests/unit/test_solr_queries.py b/backend/tests/unit/test_solr_queries.py index 64c58844f..0e6c75a42 100644 --- a/backend/tests/unit/test_solr_queries.py +++ b/backend/tests/unit/test_solr_queries.py @@ -5,6 +5,7 @@ build_association_query, build_autocomplete_query, build_histopheno_query, + build_mapping_query, build_search_query, ) from monarch_py.utils.utils import compare_dicts, dict_diff @@ -111,3 +112,9 @@ def test_build_autocomplete_query(autocomplete_query): query = build_autocomplete_query(q="fanc").dict() expected = autocomplete_query assert compare_dicts(query, expected), f"Query is not as expected. Difference: {dict_diff(query, expected)}" + + +def test_build_mappings_query(mapping_query): + query = build_mapping_query(entity_id=["MONDO:0020121"]).dict() + expected = mapping_query + assert compare_dicts(query, expected), f"Query is not as expected. Difference: {dict_diff(query, expected)}" diff --git a/frontend/fixtures/mappings.json b/frontend/fixtures/mappings.json new file mode 100644 index 000000000..016753b75 --- /dev/null +++ b/frontend/fixtures/mappings.json @@ -0,0 +1,70 @@ +{ + "limit": 20, + "offset": 0, + "total": 7, + "items": [ + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "DOID:9884", + "object_label": "muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "cda26856-16a7-499c-956f-119cbaac5b96" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "ICD10CM:G71.0", + "object_label": "Muscular dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "25777569-b997-4c8f-a1f3-5af352a16ee1" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "MESH:D009136", + "object_label": null, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "819ab197-2ab1-4b73-8d0f-d7d4ec14d8a7" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "NCIT:C84910", + "object_label": "Muscular Dystrophy", + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "adb4b8ed-c4dc-4353-a08e-a4cb02b1826e" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "SCTID:73297009", + "object_label": null, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "f6417283-c9d1-4289-aee6-16d30a4445b1" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "UMLS:C0026850", + "object_label": null, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "93968631-eedb-448b-b58a-e31e3e411dde" + }, + { + "subject_id": "MONDO:0020121", + "subject_label": "muscular dystrophy", + "predicate_id": "skos:exactMatch", + "object_id": "Orphanet:98473", + "object_label": null, + "mapping_justification": "semapv:UnspecifiedMatching", + "id": "e39e8ba9-8d7e-4b33-9f46-3867b652bdb5" + } + ] +} diff --git a/scripts/generate_fixtures.py b/scripts/generate_fixtures.py index ddf39b26c..6939e22fc 100644 --- a/scripts/generate_fixtures.py +++ b/scripts/generate_fixtures.py @@ -9,15 +9,16 @@ from monarch_py.implementations.solr.solr_query_utils import ( build_association_query, build_association_counts_query, + build_association_table_query, build_autocomplete_query, build_histopheno_query, + build_mapping_query, build_search_query, - build_association_table_query, ) from monarch_py.service.solr_service import SolrService, core from monarch_py.utils.utils import format_output -from pprint import pprint as pp +# from pprint import pprint as pp ### Define variables oak = OakImplementation() @@ -26,6 +27,7 @@ solr_url = os.getenv("MONARCH_SOLR_URL", "http://localhost:8983/solr") solr_entities = SolrService(base_url=solr_url, core=core.ENTITY) solr_associations = SolrService(base_url=solr_url, core=core.ASSOCIATION) +solr_mappings = SolrService(base_url=solr_url, core=core.SSSOM) root = Path(__file__).parent.parent frontend_fixture_dir = Path(root) / "frontend" / "fixtures" @@ -192,6 +194,7 @@ def main( fixtures["histopheno"] = si.get_histopheno(node_id) fixtures["entity"] = si.get_entity(id=node_id, extra=False) fixtures["node"] = si.get_entity(id=node_id, extra=True) + fixtures["mappings"] = si.get_mappings(entity_id=node_id) # fixtures['node-publication-abstract'] = # fixtures['node-publication-summary'] = # fixtures['ontologies'] = @@ -227,6 +230,7 @@ def main( ) extra_fixtures["autocomplete-query"] = build_autocomplete_query(q="fanc") extra_fixtures["histopheno-query"] = build_histopheno_query(subject_closure=node_id) + extra_fixtures["mapping-query"] = build_mapping_query(entity_id=[node_id]) extra_fixtures["search-query"] = build_search_query(q="fanconi") # solr doc fixtures @@ -240,6 +244,7 @@ def main( extra_fixtures["autocomplete-response"] = solr_entities.query(extra_fixtures["autocomplete-query"]) extra_fixtures["entity-response"] = solr_entities.get(node_id) extra_fixtures["histopheno-response"] = solr_associations.query(extra_fixtures["histopheno-query"]) + extra_fixtures["mapping-response"] = solr_mappings.query(extra_fixtures["mapping-query"]) extra_fixtures["search-response"] = solr_entities.query(extra_fixtures["search-query"]) ### Write frontend fixtures