diff --git a/.github/actions/acceptance-tests/action.yml b/.github/actions/acceptance-tests/action.yml index dcf3ddb29..0ac177dab 100644 --- a/.github/actions/acceptance-tests/action.yml +++ b/.github/actions/acceptance-tests/action.yml @@ -25,7 +25,7 @@ runs: steps: - name: Run component tests - if: ${{ inputs.testType != 'e2e' }} + if: ${{ inputs.testType == 'component' }} uses: ./.github/actions/acceptance-tests-component with: testType: ${{ inputs.testType }} @@ -33,7 +33,7 @@ runs: targetComponent: ${{ inputs.targetComponent }} - name: Run e2e tests - if: ${{ inputs.testType == 'e2e' && inputs.targetEnvironment == 'main' }} + if: ${{ inputs.testType == 'e2e' }} uses: ./.github/actions/acceptance-tests-e2e with: targetEnvironment: ${{ inputs.targetEnvironment }} diff --git a/.github/actions/build-proxies/action.yml b/.github/actions/build-proxies/action.yml index 728edf4bc..23c5005c3 100644 --- a/.github/actions/build-proxies/action.yml +++ b/.github/actions/build-proxies/action.yml @@ -118,4 +118,5 @@ runs: --apimEnvironment "${{ env.APIM_ENV }}" \ --boundedContext "notify-supplier" \ --targetDomain "$TARGET_DOMAIN" \ - --version "${{ inputs.version }}" + --version "${{ inputs.version }}" \ + --internalRef "feature/CCM-17012" # TO BE REMOVED - used to trigger workflow until internal branch merges diff --git a/.github/workflows/deploy-dynamic-env-proxy.yaml b/.github/workflows/deploy-dynamic-env-proxy.yaml index 5c4607ae0..7a4313ad1 100644 --- a/.github/workflows/deploy-dynamic-env-proxy.yaml +++ b/.github/workflows/deploy-dynamic-env-proxy.yaml @@ -1,3 +1,4 @@ +# Test name: Deploy dynamic PR environment proxy run-name: Deploy proxy for PR environment on internal-dev by @${{ github.actor }} diff --git a/Makefile b/Makefile index c7915eb31..a0368e2f0 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ # the project as automated steps to be executed on locally and in the CD pipeline. include scripts/init.mk +-include .env # Load environment variables from .env file if it exists # ============================================================================== @@ -130,11 +131,14 @@ ${VERBOSE}.SILENT: \ # E2E Test commands # ##################### +# https://pytest-xdist.readthedocs.io/en/stable/known-limitations.html#output-stdout-and-stderr-from-workers means pytest won't print to stdout even with -s +PYTEST_WORKERS := 4 # set to 0 to see stdout/stderr when debugging e2e tests + TEST_CMD := APIGEE_ACCESS_TOKEN="$(APIGEE_ACCESS_TOKEN)" \ STATUS_ENDPOINT_API_KEY="$(STATUS_ENDPOINT_API_KEY)" \ PYTHONPATH=. poetry run pytest --disable-warnings -vv \ --color=yes \ - -n 4 \ + -n $(PYTEST_WORKERS) \ --api-name=nhs-notify-supplier \ --proxy-name="$(PROXY_NAME)" \ -s \ @@ -145,7 +149,6 @@ TEST_CMD := APIGEE_ACCESS_TOKEN="$(APIGEE_ACCESS_TOKEN)" \ --only-rerun 'AssertionError: Unexpected 502' \ --junitxml=test-report.xml - .internal-dev-test: @cd tests/e2e-tests && \ $(TEST_CMD) \ @@ -161,7 +164,7 @@ TEST_CMD := APIGEE_ACCESS_TOKEN="$(APIGEE_ACCESS_TOKEN)" \ PROD_CMD := APIGEE_ACCESS_TOKEN="$(APIGEE_ACCESS_TOKEN)" \ PYTHONPATH=. poetry run pytest --disable-warnings -vv \ --color=yes \ - -n 4 \ + -n $(PYTEST_WORKERS) \ --api-name=nhs-notify-supplier \ --proxy-name="$(PROXY_NAME)" \ -s \ diff --git a/tests/component-tests/integration-tests/urgent-letter-priority.spec.ts b/tests/component-tests/integration-tests/urgent-letter-priority.spec.ts index 2a2f2858c..f4cb2c65c 100644 --- a/tests/component-tests/integration-tests/urgent-letter-priority.spec.ts +++ b/tests/component-tests/integration-tests/urgent-letter-priority.spec.ts @@ -1,7 +1,6 @@ import { expect, test } from "@playwright/test"; import getRestApiGatewayBaseUrl from "tests/helpers/aws-gateway-helper"; import { pollForLetterStatus } from "tests/helpers/poll-for-letters-helper"; -import { getLettersFromQueueViaIndex } from "tests/helpers/generate-fetch-test-data"; import { getVariantsWithUrgency, sendEventsForVariants, @@ -44,12 +43,6 @@ test.describe("Urgent Letter Priority Tests", () => { await verifyAllocationLogsContainPriority(urgencyNineLetterIds, 9); await verifyAllocationLogsContainPriority(urgencyTenLetterIds, 10); - const lettersFromQueue = await getLettersFromQueueViaIndex(supplier); - - const letterIdsFromQueue = lettersFromQueue.map( - (letter) => letter.letterId, - ); - const header = createValidRequestHeaders(supplier); const response = await request.get(`${baseUrl}/${SUPPLIER_LETTERS}`, { headers: header, @@ -63,10 +56,9 @@ test.describe("Urgent Letter Priority Tests", () => { GetLettersResponseSchema.parse(responseBody); const letterIds = getLettersResponse.data.map((letter) => letter.id); - expect(letterIds).toEqual(letterIdsFromQueue); verifyIndexPositionOfLetterVariants( - letterIdsFromQueue, + letterIds, urgencyTenLetterIds, urgencyNineLetterIds, ); diff --git a/tests/constants/api-constants.ts b/tests/constants/api-constants.ts index 608fb75d8..0afe02ca3 100644 --- a/tests/constants/api-constants.ts +++ b/tests/constants/api-constants.ts @@ -5,7 +5,7 @@ export const AWS_REGION = "eu-west-2"; export const envName = process.env.TARGET_ENVIRONMENT ?? "main"; export const API_NAME = `nhs-${envName}-supapi`; export const LETTERSTABLENAME = `nhs-${envName}-supapi-letters`; -export const SUPPLIERID = "TestSupplier1"; +export const SUPPLIERID = "supplier1"; export const MI_ENDPOINT = "mi"; export const SUPPLIERTABLENAME = `nhs-${envName}-supapi-suppliers`; export const UPSERT_LETTER_LAMBDA_ARN = `arn:aws:lambda:eu-west-2:820178564574:function:nhs-${envName}-supapi-upsertletter`; diff --git a/tests/e2e-tests/api/data/test_get_letter_data.py b/tests/e2e-tests/api/data/test_get_letter_data.py index 42bfc0bef..94b865079 100644 --- a/tests/e2e-tests/api/data/test_get_letter_data.py +++ b/tests/e2e-tests/api/data/test_get_letter_data.py @@ -11,28 +11,17 @@ @pytest.mark.devtest @pytest.mark.inttest @pytest.mark.prodtest -def test_200_get_letter_status(url, authentication_secret): +def test_200_get_letter_data(url, authentication_secret): headers = Generators.generate_valid_headers(authentication_secret) ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=1) - get_letter_data = requests.get(f"{url}/{LETTERS_ENDPOINT}/{ids[0]}/data", headers=headers) + print(f"calling GET {url}{LETTERS_ENDPOINT}/{ids[0]}/data with headers {headers}") + get_letter_data = requests.get(f"{url}{LETTERS_ENDPOINT}/{ids[0]}/data", headers=headers) ErrorHandler.handle_retry(get_letter_data) assert get_letter_data.status_code == 200, f"Response: {get_letter_data.status_code}: {get_letter_data.text}" assert get_letter_data.headers.get("Content-Type") == "application/pdf" -@pytest.mark.test -@pytest.mark.devtest -@pytest.mark.inttest -@pytest.mark.prodtest -def test_404_letter_does_not_exist(url, authentication_secret): - headers = Generators.generate_valid_headers(authentication_secret) - get_message_response = requests.get(f"{url}/{LETTERS_ENDPOINT}/xx", headers=headers) - - ErrorHandler.handle_retry(get_message_response) - assert get_message_response.status_code == 404 - assert get_message_response.json().get("errors")[0].get("detail") == "No resource found with that ID" - @pytest.mark.test @pytest.mark.devtest @pytest.mark.inttest @@ -40,7 +29,9 @@ def test_404_letter_does_not_exist(url, authentication_secret): def test_404_letter_does_not_exist(url, authentication_secret): letter_id = uuid.uuid4().hex headers = Generators.generate_valid_headers(authentication_secret) - get_message_response = requests.get(f"{url}/{LETTERS_ENDPOINT}/{letter_id}/data", headers=headers) + + print(f"calling GET {url}{LETTERS_ENDPOINT}/{letter_id}/data with headers {headers}") + get_message_response = requests.get(f"{url}{LETTERS_ENDPOINT}/{letter_id}/data", headers=headers) ErrorHandler.handle_retry(get_message_response) assert get_message_response.status_code == 404 diff --git a/tests/e2e-tests/api/headers/test_x_request_id.py b/tests/e2e-tests/api/headers/test_x_request_id.py index 827b8549d..7adaa7dcb 100644 --- a/tests/e2e-tests/api/headers/test_x_request_id.py +++ b/tests/e2e-tests/api/headers/test_x_request_id.py @@ -20,7 +20,7 @@ def test_header_letters_endpoint( ): auth_header = {"apikey": authentication_secret.value} if authentication_secret.auth_type == "apikey" \ else {"Authorization": authentication_secret.value} - resp = getattr(requests, method)(f"{url}/{endpoints}", headers={ + resp = getattr(requests, method)(f"{url}{endpoints}", headers={ **auth_header, "X-Request-ID": None }) @@ -38,7 +38,7 @@ def test_header_mi_endpoint( ): auth_header = {"apikey": authentication_secret.value} if authentication_secret.auth_type == "apikey" \ else {"Authorization": authentication_secret.value} - resp = getattr(requests, "post")(f"{url}/{MI_ENDPOINT}", headers={ + resp = getattr(requests, "post")(f"{url}{MI_ENDPOINT}", headers={ **auth_header, "X-Request-ID": "" }) diff --git a/tests/e2e-tests/api/letters/test_get_letter_status.py b/tests/e2e-tests/api/letters/test_get_letter_status.py index c55af8820..9cfa22175 100644 --- a/tests/e2e-tests/api/letters/test_get_letter_status.py +++ b/tests/e2e-tests/api/letters/test_get_letter_status.py @@ -16,19 +16,21 @@ def test_200_get_letter_status(url, authentication_secret): ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=1) letter_id = ids[0] - get_message_response = requests.get(f"{url}/{LETTERS_ENDPOINT}/{letter_id}", headers=headers) + print(f"calling GET {url}{LETTERS_ENDPOINT}/{letter_id} with headers {headers}") + get_message_response = requests.get(f"{url}{LETTERS_ENDPOINT}/{letter_id}", headers=headers) ErrorHandler.handle_retry(get_message_response) assert get_message_response.status_code == 200, f"Response: {get_message_response.status_code}: {get_message_response.text}" - @pytest.mark.test @pytest.mark.devtest @pytest.mark.inttest @pytest.mark.prodtest def test_404_letter_does_not_exist(url, authentication_secret): headers = Generators.generate_valid_headers(authentication_secret) - get_message_response = requests.get(f"{url}/{LETTERS_ENDPOINT}/xx", headers=headers) + + print(f"calling GET {url}{LETTERS_ENDPOINT}/xx with headers {headers}") + get_message_response = requests.get(f"{url}{LETTERS_ENDPOINT}/xx", headers=headers) ErrorHandler.handle_retry(get_message_response) assert get_message_response.status_code == 404, f"Response: {get_message_response.status_code}: {get_message_response.text}" diff --git a/tests/e2e-tests/api/letters/test_get_list_of_letters.py b/tests/e2e-tests/api/letters/test_get_list_of_letters.py index 275d255a6..1c67edb91 100644 --- a/tests/e2e-tests/api/letters/test_get_list_of_letters.py +++ b/tests/e2e-tests/api/letters/test_get_list_of_letters.py @@ -12,5 +12,6 @@ def test_200_get_letters(url, authentication_secret): headers = Generators.generate_valid_headers(authentication_secret) ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=1) + assert ids, "Expected at least one PENDING letter" assert len(ids) == 1 diff --git a/tests/e2e-tests/api/letters/test_multiple_letter_status.py b/tests/e2e-tests/api/letters/test_multiple_letter_status.py index 744fbb8d4..51fe72ddf 100644 --- a/tests/e2e-tests/api/letters/test_multiple_letter_status.py +++ b/tests/e2e-tests/api/letters/test_multiple_letter_status.py @@ -18,8 +18,9 @@ def test_202_with_valid_headers(url, authentication_secret): ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=2) data = Generators.generate_multiple_valid_request(ids) + print(f"calling POST {url}{LETTERS_ENDPOINT} with headers {headers} and body {data}") update_letter_status = requests.post( - f"{url}/{LETTERS_ENDPOINT}", + f"{url}{LETTERS_ENDPOINT}", headers=headers, json=data, ) @@ -37,8 +38,9 @@ def test_400_duplicates_in_request_body(url, authentication_secret): ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=2) data = Generators.generate_duplicate_request(ids) + print(f"calling POST {url}{LETTERS_ENDPOINT} with headers {headers} and body {data}") update_letter_status = requests.post( - f"{url}/{LETTERS_ENDPOINT}", + f"{url}{LETTERS_ENDPOINT}", headers=headers, json=data, ) @@ -57,8 +59,9 @@ def test_400_invalid_status_in_request_body(url, authentication_secret): ids = get_pending_letter_ids(url, headers, LETTERS_ENDPOINT, limit=3) data = Generators.generate_invalid_status_request(ids) + print(f"calling POST {url}{LETTERS_ENDPOINT} with headers {headers} and body {data}") update_letter_status = requests.post( - f"{url}/{LETTERS_ENDPOINT}", + f"{url}{LETTERS_ENDPOINT}", headers=headers, json=data, ) diff --git a/tests/e2e-tests/api/letters/test_update_letter_status.py b/tests/e2e-tests/api/letters/test_update_letter_status.py index 28a61c3ff..98200ec22 100644 --- a/tests/e2e-tests/api/letters/test_update_letter_status.py +++ b/tests/e2e-tests/api/letters/test_update_letter_status.py @@ -19,8 +19,10 @@ def test_202_with_valid_headers(url, authentication_secret): letter_id = ids[0] data = Generators.generate_valid_message_body("ACCEPTED", letter_id) + + print(f"calling PATCH {url}{LETTERS_ENDPOINT}/{letter_id} with headers {headers} and body {data}") update_letter_status = requests.patch( - f"{url}/{LETTERS_ENDPOINT}/{letter_id}", + f"{url}{LETTERS_ENDPOINT}/{letter_id}", headers=headers, json=data, ) @@ -35,8 +37,10 @@ def test_202_with_rejected_status(url, authentication_secret): letter_id = ids[0] data = Generators.generate_valid_message_rejected("REJECTED", letter_id) + + print(f"calling PATCH {url}{LETTERS_ENDPOINT}/{letter_id} with headers {headers} and body {data}") update_letter_status = requests.patch( - f"{url}/{LETTERS_ENDPOINT}/{letter_id}", + f"{url}{LETTERS_ENDPOINT}/{letter_id}", headers=headers, json=data, ) @@ -55,8 +59,10 @@ def test_400_with_invalid_status(url, authentication_secret): letter_id = ids[0] data = Generators.generate_valid_message_body("", letter_id) + + print(f"calling PATCH {url}{LETTERS_ENDPOINT}/{letter_id} with headers {headers} and body {data}") update_letter_status = requests.patch( - f"{url}/{LETTERS_ENDPOINT}/{letter_id}", + f"{url}{LETTERS_ENDPOINT}/{letter_id}", headers=headers, json=data, ) @@ -75,8 +81,10 @@ def test_400_id_mismatch_with_request(url, authentication_secret): letter_id = ids[0] data = Generators.generate_valid_message_body("ACCEPTED", "letter1") + + print(f"calling PATCH {url}{LETTERS_ENDPOINT}/{letter_id} with headers {headers} and body {data}") update_letter_status = requests.patch( - f"{url}/{LETTERS_ENDPOINT}/{letter_id}", + f"{url}{LETTERS_ENDPOINT}/{letter_id}", headers=headers, json=data, ) diff --git a/tests/e2e-tests/lib/letters.py b/tests/e2e-tests/lib/letters.py index cabd8f458..4a1774ecb 100644 --- a/tests/e2e-tests/lib/letters.py +++ b/tests/e2e-tests/lib/letters.py @@ -8,7 +8,7 @@ _REPO_ROOT = pathlib.Path(__file__).resolve().parents[3] _CLI_WORKSPACE = "nhs-notify-supplier-api-letter-test-data-utility" -_SUPPLIER_ID = "TestSupplier1" +_SUPPLIER_ID = "supplier1" # This should be the same id registered in the Apigee App to which the proxy will be associated def create_test_data(count: int = 10) -> None: @@ -68,17 +68,19 @@ def get_pending_letter_ids( deadline = time.monotonic() + timeout_s data = [] while time.monotonic() < deadline: + # Retrieves letters based on the supplier registered in the Apigee App response = requests.get( - f"{url}/{letters_endpoint}?limit={limit}", headers=headers + f"{url}{letters_endpoint}?limit={limit}", headers=headers ) ErrorHandler.handle_retry(response) response.raise_for_status() data.extend(response.json().get("data", [])) if len(data) >= limit: + print(f"Created and found letters with IDs {[item.get('id') for item in data]} for supplier registered in the Apigee App, to which the proxy is associated") return [item.get("id") for item in data] time.sleep(interval_s) raise TimeoutError( f"Timed out after {retries} retries waiting for {limit} PENDING letter(s) at " - f"{url}/{letters_endpoint}" + f"{url}{letters_endpoint}" )