Skip to content

Commit 2f0b9ca

Browse files
Increasing data curation coverage (#637)
## Description A few small coverage gaps on `data-curation/`. I also noticed a small place in `validation/` tests where we should be using the constant. I had a local issue with validation; I had to remove and regenerate the .tmp files to get tests to work locally. This doesn't impact github actions since it regenerates the tests each time. I added a small cleanup ticket (https://app.zenhub.com/workspaces/dibbs-text-to-code-68756bf8ea06bb00319391c0/issues/gh/cdcgov/dibbs-text-to-code/638) to see if there's anything we can add locally to either regenerate the files with each run, or a check to determine if it should, but it could be overkill. ## Related Issues ## Additional Notes [Add any additional context or notes that reviewers should know about.] <--------------------- REMOVE THE LINES BELOW BEFORE MERGING ---------------------> ## Checklist Please review and complete the following checklist before submitting your pull request: - [ ] I have ensured that the pull request is of a manageable size, allowing it to be reviewed within a single session. - [ ] I have reviewed my changes to ensure they are clear, concise, and well-documented. - [ ] I have updated the documentation, if applicable. - [ ] I have added or updated test cases to cover my changes, if applicable. - [ ] I have minimized the number of reviewers to include only those essential for the review. ## Checklist for Reviewers Please review and complete the following checklist during the review process: - [ ] The code follows best practices and conventions. - [ ] The changes implement the desired functionality or fix the reported issue. - [ ] The tests cover the new changes and pass successfully. - [ ] Any potential edge cases or error scenarios have been considered.
1 parent 90b5dd5 commit 2f0b9ca

3 files changed

Lines changed: 129 additions & 4 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import pytest
2+
from requests.models import Response
3+
4+
from data_curation.terminologies import http_client
5+
from data_curation.terminologies.http_client import get_with_timeout
6+
7+
8+
def test_get_with_timeout_calls_requests_get_with_timeout(
9+
monkeypatch: pytest.MonkeyPatch,
10+
):
11+
response = Response()
12+
response.status_code = http_client.STATUS_CODE_OK
13+
calls: list[tuple[str, dict[str, object] | None, int | None, tuple[str, str] | None]] = []
14+
15+
def fake_get(
16+
url: str,
17+
params: dict[str, object] | None = None,
18+
timeout: int | None = None,
19+
auth: tuple[str, str] | None = None,
20+
) -> Response:
21+
calls.append((url, params, timeout, auth))
22+
23+
return response
24+
25+
monkeypatch.setattr(http_client.requests, "get", fake_get)
26+
27+
result = get_with_timeout(
28+
"https://example.com",
29+
params={"code": "1234-5"},
30+
auth=("user", "password"),
31+
)
32+
33+
assert result is response
34+
assert calls == [
35+
(
36+
"https://example.com",
37+
{"code": "1234-5"},
38+
60,
39+
("user", "password"),
40+
)
41+
]

packages/data-curation/tests/test_loinc.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,52 @@ def mock_save_valueset_csv_file(
9999
assert saved_files[0][2] is False
100100

101101

102+
def test_extract_full_loinc_lab_names_handles_empty_api_results(
103+
tmp_path: Path,
104+
monkeypatch: pytest.MonkeyPatch,
105+
capsys: pytest.CaptureFixture[str],
106+
) -> None:
107+
payload: dict[str, object] = {
108+
"ResponseSummary": {
109+
"RecordsFound": 0,
110+
"RowsReturned": 1,
111+
"Next": None,
112+
},
113+
"Results": [],
114+
}
115+
consumer_names_file = tmp_path / "consumer_names.csv"
116+
consumer_names_file.write_text(
117+
"LoincNumber|ConsumerName\n",
118+
encoding="utf-8",
119+
)
120+
saved_files: list[tuple[str, list[loinc.LoincRow], bool]] = []
121+
122+
def mock_get_with_timeout(
123+
api_url: str,
124+
auth: tuple[str, str] | None = None,
125+
) -> MockResponse:
126+
return MockResponse(200, payload)
127+
128+
def mock_save_valueset_csv_file(
129+
filename: str, contents: list[loinc.LoincRow], append_to_file: bool = False
130+
) -> None:
131+
saved_files.append((filename, contents, append_to_file))
132+
133+
monkeypatch.setattr(loinc, "LOINC_USERNAME", "username")
134+
monkeypatch.setattr(loinc, "LOINC_PWD", "password")
135+
monkeypatch.setattr(loinc, "LOINC_CS_NAMES", consumer_names_file)
136+
monkeypatch.setattr(loinc, "get_with_timeout", mock_get_with_timeout)
137+
monkeypatch.setattr(loinc, "save_valueset_csv_file", mock_save_valueset_csv_file)
138+
139+
loinc.extract_full_loinc_lab_names()
140+
141+
assert "NO RESULTS TO PROCESS!" in capsys.readouterr().out
142+
assert len(saved_files) == 1
143+
assert saved_files[0][0].startswith("loinc_lab_names_")
144+
assert saved_files[0][1] == []
145+
assert saved_files[0][2] is False
146+
147+
102148
def test_extract_full_loinc_lab_orders(monkeypatch: pytest.MonkeyPatch) -> None:
103149
rows = [_loinc_row()]
104150
saved_files: list[tuple[str, list[dict[str, str]], bool]] = []
@@ -405,6 +451,44 @@ def test_process_loinc_valueset_requires_credentials(monkeypatch: pytest.MonkeyP
405451
loinc._process_loinc_valueset("https://example.com", "Lab Names")
406452

407453

454+
def test_process_loincs_for_umls_urls_processes_api_response(
455+
monkeypatch: pytest.MonkeyPatch,
456+
) -> None:
457+
payload: dict[str, object] = {
458+
"ResponseSummary": {
459+
"RecordsFound": 1,
460+
"RowsReturned": 1,
461+
"Next": None,
462+
},
463+
"Results": [
464+
{
465+
"LOINC_NUM": "12345-F",
466+
"LONG_COMMON_NAME": "TEST LONG NAME",
467+
}
468+
],
469+
}
470+
471+
def mock_get_with_timeout(
472+
api_url: str,
473+
auth: tuple[str, str] | None = None,
474+
) -> MockResponse:
475+
return MockResponse(200, payload)
476+
477+
monkeypatch.setattr(loinc, "LOINC_USERNAME", "username")
478+
monkeypatch.setattr(loinc, "LOINC_PWD", "password")
479+
monkeypatch.setattr(loinc, "get_with_timeout", mock_get_with_timeout)
480+
481+
result = loinc.process_loincs_for_umls_urls()
482+
483+
assert result == {
484+
"12345-F": {
485+
"atom": loinc.UMLS_LOINC_LAB_ATOMS_URL + "12345-F/atoms",
486+
"crs": loinc.UMLS_LOINC_LAB_CROSSWALK_URL + "12345-F",
487+
"long_name": "TEST LONG NAME",
488+
}
489+
}
490+
491+
408492
def test_process_loincs_for_umls_urls(monkeypatch: pytest.MonkeyPatch) -> None:
409493
calls: dict[str, str] = {}
410494
expected = {

packages/validation/tests/test_validation.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self) -> None:
2929

3030
def get_attribute_value(self, attribute: str) -> str:
3131
values = {
32-
"id": "ttc-labOrder-code-missing",
32+
"id": LabTestNameOrderedSchematronErrors.MISSING_CODE_ATTRIBUTE.value,
3333
"location": FAKE_LOCATION,
3434
"test": FAKE_TEST,
3535
}
@@ -112,7 +112,7 @@ def test_validation():
112112

113113
assert results == [
114114
ValidationResult(
115-
error_id="ttc-labOrder-code-missing",
115+
error_id=LabTestNameOrderedSchematronErrors.MISSING_CODE_ATTRIBUTE.value,
116116
location="/Q{urn:hl7-org:v3}ClinicalDocument[1]/Q{urn:hl7-org:v3}component[1]/Q{urn:hl7-org:v3}structuredBody[1]/Q{urn:hl7-org:v3}component[1]/Q{urn:hl7-org:v3}section[1]/Q{urn:hl7-org:v3}entry[1]/Q{urn:hl7-org:v3}observation[1]",
117117
)
118118
]
@@ -151,7 +151,7 @@ def test_validation_redoes_all_steps(monkeypatch: pytest.MonkeyPatch, tmp_path:
151151
assert results == [
152152
ValidationResult(
153153
error_id=LabTestNameOrderedSchematronErrors.MISSING_CODE_ATTRIBUTE.value,
154-
location="/ClinicalDocument/component/structuredBody/component/section/entry/observation",
154+
location=FAKE_LOCATION,
155155
)
156156
]
157157
assert stage1_output.read_text() == "<generated />"
@@ -179,7 +179,7 @@ def test_validation_uses_existing_generated_files(monkeypatch: pytest.MonkeyPatc
179179
assert results == [
180180
ValidationResult(
181181
error_id=LabTestNameOrderedSchematronErrors.MISSING_CODE_ATTRIBUTE.value,
182-
location="/ClinicalDocument/component/structuredBody/component/section/entry/observation",
182+
location=FAKE_LOCATION,
183183
)
184184
]
185185
assert stage1_output.read_text() == "existing stage 1"

0 commit comments

Comments
 (0)