Skip to content

Commit 10df6ad

Browse files
authored
Merge branch 'develop' into feature/jale13-nrl-0000-upgrade-ec2-storage
2 parents 96cf61f + b88c830 commit 10df6ad

21 files changed

Lines changed: 650 additions & 306 deletions

.github/workflows/daily-build.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,18 @@ jobs:
6767
with:
6868
key: ${{ github.run_id }}-nrlf-permissions
6969
path: dist/nrlf_permissions.zip
70+
71+
sbom:
72+
name: Generate SBOM - ${{ github.ref }}
73+
runs-on: ubuntu-latest
74+
75+
steps:
76+
- name: Git clone - ${{ github.ref }}
77+
uses: actions/checkout@v4
78+
with:
79+
ref: ${{ github.ref }}
80+
81+
- name: Generate SBOM
82+
uses: nhs-england-tools/trivy-action/sbom-scan@v1.4.0
83+
with:
84+
repo-path: "./"

.github/workflows/pr-env-deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,10 +300,10 @@ jobs:
300300
run: make test-performance-prepare TF_WORKSPACE_NAME=${{ needs.set-environment-id.outputs.environment_id }}
301301

302302
- name: Run Performance Test - Baseline
303-
run: make test-performance-baseline HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
303+
run: make test-performance-baseline-internal HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
304304

305305
- name: Run Performance Test - Stress
306-
run: make test-performance-stress HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
306+
run: make test-performance-stress-internal HOST=${{ needs.set-environment-id.outputs.environment_id }}.api.record-locator.dev.national.nhs.uk ENV_TYPE=dev
307307

308308
- name: Process Performance Test Outputs
309309
run: make test-performance-output

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ dist
7777
allure-results/*
7878
allure-report/*
7979

80-
# Performance test ref data
80+
# Performance test ref data & output
8181
tests/performance/reference-data.json
8282
tests/performance/producer/expanded_pointer_distributions.json
83+
producer-internal-*.json
84+
producer-public-*.json
85+
consumer-internal-*.json
86+
consumer-public-*.json

Makefile

Lines changed: 90 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ PERFTEST_PATIENTS_WITH_POINTERS ?= 0
2121
PERFTEST_POINTERS_PER_PATIENT ?= 0
2222
PERFTEST_TYPE_DIST_PROFILE ?= default
2323
PERFTEST_CUSTODIAN_DIST_PROFILE ?= default
24+
PERFTEST_TOKEN_REFRESH_PORT ?= 8765
2425

2526
export PATH := $(PATH):$(PWD)/.venv/bin
2627
export USE_SHARED_RESOURCES := $(shell poetry run python scripts/are_resources_shared_for_stack.py $(TF_WORKSPACE_NAME))
@@ -156,20 +157,58 @@ test-performance-prepare:
156157
mkdir -p $(DIST_PATH)
157158
PYTHONPATH=. poetry run python tests/performance/environment.py setup $(TF_WORKSPACE_NAME)
158159

159-
test-performance: check-warn test-performance-baseline test-performance-stress ## Run the performance tests
160+
test-performance-internal: check-warn test-performance-baseline-internal test-performance-stress-internal ## Run the performance tests against the internal access points
160161

161-
test-performance-baseline:
162-
@echo "Running consumer performance baseline test"
163-
k6 run --out csv=$(DIST_PATH)/consumer-baseline.csv tests/performance/consumer/baseline.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
164-
165-
test-performance-stress:
166-
@echo "Running consumer performance stress test"
162+
test-performance-baseline-internal: check-warn ## Run the performance baseline tests for the internal access points
163+
@echo "Running internal consumer performance baseline test"
164+
TEST_CONNECT_MODE=internal \
165+
TEST_STACK_DOMAIN=$(shell terraform -chdir=terraform/infrastructure output -raw domain 2>/dev/null) \
166+
k6 run --out csv=$(DIST_PATH)/consumer-baseline.csv tests/performance/consumer/baseline.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
167+
168+
test-performance-baseline-public: check-warn ## Run the baseline performance tests for the external access points
169+
@echo "Fetching public mode configuration and bearer token..."
170+
@CONFIG_FILE=$$(mktemp /tmp/perf_config_XXXXXX); \
171+
trap "rm -f $$CONFIG_FILE" EXIT; \
172+
PYTHONPATH=. python3 tests/performance/get_test_config.py $(ENV_TYPE) 2>&1 | tail -n 1 > $$CONFIG_FILE; \
173+
PUBLIC_BASE_URL=$$(jq -r '.public_base_url' $$CONFIG_FILE); \
174+
echo "Running consumer performance baseline test against the external access points"; \
175+
TEST_CONNECT_MODE=public \
176+
TEST_PUBLIC_BASE_URL=$$PUBLIC_BASE_URL \
177+
TEST_CONFIG_FILE=$$CONFIG_FILE \
178+
k6 run --out csv=$(DIST_PATH)/consumer-baseline-public.csv tests/performance/consumer/baseline.js -e ENV_TYPE=$(ENV_TYPE)
179+
180+
test-performance-stress-internal: ## Run the performance stress tests for the internal access points
181+
@echo "Running internal consumer performance stress test"
167182
k6 run --out csv=$(DIST_PATH)/consumer-stress.csv tests/performance/consumer/stress.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
168183

169-
test-performance-soak:
170-
@echo "Running consumer performance soak test"
184+
test-performance-stress-public: check-warn ## Run the stress performance tests for the external access points
185+
@echo "Fetching public mode configuration and bearer token..."
186+
@CONFIG_FILE=$$(mktemp /tmp/perf_config_XXXXXX); \
187+
trap "rm -f $$CONFIG_FILE" EXIT; \
188+
PYTHONPATH=. python3 tests/performance/get_test_config.py $(ENV_TYPE) 2>&1 | tail -n 1 > $$CONFIG_FILE; \
189+
PUBLIC_BASE_URL=$$(jq -r '.public_base_url' $$CONFIG_FILE); \
190+
echo "Running consumer performance stress test against the external access points"; \
191+
TEST_CONNECT_MODE=public \
192+
TEST_PUBLIC_BASE_URL=$$PUBLIC_BASE_URL \
193+
TEST_CONFIG_FILE=$$CONFIG_FILE \
194+
k6 run --out csv=$(DIST_PATH)/consumer-stress-public.csv tests/performance/consumer/stress.js -e ENV_TYPE=$(ENV_TYPE)
195+
196+
test-performance-soak-internal:
197+
@echo "Running internal consumer performance soak test"
171198
k6 run --out csv=$(DIST_PATH)/consumer-soak.csv tests/performance/consumer/soak.js -e HOST=$(HOST) -e ENV_TYPE=$(ENV_TYPE)
172199

200+
test-performance-soak-public: check-warn ## Run the soak performance tests for the external access points
201+
@echo "Fetching public mode configuration and bearer token..."
202+
@CONFIG_FILE=$$(mktemp /tmp/perf_config_XXXXXX); \
203+
trap "rm -f $$CONFIG_FILE" EXIT; \
204+
PYTHONPATH=. python3 tests/performance/get_test_config.py $(ENV_TYPE) 2>&1 | tail -n 1 > $$CONFIG_FILE; \
205+
PUBLIC_BASE_URL=$$(jq -r '.public_base_url' $$CONFIG_FILE); \
206+
echo "Running consumer performance soak test against the external access points"; \
207+
TEST_CONNECT_MODE=public \
208+
TEST_PUBLIC_BASE_URL=$$PUBLIC_BASE_URL \
209+
TEST_CONFIG_FILE=$$CONFIG_FILE \
210+
k6 run --out csv=$(DIST_PATH)/consumer-soak-public.csv tests/performance/consumer/soak.js -e ENV_TYPE=$(ENV_TYPE)
211+
173212
test-performance-output: ## Process outputs from the performance tests
174213
@echo "Processing performance test outputs"
175214
poetry run python tests/performance/process_results.py baseline $(DIST_PATH)/consumer-baseline.csv
@@ -254,6 +293,7 @@ generate-models: check-warn ## Generate Pydantic Models
254293

255294

256295
perftest-generate-permissions: ## Generate perftest permissions and add to nrlf_permissions
296+
@echo "Generating permissions for performance tests with DIST_PATH=$(DIST_PATH)"
257297
PYTHONPATH=. poetry run python tests/performance/producer/generate_permissions.py --output_dir="$(DIST_PATH)/nrlf_permissions/K6PerformanceTest"
258298

259299
perftest-seed-tables: ## Seed tables and upload generated perftest input files to s3
@@ -270,22 +310,53 @@ perftest-prepare: ## Prepare input files for producer & consumer perf tests
270310
mkdir -p "${DIST_PATH}/nft"
271311
aws s3 cp "s3://nhsd-nrlf--${ENV}-metadata/performance/seed-pointers-extract-${PERFTEST_TABLE_NAME}.zip" "${DIST_PATH}/pointer_extract-${PERFTEST_TABLE_NAME}.zip"
272312
unzip "${DIST_PATH}/pointer_extract-${PERFTEST_TABLE_NAME}.zip"
273-
# cp "${DIST_PATH}/nft/seed-pointers-extract-${PERFTEST_TABLE_NAME}.csv" "${DIST_PATH}/seed-pointers-extract.csv"
274313
PYTHONPATH=. poetry run python ./tests/performance/generate_producer_distributions.py
275314

276-
perftest-producer: ## Run producer perf tests
315+
perftest-producer-internal: ## Run producer perf tests
277316
@echo "Running producer performance tests with HOST=$(PERFTEST_HOST) and ENV_TYPE=$(ENV_TYPE) and DIST_PATH=$(DIST_PATH)"
278-
k6 run tests/performance/producer/perftest.js -e HOST=$(PERFTEST_HOST) -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
279-
280-
perftest-consumer: ## Run consumer perf tests
317+
k6 run tests/performance/producer/perftest.js --summary-mode=full --out json=$(DIST_PATH)/producer-internal-$$(date +%Y%m%d%H%M%S).json -e HOST=$(PERFTEST_HOST) -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
318+
319+
perftest-producer-public: check-warn ## Run the producer perftests for the external access points
320+
@echo "Starting token refresher in background with ENV=$(ENV) PERFTEST_TOKEN_REFRESH_PORT=$(PERFTEST_TOKEN_REFRESH_PORT)"
321+
ENV=$(ENV) TOKEN_REFRESH_PORT=$(PERFTEST_TOKEN_REFRESH_PORT) PYTHONPATH=. poetry run python ./tests/performance/token_refresher.py &
322+
trap "kill $$(lsof -t -i :$(PERFTEST_TOKEN_REFRESH_PORT)) 2>/dev/null" EXIT
323+
@echo "Fetching public mode configuration..."
324+
@CONFIG_FILE=$$(mktemp /tmp/perf_config_XXXXXX); \
325+
trap "rm -f $$CONFIG_FILE" EXIT; \
326+
PYTHONPATH=. poetry run python tests/performance/get_test_config.py $(ENV_TYPE) 2>&1 | tail -n 1 > $$CONFIG_FILE; \
327+
PUBLIC_BASE_URL=$$(jq -r '.public_base_url' $$CONFIG_FILE); \
328+
echo "Running public producer perftests with ENV_TYPE=$(ENV_TYPE) and DIST_PATH=$(DIST_PATH)"; \
329+
TEST_CONNECT_MODE=public \
330+
TEST_PUBLIC_BASE_URL=$$PUBLIC_BASE_URL \
331+
TEST_CONFIG_FILE=$$CONFIG_FILE \
332+
k6 run tests/performance/producer/perftest.js --summary-mode=full --out json=$(DIST_PATH)/producer-public-$$(date +%Y%m%d%H%M%S).json -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
333+
kill $$(lsof -t -i :$(PERFTEST_TOKEN_REFRESH_PORT))
334+
335+
perftest-consumer-internal:
281336
@echo "Running consumer performance tests with HOST=$(PERFTEST_HOST) and ENV_TYPE=$(ENV_TYPE) and DIST_PATH=$(DIST_PATH)"
282-
k6 run tests/performance/consumer/perftest.js -e HOST=$(PERFTEST_HOST) -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
283-
284-
perftest-generate-pointer-table-extract: ## Refresh the perf test input files in s3. Can be expensive to run on large tables
285-
@echo "Generating pointer table extract with PERFTEST_TABLE_NAME=$(PERFTEST_TABLE_NAME) and DIST_PATH=$(DIST_PATH)"
337+
k6 run tests/performance/consumer/perftest.js --summary-mode=full --out json=$(DIST_PATH)/consumer-internal-$$(date +%Y%m%d%H%M%S).json -e HOST=$(PERFTEST_HOST) -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
338+
339+
perftest-consumer-public: check-warn ## Run the consumer perftests for the external access points
340+
@echo "Starting token refresher in background with ENV=$(ENV) PERFTEST_TOKEN_REFRESH_PORT=$(PERFTEST_TOKEN_REFRESH_PORT)"
341+
ENV=$(ENV) TOKEN_REFRESH_PORT=$(PERFTEST_TOKEN_REFRESH_PORT) PYTHONPATH=. poetry run python ./tests/performance/token_refresher.py &
342+
trap "kill $$(lsof -t -i :$(PERFTEST_TOKEN_REFRESH_PORT)) 2>/dev/null" EXIT
343+
@echo "Fetching public mode configuration..."
344+
@CONFIG_FILE=$$(mktemp /tmp/perf_config_XXXXXX); \
345+
trap "rm -f $$CONFIG_FILE" EXIT; \
346+
PYTHONPATH=. poetry run python tests/performance/get_test_config.py $(ENV_TYPE) 2>&1 | tail -n 1 > $$CONFIG_FILE; \
347+
PUBLIC_BASE_URL=$$(jq -r '.public_base_url' $$CONFIG_FILE); \
348+
echo "Running public consumer perftests with ENV_TYPE=$(ENV_TYPE) and DIST_PATH=$(DIST_PATH)"; \
349+
TEST_CONNECT_MODE=public \
350+
TEST_PUBLIC_BASE_URL=$$PUBLIC_BASE_URL \
351+
TEST_CONFIG_FILE=$$CONFIG_FILE \
352+
k6 run tests/performance/consumer/perftest.js --summary-mode=full --out json=$(DIST_PATH)/consumer-public-$$(date +%Y%m%d%H%M%S).json -e ENV_TYPE=$(ENV_TYPE) -e DIST_PATH=$(DIST_PATH)
353+
kill $$(lsof -t -i :$(PERFTEST_TOKEN_REFRESH_PORT))
354+
355+
perftest-generate-pointer-table-extract:
356+
@echo "Generating pointer table extract with PERFTEST_TABLE_NAME=$(PERFTEST_TABLE_NAME) and ENV=$(ENV) and DIST_PATH=$(DIST_PATH)"
286357
rm -rf "${DIST_PATH}/nft"
287358
mkdir -p "${DIST_PATH}/nft"
288-
PYTHONPATH=. poetry run python tests/performance/perftest_environment.py generate_pointer_table_extract --output_dir="${DIST_PATH}/nft"
359+
PYTHONPATH=. poetry run python tests/performance/perftest_environment.py generate_pointer_table_extract --output_dir="${DIST_PATH}/nft" --extract-size=2000000
289360
./scripts/get-current-info.sh > "${DIST_PATH}/nft/info.json"
290361
zip -r "${DIST_PATH}/pointer_extract-${PERFTEST_TABLE_NAME}.zip" "${DIST_PATH}/nft"
291362
aws s3 cp "${DIST_PATH}/pointer_extract-${PERFTEST_TABLE_NAME}.zip" "s3://nhsd-nrlf--${ENV}-metadata/performance/seed-pointers-extract-${PERFTEST_TABLE_NAME}.zip"

poetry.lock

Lines changed: 19 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/seed_nft_tables.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,21 @@ def _write_pointer_extract_to_file(table_name, pointer_data):
102102
create_extract_metadata_file(table_name, nft_dist_path)
103103

104104

105+
# To avoid sonarcube maintainability warning
106+
def get_pointer_processor(unprocessed_items):
107+
def pointer_is_processed(pointer):
108+
pointer_id = pointer[0]
109+
matches = [
110+
unprocessed_item
111+
for unprocessed_item in unprocessed_items
112+
if unprocessed_item["PutRequest"]["Item"].get("id") == pointer_id
113+
]
114+
115+
return len(matches) == 0
116+
117+
return pointer_is_processed
118+
119+
105120
def _populate_seed_table(
106121
table_name: str,
107122
patients_with_pointers: int,
@@ -143,6 +158,7 @@ def _populate_seed_table(
143158
unprocessed_count = 0
144159

145160
pointer_data: list[list[str]] = []
161+
batch_pointer_data: list[list[str]] = []
146162

147163
start_time = datetime.now(tz=timezone.utc)
148164
batch_upsert_items: list[dict[str, Any]] = []
@@ -158,11 +174,20 @@ def _populate_seed_table(
158174
RequestItems={table_name: batch_upsert_items}
159175
)
160176

177+
processed_pointers = batch_pointer_data
178+
161179
if response.get("UnprocessedItems"):
162-
unprocessed_count += len(
163-
response.get("UnprocessedItems").get(table_name, [])
180+
unprocessed_items = response.get("UnprocessedItems").get(table_name, [])
181+
unprocessed_count += len(unprocessed_items)
182+
pointer_is_processed = get_pointer_processor(unprocessed_items)
183+
184+
processed_pointers = list(
185+
filter(pointer_is_processed, batch_pointer_data)
164186
)
165187

188+
pointer_data.extend(processed_pointers)
189+
190+
batch_pointer_data = []
166191
batch_upsert_items = []
167192
batch_counter = 0
168193

@@ -178,7 +203,7 @@ def _populate_seed_table(
178203
)
179204
put_req = {"PutRequest": {"Item": pointer.model_dump()}}
180205
batch_upsert_items.append(put_req)
181-
pointer_data.append(
206+
batch_pointer_data.append(
182207
[
183208
pointer.id,
184209
new_type, # not full type url

terraform/account-wide-infrastructure/test/dynamodb__pointers-table.tf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,21 @@ module "ref-pointers-table" {
3232
}
3333

3434
module "perftest-pointers-table" {
35+
source = "../modules/pointers-table"
36+
name_prefix = "nhsd-nrlf--perftest"
37+
}
38+
39+
module "perftest-pointers-baseline-table" {
3540
source = "../modules/pointers-table"
3641
name_prefix = "nhsd-nrlf--perftest-baseline"
3742
}
43+
44+
module "perftest-pointers-15m-table" {
45+
source = "../modules/pointers-table"
46+
name_prefix = "nhsd-nrlf--perftest-15m"
47+
}
48+
49+
module "perftest-pointers-55m-table" {
50+
source = "../modules/pointers-table"
51+
name_prefix = "nhsd-nrlf--perftest-55m"
52+
}

0 commit comments

Comments
 (0)