Skip to content

Commit dbebe5c

Browse files
authored
VED-812: Add e2e test pipeline (#905)
* VED-812: Add e2e test pipeline. * VED-812: Add test pipeline trigger. * VED-812: Add debug logging. * VED-812: Fix Sonar errors. * VED-812: Update test trigger. * VED-812: Fix variable name. * VED-812: Use Python library for TOTP code generation. Add some missing env vars. * VED-812: Change test command. * VED-812: Obtain AWS credentials before running e2e tests. * VED-812: Hard code environment for testing. * VED-812: Use input parameters. Add batch e2e tests. * VED-812: Pass secrets to reusable pipeline. Fix batch e2e test command. * VED-812: Read outputs from Terraform. Some tidying up. * VED-812: Select workspace before running Terraform output. * VED-812: Fix env var names * VED-812: Set workspace explicitly. * VED-812: Revert previous change. * VED-812: Add missing env var. * VED-812: Only restore relevant caches. Always run batch e2e tests. * VED-812: Wait for API to be available before running tests. * VED-812: Replace use of unavailable context. * VED-812: Set proxy name and service base path according to the environment. * VED-812: Replicate existing e2e test commands per env. * VED-812: Tidy up. Use env vars associated with the Apigee environment. Make more steps conditional. * VED-812: Update test pipeline. * VED-812: Improve Terraform workspace Makefile commands. * VED-812: Add workaround for batch e2e tests conditional job. * VED-812: Wait for correct commit hash earlier in the pipeline. * VED-812: Remove testing pipeline.
1 parent c7856fe commit dbebe5c

File tree

11 files changed

+296
-45
lines changed

11 files changed

+296
-45
lines changed

.github/workflows/deploy-backend.yml

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,62 +42,54 @@ on:
4242
type: string
4343
description: Set the sub environment name e.g. pr-xxx, or green/blue in higher environments
4444

45+
env: # Sonarcloud - do not allow direct usage of untrusted data
46+
APIGEE_ENVIRONMENT: ${{ inputs.apigee_environment }}
47+
ENVIRONMENT: ${{ inputs.environment }}
48+
SUB_ENVIRONMENT: ${{ inputs.sub_environment }}
49+
50+
permissions:
51+
id-token: write
52+
contents: read
53+
4554
jobs:
4655
terraform-plan:
4756
runs-on: ubuntu-latest
4857
environment:
4958
name: ${{ inputs.environment }}
50-
env: # Sonarcloud - do not allow direct usage of untrusted data
51-
APIGEE_ENVIRONMENT: ${{ inputs.apigee_environment }}
52-
BACKEND_ENVIRONMENT: ${{ inputs.environment }}
53-
BACKEND_SUB_ENVIRONMENT: ${{ inputs.sub_environment }}
54-
permissions:
55-
id-token: write
56-
contents: read
5759
steps:
60+
- name: Checkout
61+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
62+
5863
- name: Connect to AWS
5964
uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838
6065
with:
6166
aws-region: eu-west-2
6267
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/auto-ops
6368
role-session-name: github-actions
6469

65-
- name: Whoami
66-
run: aws sts get-caller-identity
67-
68-
- name: Checkout
69-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
70-
7170
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
7271
with:
7372
terraform_version: "1.12.2"
7473

7574
- name: Terraform Init
76-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
77-
run: make init apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
75+
working-directory: terraform
76+
run: make init
7877

7978
- name: Terraform Plan
80-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
81-
run: make plan-ci apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
79+
working-directory: terraform
80+
run: make plan-ci
8281

8382
- name: Save Terraform Plan
8483
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
8584
with:
8685
name: tfplan
87-
path: ${{ vars.TERRAFORM_DIR_PATH }}/tfplan
86+
path: terraform/tfplan
8887

8988
terraform-apply:
9089
needs: terraform-plan
9190
runs-on: ubuntu-latest
9291
environment:
9392
name: ${{ inputs.environment }}
94-
env: # Sonarcloud - do not allow direct usage of untrusted data
95-
APIGEE_ENVIRONMENT: ${{ inputs.apigee_environment }}
96-
BACKEND_ENVIRONMENT: ${{ inputs.environment }}
97-
BACKEND_SUB_ENVIRONMENT: ${{ inputs.sub_environment }}
98-
permissions:
99-
id-token: write
100-
contents: read
10193
steps:
10294
- name: Checkout
10395
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
@@ -116,16 +108,16 @@ jobs:
116108
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0
117109
with:
118110
name: tfplan
119-
path: ${{ vars.TERRAFORM_DIR_PATH }}
111+
path: terraform
120112

121113
- name: Terraform Init
122-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
123-
run: make init apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
114+
working-directory: terraform
115+
run: make init
124116

125117
- name: Terraform Apply
126-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
118+
working-directory: terraform
127119
run: |
128-
make apply-ci apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
120+
make apply-ci
129121
echo "ID_SYNC_QUEUE_ARN=$(make -s output name=id_sync_queue_arn)" >> $GITHUB_ENV
130122
131123
- name: Install poetry
@@ -137,12 +129,14 @@ jobs:
137129
with:
138130
python-version: 3.11
139131
cache: "poetry"
132+
cache-dependency-path: |
133+
lambdas/mns_subscription/poetry.lock
134+
lambdas/shared/poetry.lock
140135
141136
- name: Create MNS Subscription
142137
if: ${{ inputs.environment == 'dev' && inputs.create_mns_subscription }}
143138
working-directory: "./lambdas/mns_subscription"
144139
env:
145-
APIGEE_ENVIRONMENT: ${{ inputs.apigee_environment }}
146140
SQS_ARN: ${{ env.ID_SYNC_QUEUE_ARN }}
147141
run: |
148142
poetry install --no-root

.github/workflows/pr-teardown.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
terraform_version: "1.12.2"
4444

4545
- name: Terraform Init and extract MNS SQS QUEUE ARN
46-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
46+
working-directory: terraform
4747
run: |
4848
make init apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
4949
make workspace apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
@@ -56,6 +56,9 @@ jobs:
5656
with:
5757
python-version: 3.11
5858
cache: "poetry"
59+
cache-dependency-path: |
60+
lambdas/mns_subscription/poetry.lock
61+
lambdas/shared/poetry.lock
5962
6063
- name: Unsubscribe MNS
6164
working-directory: "./lambdas/mns_subscription"
@@ -68,6 +71,6 @@ jobs:
6871
make unsubscribe
6972
7073
- name: Terraform Destroy
71-
working-directory: ${{ vars.TERRAFORM_DIR_PATH }}
74+
working-directory: terraform
7275
run: |
7376
make destroy apigee_environment=$APIGEE_ENVIRONMENT environment=$BACKEND_ENVIRONMENT sub_environment=$BACKEND_SUB_ENVIRONMENT
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
name: Run e2e Tests
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
apigee_environment:
7+
required: true
8+
type: string
9+
environment:
10+
required: true
11+
type: string
12+
sub_environment:
13+
required: true
14+
type: string
15+
workflow_dispatch:
16+
inputs:
17+
apigee_environment:
18+
type: choice
19+
description: Select the Apigee proxy environment
20+
options:
21+
- internal-dev
22+
- int
23+
- ref
24+
- prod
25+
environment:
26+
type: string
27+
description: Select the backend environment
28+
options:
29+
- dev
30+
- preprod
31+
- prod
32+
sub_environment:
33+
type: string
34+
description: Set the sub environment name e.g. pr-xxx, or green/blue in higher environments
35+
36+
env:
37+
APIGEE_ENVIRONMENT: ${{ inputs.apigee_environment }}
38+
ENVIRONMENT: ${{ inputs.environment }}
39+
SUB_ENVIRONMENT: ${{ inputs.sub_environment }}
40+
SERVICE_BASE_PATH: ${{ startsWith(inputs.sub_environment, 'pr-') && format('immunisation-fhir-api/FHIR/R4-{0}', inputs.sub_environment) || 'immunisation-fhir-api/FHIR/R4' }}
41+
PROXY_NAME: ${{ startsWith(inputs.sub_environment, 'pr-') && format('immunisation-fhir-api-{0}', inputs.sub_environment) || format('immunisation-fhir-api-{0}', inputs.apigee_environment) }}
42+
STATUS_API_KEY: ${{ secrets.STATUS_API_KEY }}
43+
SOURCE_COMMIT_ID: ${{ github.sha }}
44+
45+
permissions:
46+
id-token: write
47+
contents: read
48+
49+
jobs:
50+
wait-for-deployment:
51+
runs-on: ubuntu-latest
52+
environment: ${{ inputs.apigee_environment }}
53+
outputs:
54+
# Workaround for environment-level variables being unavailable in `jobs.<job-id>.if`.
55+
RUN_BATCH_E2E_TESTS: ${{ vars.RUN_BATCH_E2E_TESTS }}
56+
steps:
57+
- name: Wait for API to be available
58+
run: |
59+
endpoint=""
60+
if [[ ${APIGEE_ENVIRONMENT} =~ "prod" ]]; then
61+
endpoint="https://api.service.nhs.uk/${SERVICE_BASE_PATH}/_status"
62+
else
63+
endpoint="https://${APIGEE_ENVIRONMENT}.api.service.nhs.uk/${SERVICE_BASE_PATH}/_status"
64+
fi
65+
66+
counter=0
67+
while [[ ${counter} -lt 31 ]]; do
68+
response=$(curl -H "apikey: ${STATUS_API_KEY}" -s "${endpoint}")
69+
70+
response_code=$(jq -r '.checks.healthcheck.responseCode' <<< "${response}")
71+
response_body=$(jq -r '.checks.healthcheck.outcome' <<< "${response}")
72+
status=$(jq -r '.status' <<< "${response}")
73+
commitId=$(jq -r '.commitId' <<< "${response}")
74+
75+
if [[ "${response_code}" -eq 200 ]] && [[ "${response_body}" == "OK" ]] && [[ "${status}" == "pass" ]]; then
76+
echo "Status test successful"
77+
if [[ "${commitId}" == "${SOURCE_COMMIT_ID}" ]]; then
78+
echo "Commit hash test successful"
79+
break
80+
else
81+
echo "Waiting for ${endpoint} to return the correct commit hash..."
82+
fi
83+
else
84+
echo "Waiting for ${endpoint} to return a 200 response with 'OK' body..."
85+
fi
86+
87+
((counter=counter+1)) # Increment counter by 1
88+
echo "Attempt ${counter}"
89+
sleep 30
90+
done
91+
92+
if [[ ${counter} -eq 31 ]]; then
93+
echo "Status test failed: Maximum number of attempts reached"
94+
echo "Last response received:"
95+
echo "${response}"
96+
exit 1
97+
fi
98+
99+
e2e-tests:
100+
runs-on: ubuntu-latest
101+
needs: [wait-for-deployment]
102+
environment: ${{ inputs.apigee_environment }}
103+
env:
104+
APIGEE_USERNAME: ${{ vars.APIGEE_USERNAME }}
105+
steps:
106+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
107+
108+
- name: Connect to AWS
109+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
110+
uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838
111+
with:
112+
aws-region: eu-west-2
113+
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/auto-ops
114+
role-session-name: github-actions
115+
116+
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd
117+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
118+
with:
119+
terraform_version: "1.12.2"
120+
121+
- name: Terraform Init
122+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
123+
working-directory: terraform
124+
run: make init
125+
126+
- name: Set Terraform workspace
127+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
128+
working-directory: terraform
129+
run: make workspace
130+
131+
- name: Read Terraform outputs
132+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
133+
working-directory: terraform
134+
run: |
135+
echo "IMMS_DELTA_TABLE_NAME=$(make -s output name=imms_delta_table_name)" >> $GITHUB_ENV
136+
echo "AWS_DOMAIN_NAME=$(make -s output name=service_domain_name)" >> $GITHUB_ENV
137+
echo "DYNAMODB_TABLE_NAME=$(make -s output name=dynamodb_table_name)" >> $GITHUB_ENV
138+
echo "AWS_SQS_QUEUE_NAME=$(make -s output name=aws_sqs_queue_name)" >> $GITHUB_ENV
139+
echo "AWS_SNS_TOPIC_NAME=$(make -s output name=aws_sns_topic_name)" >> $GITHUB_ENV
140+
141+
- name: Install poetry
142+
run: pip install poetry==2.1.4
143+
144+
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c
145+
with:
146+
python-version: 3.11
147+
cache: "poetry"
148+
cache-dependency-path: "e2e/poetry.lock"
149+
150+
- name: Install e2e test dependencies
151+
working-directory: e2e
152+
run: poetry install --no-root
153+
154+
- name: Get Apigee access token
155+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
156+
working-directory: e2e
157+
env:
158+
APIGEE_PASSWORD: ${{ secrets.APIGEE_PASSWORD }}
159+
APIGEE_BASIC_AUTH_TOKEN: ${{ secrets.APIGEE_BASIC_AUTH_TOKEN }}
160+
APIGEE_OTP_KEY: ${{ secrets.APIGEE_OTP_KEY }}
161+
run: |
162+
CODE=$(poetry run python utils/compute_totp_code.py "$APIGEE_OTP_KEY")
163+
echo "::add-mask::$CODE"
164+
165+
echo "Requesting access token from Apigee..."
166+
response=$(curl -s -X POST "https://login.apigee.com/oauth/token" \
167+
-H "Content-Type: application/x-www-form-urlencoded" \
168+
-H "Accept: application/json;charset=utf-8" \
169+
-H "Authorization: Basic $APIGEE_BASIC_AUTH_TOKEN" \
170+
-d "username=$APIGEE_USERNAME&password=$APIGEE_PASSWORD&mfa_token=$CODE&grant_type=password")
171+
172+
token=$(jq -e -r '.access_token' <<< "$response")
173+
echo "::add-mask::$token"
174+
echo "APIGEE_ACCESS_TOKEN=$token" >> $GITHUB_ENV
175+
176+
- name: Run proxy deployment e2e test suite
177+
working-directory: e2e
178+
run: poetry run python -m unittest test_deployment
179+
180+
- name: Run proxy e2e test suite
181+
if: ${{ vars.RUN_PROXY_E2E_TESTS == 'true' }}
182+
working-directory: e2e
183+
run: poetry run python -m unittest test_proxy
184+
185+
- name: Run sandbox e2e test suite
186+
if: ${{ vars.RUN_SANDBOX_E2E_TESTS == 'true' }}
187+
working-directory: e2e
188+
run: poetry run python -m unittest test_proxy.TestProxyHealthcheck
189+
190+
- name: Run full e2e test suite
191+
if: ${{ vars.RUN_FULL_E2E_TESTS == 'true' }}
192+
working-directory: e2e
193+
run: poetry run python -m unittest
194+
195+
batch-e2e-tests:
196+
needs: [wait-for-deployment, e2e-tests]
197+
# Only actually depend on wait-for-deployment, but run after e2e-tests
198+
if: ${{ !cancelled() && needs.wait-for-deployment.result == 'success' && needs.wait-for-deployment.outputs.RUN_BATCH_E2E_TESTS == 'true' }}
199+
runs-on: ubuntu-latest
200+
environment: ${{ inputs.apigee_environment }}
201+
steps:
202+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
203+
204+
- name: Connect to AWS
205+
uses: aws-actions/configure-aws-credentials@a03048d87541d1d9fcf2ecf528a4a65ba9bd7838
206+
with:
207+
aws-region: eu-west-2
208+
role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/auto-ops
209+
role-session-name: github-actions
210+
211+
- name: Install poetry
212+
run: pip install poetry==2.1.4
213+
214+
- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c
215+
with:
216+
python-version: 3.11
217+
cache: "poetry"
218+
cache-dependency-path: "e2e_batch/poetry.lock"
219+
220+
- name: Install e2e test dependencies
221+
working-directory: e2e_batch
222+
run: poetry install --no-root
223+
224+
- name: Run batch e2e test suite
225+
working-directory: e2e_batch
226+
env:
227+
ENVIRONMENT: ${{ inputs.sub_environment }}
228+
run: poetry run python -m unittest -c -v

0 commit comments

Comments
 (0)