Skip to content

Commit 0eee2e3

Browse files
authored
Merge branch 'develop' into feature/eema1-NRL-703-ignoreSupersedeDeleteSyncPerm
2 parents 00e57d3 + 299a773 commit 0eee2e3

File tree

7 files changed

+233
-76
lines changed

7 files changed

+233
-76
lines changed

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ FEATURE_TEST_ARGS ?= ./tests/features --format progress2
1313
TF_WORKSPACE_NAME ?= $(shell terraform -chdir=terraform/infrastructure workspace show)
1414
ENV ?= dev
1515
APP_ALIAS ?= default
16+
HOST ?= $(TF_WORKSPACE_NAME).api.record-locator.$(ENV).national.nhs.uk
17+
ENV_TYPE ?= $(ENV)
1618

1719
export PATH := $(PATH):$(PWD)/.venv/bin
1820

@@ -85,15 +87,15 @@ test-performance-prepare:
8587
test-performance: check-warn test-performance-baseline test-performance-stress ## Run the performance tests
8688

8789
test-performance-baseline:
88-
@echo "Running performance baseline test"
90+
@echo "Running consumer performance baseline test"
8991
k6 run --out csv=$(DIST_PATH)/consumer-baseline.csv tests/performance/consumer/baseline.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
9092

9193
test-performance-stress:
92-
@echo "Running performance stress test"
94+
@echo "Running consumer performance stress test"
9395
k6 run --out csv=$(DIST_PATH)/consumer-stress.csv tests/performance/consumer/stress.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
9496

9597
test-performance-soak:
96-
@echo "Running performance soak test"
98+
@echo "Running consumer performance soak test"
9799
k6 run --out csv=$(DIST_PATH)/consumer-soak.csv tests/performance/consumer/soak.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
98100

99101
test-performance-output: ## Process outputs from the performance tests

tests/performance/constants.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@ export const DEFAULT_TEST_RECORD = open(
33
);
44
export const ODS_CODE = "Y05868";
55
export const REFERENCE_DATA = JSON.parse(open("./reference-data.json"));
6-
export const POINTER_IDS = REFERENCE_DATA["ids"];
6+
export const POINTER_DOCUMENTS =
7+
"documents" in REFERENCE_DATA ? REFERENCE_DATA["documents"] : {};
8+
export const ALL_POINTER_IDS =
9+
"pointer_ids" in REFERENCE_DATA
10+
? REFERENCE_DATA["pointer_ids"]
11+
: Object.keys(POINTER_DOCUMENTS);
12+
export const POINTERS_TO_DELETE = ALL_POINTER_IDS.slice(0, 3500);
13+
export const POINTER_IDS = ALL_POINTER_IDS.slice(3500);
714
export const NHS_NUMBERS = REFERENCE_DATA["nhs_numbers"];
815
export const POINTER_TYPES = [
9-
"http://snomed.info/sct|736253002",
10-
"http://snomed.info/sct|1363501000000100",
11-
"http://snomed.info/sct|1382601000000107",
12-
"http://snomed.info/sct|325691000000100",
13-
"http://snomed.info/sct|736373009",
14-
"http://snomed.info/sct|861421000000109",
15-
"http://snomed.info/sct|887701000000100",
16+
"736253002",
17+
"1363501000000100",
18+
"1382601000000107",
19+
"325691000000100",
20+
"736373009",
21+
"861421000000109",
22+
"887701000000100",
1623
];

tests/performance/consumer/client.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export function searchDocumentReference() {
7777
const identifier = encodeURIComponent(
7878
`https://fhir.nhs.uk/Id/nhs-number|${nhsNumber}`
7979
);
80-
const type = encodeURIComponent(pointer_type);
80+
const type = encodeURIComponent(`http://snomed.info/sct|${pointer_type}`);
8181

8282
const res = http.get(
8383
`https://${__ENV.HOST}/consumer/DocumentReference?subject:identifier=${identifier}&type=${type}`,
@@ -118,7 +118,7 @@ export function searchPostDocumentReference() {
118118

119119
const body = JSON.stringify({
120120
"subject:identifier": `https://fhir.nhs.uk/Id/nhs-number|${nhsNumber}`,
121-
type: pointer_type,
121+
type: `http://snomed.info/sct|${pointer_type}`,
122122
});
123123

124124
const res = http.post(

tests/performance/environment.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,30 +57,34 @@ def setup(
5757
patient_count: int = 100,
5858
documents_per_type: int = 10,
5959
ods_code: str = "Y05868",
60-
cleanup: bool = False,
6160
out: str = "tests/performance/reference-data.json",
61+
output_full_pointers: bool = False,
6262
):
6363
print(f"Creating Test Data in environment '{env}'")
6464

6565
print(f"Patient Count: {patient_count}")
6666
print(f"Documents Per Type: {documents_per_type}")
6767

6868
table = DYNAMODB.Table(f"nhsd-nrlf--{env}--document-pointer")
69-
document_ids = set()
69+
documents = {}
7070
nhs_numbers = set()
7171

7272
with table.batch_writer() as batch:
7373
for record in _generate_records(patient_count, documents_per_type, ods_code):
7474
pointer = DocumentPointer.from_document_reference(record)
7575
batch.put_item(Item=pointer.dict())
7676

77-
document_ids.add(pointer.id)
77+
documents[pointer.id] = record.dict(exclude_none=True)
7878
nhs_numbers.add(pointer.nhs_number)
7979

80-
print(
81-
f"Created {len(document_ids)} document pointers for {len(nhs_numbers)} patients"
82-
)
83-
output = json.dumps({"ids": list(document_ids), "nhs_numbers": list(nhs_numbers)})
80+
print(f"Created {len(documents)} documents for {len(nhs_numbers)} patients")
81+
82+
if output_full_pointers:
83+
output = json.dumps({"documents": documents, "nhs_numbers": list(nhs_numbers)})
84+
else:
85+
output = json.dumps(
86+
{"pointer_ids": list(documents.keys()), "nhs_numbers": list(nhs_numbers)}
87+
)
8488

8589
output_path = pathlib.Path(out)
8690
output_path.write_text(output)
@@ -91,10 +95,15 @@ def cleanup(env: str, input: str = "tests/performance/reference-data.json"):
9195
input_path = pathlib.Path(input)
9296
data = json.loads(input_path.read_text())
9397

94-
print(f"Cleaning up {len(data['ids'])} document pointers in environment '{env}'")
98+
if "documents" in data:
99+
pointer_ids = data["documents"].keys()
100+
else:
101+
pointer_ids = data["pointer_ids"]
102+
103+
print(f"Cleaning up {len(pointer_ids)} document pointers in environment '{env}'")
95104
table = DYNAMODB.Table(f"nhsd-nrlf--{env}--document-pointer")
96105
with table.batch_writer() as batch:
97-
for id in data["ids"]:
106+
for id in pointer_ids:
98107
ods_code, document_id = id.split("-", maxsplit=1)
99108
pk = f"D#{ods_code}#{document_id}"
100109
batch.delete_item(Key={"pk": pk, "sk": pk})
Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,28 @@
11
import http from "k6/http";
2-
import { ALL_POINTER_TYPES, ODS_CODE } from "../constants.js";
2+
import {
3+
POINTER_TYPES,
4+
ODS_CODE,
5+
NHS_NUMBERS,
6+
POINTER_IDS,
7+
POINTER_DOCUMENTS,
8+
POINTERS_TO_DELETE,
9+
} from "../constants.js";
310
import { check } from "k6";
11+
import { randomItem } from "https://jslib.k6.io/k6-utils/1.2.0/index.js";
12+
import { crypto } from "k6/experimental/webcrypto";
13+
import { createRecord } from "../setup.js";
414

515
function getBaseURL() {
616
return `https://${__ENV.HOST}/producer/DocumentReference`;
717
}
818

9-
function getHeaders(odsCode = ODS_CODE, pointerTypes = ALL_POINTER_TYPES) {
19+
function getHeaders(odsCode = ODS_CODE) {
1020
return {
1121
"Content-Type": "application/fhir+json",
1222
"NHSD-Connection-Metadata": JSON.stringify({
1323
"nrl.ods-code": odsCode,
14-
"nrl.pointer-types": Object.keys(pointerTypes).map(
15-
(pointerType) => `http://snomed.info/sct|${pointerType}`
24+
"nrl.pointer-types": POINTER_TYPES.map(
25+
(type) => `http://snomed.info/sct|${type}`
1626
),
1727
}),
1828
"NHSD-Client-RP-Details": JSON.stringify({
@@ -22,11 +32,121 @@ function getHeaders(odsCode = ODS_CODE, pointerTypes = ALL_POINTER_TYPES) {
2232
};
2333
}
2434

25-
export function createDocumentReference(document) {
26-
return http.post(getBaseURL(), document, { headers: getHeaders() });
35+
export function createDocumentReference() {
36+
const nhsNumber = randomItem(NHS_NUMBERS);
37+
const pointerType = randomItem(POINTER_TYPES);
38+
const record = createRecord(nhsNumber, pointerType);
39+
40+
const res = http.post(getBaseURL(), JSON.stringify(record), {
41+
headers: getHeaders(),
42+
});
43+
44+
check(res, { "create status is 201": (r) => r.status === 201 });
45+
46+
if (res.status !== 201) {
47+
console.warn(
48+
`Failed to create record: ${res.status}: ${
49+
JSON.parse(res.body).issue[0].diagnostics
50+
}`
51+
);
52+
}
2753
}
2854

29-
export function deleteDocumentReference(document_id) {
30-
const url = `${getBaseURL()}/${document_id}`;
31-
return http.del(url, { headers: getHeaders() });
55+
export function readDocumentReference() {
56+
const id = randomItem(POINTER_IDS);
57+
58+
const res = http.get(`${getBaseURL()}/${id}`, { headers: getHeaders() });
59+
60+
check(res, { "status is 200": (r) => r.status === 200 });
61+
}
62+
63+
export function updateDocumentReference() {
64+
const id = randomItem(POINTER_IDS);
65+
const document = POINTER_DOCUMENTS[id];
66+
67+
document.content[0].attachment.url = "https://example.com/k6-updated-url.pdf";
68+
69+
const res = http.put(`${getBaseURL()}/${id}`, JSON.stringify(document), {
70+
headers: getHeaders(),
71+
});
72+
73+
check(res, { "status is 200": (r) => r.status === 200 });
74+
}
75+
76+
export function deleteDocumentReference() {
77+
const id = randomItem(POINTERS_TO_DELETE);
78+
79+
const res = http.del(`${getBaseURL()}/${id}`, null, {
80+
headers: getHeaders(),
81+
});
82+
83+
check(res, { "delete status is 200": (r) => r.status === 200 });
84+
}
85+
86+
export function upsertDocumentReference() {
87+
const nhsNumber = randomItem(NHS_NUMBERS);
88+
const pointerType = randomItem(POINTER_TYPES);
89+
const record = createRecord(nhsNumber, pointerType);
90+
91+
record.id = `k6perf-${crypto.randomUUID()}`;
92+
93+
const res = http.post(getBaseURL(), JSON.stringify(record), {
94+
headers: getHeaders(),
95+
});
96+
97+
check(res, { "create status is 201": (r) => r.status === 201 });
98+
99+
if (res.status !== 201) {
100+
console.warn(
101+
`Failed to create record: ${res.status}: ${
102+
JSON.parse(res.body).issue[0].diagnostics
103+
}`
104+
);
105+
}
106+
}
107+
108+
export function searchDocumentReference() {
109+
const nhsNumber = randomItem(NHS_NUMBERS);
110+
const pointerType = randomItem(POINTER_TYPES);
111+
112+
const identifier = encodeURIComponent(
113+
`https://fhir.nhs.uk/Id/nhs-number|${nhsNumber}`
114+
);
115+
const type = encodeURIComponent(`http://snomed.info/sct|${pointerType}`);
116+
117+
const url = `${getBaseURL()}?subject:identifier=${identifier}&type=${type}`;
118+
119+
const res = http.get(url, {
120+
headers: getHeaders(),
121+
});
122+
123+
check(res, { "status is 200": (r) => r.status === 200 });
124+
125+
if (res.status !== 200) {
126+
console.log(
127+
`Search failed with ${res.status}: ${JSON.stringify(res.body)}`
128+
);
129+
}
130+
}
131+
132+
export function searchPostDocumentReference() {
133+
const nhsNumber = randomItem(NHS_NUMBERS);
134+
const pointerType = randomItem(POINTER_TYPES);
135+
136+
const body = JSON.stringify({
137+
"subject:identifier": `https://fhir.nhs.uk/Id/nhs-number|${nhsNumber}`,
138+
type: `http://snomed.info/sct|${pointerType}`,
139+
});
140+
141+
const res = http.post(`${getBaseURL()}/_search`, body, {
142+
headers: getHeaders(),
143+
});
144+
145+
check(res, { "status is 200": (r) => r.status === 200 });
146+
147+
if (res.status !== 200) {
148+
console.log(
149+
`Search failed with ${res.status}: ${JSON.stringify(res.body)}`
150+
);
151+
}
32152
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
export * from "./client.js";
2+
3+
/*
4+
* NOTE - To run the producer K6 tests, you need to prepare the data by setting
5+
* the output_full_pointers flag to true in the environment.py:setup() method.
6+
*/
7+
8+
export const options = {
9+
tlsAuth: [
10+
{
11+
cert: open(`../../../truststore/client/${__ENV.ENV_TYPE}.crt`),
12+
key: open(`../../../truststore/client/${__ENV.ENV_TYPE}.key`),
13+
},
14+
],
15+
scenarios: {
16+
createDocumentReference: {
17+
exec: "createDocumentReference",
18+
executor: "ramping-vus",
19+
startVUs: 1,
20+
stages: [
21+
{ target: 10, duration: "30s" },
22+
{ target: 10, duration: "1m" },
23+
],
24+
},
25+
readDocumentReference: {
26+
exec: "readDocumentReference",
27+
executor: "ramping-vus",
28+
startVUs: 1,
29+
stages: [
30+
{ target: 10, duration: "30s" },
31+
{ target: 10, duration: "1m" },
32+
],
33+
},
34+
updateDocumentReference: {
35+
exec: "updateDocumentReference",
36+
executor: "ramping-vus",
37+
startVUs: 1,
38+
stages: [
39+
{ target: 10, duration: "30s" },
40+
{ target: 10, duration: "1m" },
41+
],
42+
},
43+
deleteDocumentReference: {
44+
exec: "deleteDocumentReference",
45+
executor: "ramping-vus",
46+
startVUs: 1,
47+
stages: [
48+
{ target: 10, duration: "30s" },
49+
{ target: 10, duration: "1m" },
50+
],
51+
},
52+
upsertDocumentReference: {
53+
exec: "upsertDocumentReference",
54+
executor: "ramping-vus",
55+
startVUs: 1,
56+
stages: [
57+
{ target: 10, duration: "30s" },
58+
{ target: 10, duration: "1m" },
59+
],
60+
},
61+
},
62+
};

0 commit comments

Comments
 (0)