Skip to content

Commit 573e511

Browse files
[NDR-282] Test virus scan behaviour in E2E upload tests (#845)
Co-authored-by: jameslinnell <[email protected]>
1 parent fe13922 commit 573e511

File tree

1 file changed

+162
-18
lines changed

1 file changed

+162
-18
lines changed

lambdas/tests/e2e/api/fhir/test_upload_document_fhir_api.py

Lines changed: 162 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import base64
22
import json
3+
import logging
34
import os
45

5-
from tests.e2e.conftest import APIM_ENDPOINT
6+
import pytest
7+
import requests
68

79
from lambdas.tests.e2e.api.fhir.conftest import (
810
MTLS_ENDPOINT,
@@ -13,7 +15,8 @@
1315

1416

1517
def create_upload_payload(pdm_record):
16-
sample_payload = {
18+
"""Helper to build DocumentReference payload."""
19+
payload = {
1720
"resourceType": "DocumentReference",
1821
"type": {
1922
"coding": [
@@ -55,38 +58,179 @@ def create_upload_payload(pdm_record):
5558
}
5659
],
5760
}
58-
5961
if "data" in pdm_record:
60-
sample_payload["content"][0]["attachment"]["data"] = pdm_record["data"]
61-
return json.dumps(sample_payload)
62+
payload["content"][0]["attachment"]["data"] = pdm_record["data"]
63+
return json.dumps(payload)
64+
65+
66+
def upload_document(session, payload):
67+
"""Helper to upload DocumentReference."""
68+
url = f"https://{MTLS_ENDPOINT}/DocumentReference"
69+
headers = {
70+
"Authorization": "Bearer 123",
71+
"X-Correlation-Id": "1234",
72+
}
73+
return session.post(url, headers=headers, data=payload)
74+
75+
76+
def retrieve_document_with_retry(session, doc_id, condition):
77+
"""Poll until condition is met on DocumentReference retrieval."""
78+
retrieve_url = f"https://{MTLS_ENDPOINT}/DocumentReference/{doc_id}"
79+
headers = {
80+
"Authorization": "Bearer 123",
81+
"X-Correlation-Id": "1234",
82+
}
83+
return fetch_with_retry_mtls(session, retrieve_url, headers, condition)
6284

6385

6486
def test_create_document_base64(test_data):
65-
pdm_record = {}
66-
pdm_record["ods"] = "H81109"
67-
pdm_record["nhs_number"] = "9912003071"
87+
pdm_record = {
88+
"ods": "H81109",
89+
"nhs_number": "9912003071",
90+
}
91+
6892
sample_pdf_path = os.path.join(os.path.dirname(__file__), "files", "dummy.pdf")
6993
with open(sample_pdf_path, "rb") as f:
7094
pdm_record["data"] = base64.b64encode(f.read()).decode("utf-8")
95+
payload = create_upload_payload(pdm_record)
96+
97+
session = create_mtls_session()
98+
raw_upload_response = upload_document(session, payload)
99+
assert raw_upload_response.status_code == 200
100+
101+
# Validate attachment URL
102+
upload_response = raw_upload_response.json()
103+
attachment_url = upload_response["content"][0]["attachment"]["url"]
104+
assert f"/DocumentReference/{PDM_SNOMED}~" in attachment_url
71105

106+
pdm_record["id"] = raw_upload_response.json()["id"].split("~")[1]
107+
test_data.append(pdm_record)
108+
109+
def condition(response_json):
110+
logging.info(response_json)
111+
return response_json["content"][0]["attachment"].get("data", False)
112+
113+
raw_retrieve_response = retrieve_document_with_retry(
114+
session, upload_response["id"], condition
115+
)
116+
retrieve_response = raw_retrieve_response.json()
117+
118+
# Validate base64 data
119+
base64_data = retrieve_response["content"][0]["attachment"]["data"]
120+
assert base64.b64decode(base64_data, validate=True)
121+
122+
123+
def test_create_document_presign_fails():
124+
pdm_record = {
125+
"ods": "H81109",
126+
"nhs_number": "9912003071",
127+
}
128+
129+
sample_pdf_path = os.path.join(os.path.dirname(__file__), "files", "big-dummy.pdf")
130+
with open(sample_pdf_path, "rb") as f:
131+
pdm_record["data"] = base64.b64encode(f.read()).decode("utf-8")
72132
payload = create_upload_payload(pdm_record)
73-
url = f"https://{MTLS_ENDPOINT}/DocumentReference"
74-
headers = {"Authorization": "Bearer 123"}
75133

76-
# Use mTLS
77134
session = create_mtls_session()
78-
retrieve_response = session.post(url, headers=headers, data=payload)
135+
upload_response = upload_document(session, payload)
136+
assert upload_response.status_code == 413
137+
assert upload_response.text == "HTTP content length exceeded 10485760 bytes."
138+
139+
140+
def test_create_document_virus(test_data):
141+
pdm_record = {
142+
"ods": "H81109",
143+
"nhs_number": "9730154260",
144+
}
145+
payload = create_upload_payload(pdm_record)
146+
session = create_mtls_session()
147+
148+
retrieve_response = upload_document(session, payload)
79149
upload_response = retrieve_response.json()
150+
80151
pdm_record["id"] = upload_response["id"].split("~")[1]
81152
test_data.append(pdm_record)
82153

83-
retrieve_url = f"https://{MTLS_ENDPOINT}/DocumentReference/{upload_response['id']}"
154+
# Presigned upload
155+
presign_uri = upload_response["content"][0]["attachment"]["url"]
156+
del upload_response["content"][0]["attachment"]["url"]
157+
sample_pdf_path = os.path.join(os.path.dirname(__file__), "files", "dummy.pdf")
158+
with open(sample_pdf_path, "rb") as f:
159+
presign_response = requests.put(presign_uri, files={"file": f})
160+
assert presign_response.status_code == 200
84161

85-
raw_retrieve_response = fetch_with_retry_mtls(session, retrieve_url, headers)
162+
def condition(response_json):
163+
logging.info(response_json)
164+
return response_json.get("docStatus", False) == "cancelled"
165+
166+
raw_retrieve_response = retrieve_document_with_retry(
167+
session, upload_response["id"], condition
168+
)
86169
retrieve_response = raw_retrieve_response.json()
87170

88-
attachment_url = upload_response["content"][0]["attachment"]["url"]
89-
assert (
90-
f"https://{APIM_ENDPOINT}/national-document-repository/DocumentReference/{PDM_SNOMED}~"
91-
in attachment_url
171+
assert retrieve_response["docStatus"] == "cancelled"
172+
173+
174+
@pytest.mark.parametrize(
175+
"nhs_number,expected_status,expected_code,expected_diagnostics",
176+
[
177+
(
178+
"9999999993",
179+
400,
180+
"VALIDATION_ERROR",
181+
"Failed to parse document upload request data",
182+
),
183+
(
184+
"123",
185+
400,
186+
"VALIDATION_ERROR",
187+
"Failed to parse document upload request data",
188+
),
189+
],
190+
)
191+
def test_search_edge_cases(
192+
nhs_number, expected_status, expected_code, expected_diagnostics
193+
):
194+
pdm_record = {
195+
"ods": "H81109",
196+
"nhs_number": f"{nhs_number}",
197+
}
198+
199+
sample_pdf_bytes = b"Sample PDF Content"
200+
pdm_record["data"] = base64.b64encode(sample_pdf_bytes).decode("utf-8")
201+
202+
payload = create_upload_payload(pdm_record)
203+
session = create_mtls_session()
204+
response = upload_document(session, payload)
205+
assert response.status_code == expected_status
206+
207+
body = response.json()
208+
issue = body["issue"][0]
209+
details = issue.get("details", {})
210+
coding = details.get("coding", [{}])[0]
211+
assert coding.get("code") == expected_code
212+
assert issue.get("diagnostics") == expected_diagnostics
213+
214+
215+
def test_forbidden_with_invalid_cert(temp_cert_and_key):
216+
pdm_record = {
217+
"ods": "H81109",
218+
"nhs_number": "9912003071",
219+
}
220+
221+
sample_pdf_bytes = b"Sample PDF Content"
222+
pdm_record["data"] = base64.b64encode(sample_pdf_bytes).decode("utf-8")
223+
224+
payload = create_upload_payload(pdm_record)
225+
226+
# Use an invalid cert that is trusted by TLS but fails truststore validation
227+
cert_path, key_path = temp_cert_and_key
228+
url = f"https://{MTLS_ENDPOINT}/DocumentReference"
229+
headers = {"Authorization": "Bearer 123", "X-Correlation-Id": "1234"}
230+
231+
response = requests.post(
232+
url, headers=headers, cert=(cert_path, key_path), data=payload
92233
)
234+
body = response.json()
235+
assert response.status_code == 403
236+
assert body["message"] == "Forbidden"

0 commit comments

Comments
 (0)