From 4429141085ed93fee7c4af73e3d395817b6158df Mon Sep 17 00:00:00 2001 From: Mikolaj Miotk Date: Tue, 14 Apr 2026 18:27:07 +0200 Subject: [PATCH 1/4] [HOTE-803] feat: Add some improvements to E2E tests --- .github/workflows/playwright-e2e.yaml | 43 ++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright-e2e.yaml b/.github/workflows/playwright-e2e.yaml index de89ecea..1be2b39b 100644 --- a/.github/workflows/playwright-e2e.yaml +++ b/.github/workflows/playwright-e2e.yaml @@ -97,7 +97,7 @@ jobs: - name: "Start the application" if: env.TARGET_ENV == 'local' run: | - npm run start + npm run local:start - name: "Show application status" if: env.TARGET_ENV == 'local' @@ -179,6 +179,34 @@ jobs: docker compose -f local-environment/docker-compose.yml logs "$service" > "tests/testResults/docker-compose-${service}.log" 2>&1 done + - name: "Detect flaky tests" + if: always() + run: | + RESULTS_FILE="tests/testResults/test-results.json" + if [ ! -f "$RESULTS_FILE" ]; then + echo "No test results JSON found, skipping flaky detection" + exit 0 + fi + + # Extract flaky tests from Playwright JSON results + FLAKY_TESTS=$(jq -r ' + [.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | + if length > 0 then + .[] | "\(.title) (\(.location.file):\(.location.line))" + else + empty + end + ' "$RESULTS_FILE" 2>/dev/null) + + if [ -n "$FLAKY_TESTS" ]; then + echo "::warning::Flaky tests detected (passed on retry):" + while IFS= read -r test; do + echo "::warning:: Flaky: $test" + done <<< "$FLAKY_TESTS" + else + echo "No flaky tests detected" + fi + - name: "Publish Test Results" uses: dorny/test-reporter@v3 if: always() @@ -210,6 +238,19 @@ jobs: echo ":warning: No test results found" >> $GITHUB_STEP_SUMMARY fi + # Append flaky test details to summary + RESULTS_FILE="tests/testResults/test-results.json" + if [ -f "$RESULTS_FILE" ]; then + FLAKY_COUNT=$(jq '[.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | length' "$RESULTS_FILE" 2>/dev/null || echo 0) + if [ "$FLAKY_COUNT" -gt 0 ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "### :warning: Flaky Tests ($FLAKY_COUNT)" >> $GITHUB_STEP_SUMMARY + echo "These tests failed initially but passed on retry:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + jq -r '[.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | .[] | "- **\(.title)** (\(.location.file):\(.location.line))"' "$RESULTS_FILE" 2>/dev/null >> $GITHUB_STEP_SUMMARY + fi + fi + - name: "Upload test results" uses: actions/upload-artifact@v7 if: always() From 1c8f2fbbe22123fe229bca38a6c7019be3f6dd30 Mon Sep 17 00:00:00 2001 From: Mikolaj Miotk Date: Tue, 14 Apr 2026 18:49:40 +0200 Subject: [PATCH 2/4] add timeout --- .github/workflows/playwright-e2e.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/playwright-e2e.yaml b/.github/workflows/playwright-e2e.yaml index 1be2b39b..2de89f37 100644 --- a/.github/workflows/playwright-e2e.yaml +++ b/.github/workflows/playwright-e2e.yaml @@ -91,6 +91,7 @@ jobs: playwright-${{ runner.os }}- - name: "Install Playwright browsers" + timeout-minutes: 3 working-directory: tests run: npx playwright install --with-deps From 1647350a5731139c9404b687be92779d6ffab828 Mon Sep 17 00:00:00 2001 From: Mikolaj Miotk Date: Tue, 14 Apr 2026 18:52:36 +0200 Subject: [PATCH 3/4] add parallelistation to tf --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9362d8c..8a8e10e8 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "local:terraform": "terraform -chdir=local-environment/infra", "local:terraform:init": "npm run local:terraform -- init", "local:terraform:plan": "npm run local:terraform -- plan", - "local:terraform:apply": "bash local-environment/scripts/localstack/ensure-localstack-running.sh && npm run local:terraform -- apply -auto-approve && npm run local:terraform:env", + "local:terraform:apply": "bash local-environment/scripts/localstack/ensure-localstack-running.sh && npm run local:terraform -- apply -auto-approve -parallelism=30 && npm run local:terraform:env", "local:terraform:destroy": "npm run local:terraform -- destroy -auto-approve", "local:terraform:env": "bash scripts/terraform/post-apply-env-update.sh", "local:compose": "docker compose -f local-environment/docker-compose.yml", From 18c94b694c350a0d8d2ae767498f493086454662 Mon Sep 17 00:00:00 2001 From: Mikolaj Miotk Date: Tue, 14 Apr 2026 19:07:12 +0200 Subject: [PATCH 4/4] remove unneeded depends_on --- .github/workflows/playwright-e2e.yaml | 30 +- local-environment/infra/main.tf | 433 ++++++++---------- .../infra/modules/lambda/main.tf | 9 +- .../infra/modules/lambda/variables.tf | 6 +- package.json | 4 +- 5 files changed, 229 insertions(+), 253 deletions(-) diff --git a/.github/workflows/playwright-e2e.yaml b/.github/workflows/playwright-e2e.yaml index 2de89f37..92089de8 100644 --- a/.github/workflows/playwright-e2e.yaml +++ b/.github/workflows/playwright-e2e.yaml @@ -99,6 +99,9 @@ jobs: if: env.TARGET_ENV == 'local' run: | npm run local:start + env: + BUILDKIT_PROGRESS: plain # or "quiet" to fully suppress build output + DOCKER_CLI_HINTS: false # removes "What's next?" hints - name: "Show application status" if: env.TARGET_ENV == 'local' @@ -189,17 +192,17 @@ jobs: exit 0 fi - # Extract flaky tests from Playwright JSON results - FLAKY_TESTS=$(jq -r ' - [.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | - if length > 0 then - .[] | "\(.title) (\(.location.file):\(.location.line))" - else - empty - end - ' "$RESULTS_FILE" 2>/dev/null) + # Check top-level stats for flaky count first + FLAKY_COUNT=$(jq '.stats.flaky // 0' "$RESULTS_FILE" 2>/dev/null || echo 0) + echo "Flaky test count: $FLAKY_COUNT" + + if [ "$FLAKY_COUNT" -gt 0 ]; then + # Extract flaky test details: specs contain tests, status is on test objects + FLAKY_TESTS=$(jq -r ' + [.. | .specs?[]? | {title: .title, file: .file, line: .line, tests: [.tests[]? | select(.status == "flaky") | .projectName]} | select(.tests | length > 0)] + | .[] | "[\(.tests | join(", "))] \(.title) (\(.file):\(.line))" + ' "$RESULTS_FILE" 2>/dev/null) - if [ -n "$FLAKY_TESTS" ]; then echo "::warning::Flaky tests detected (passed on retry):" while IFS= read -r test; do echo "::warning:: Flaky: $test" @@ -242,13 +245,16 @@ jobs: # Append flaky test details to summary RESULTS_FILE="tests/testResults/test-results.json" if [ -f "$RESULTS_FILE" ]; then - FLAKY_COUNT=$(jq '[.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | length' "$RESULTS_FILE" 2>/dev/null || echo 0) + FLAKY_COUNT=$(jq '.stats.flaky // 0' "$RESULTS_FILE" 2>/dev/null || echo 0) if [ "$FLAKY_COUNT" -gt 0 ]; then echo "" >> $GITHUB_STEP_SUMMARY echo "### :warning: Flaky Tests ($FLAKY_COUNT)" >> $GITHUB_STEP_SUMMARY echo "These tests failed initially but passed on retry:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - jq -r '[.suites[]? | .. | .tests?[]? | select(.status == "flaky")] | .[] | "- **\(.title)** (\(.location.file):\(.location.line))"' "$RESULTS_FILE" 2>/dev/null >> $GITHUB_STEP_SUMMARY + jq -r ' + [.. | .specs?[]? | {title: .title, file: .file, line: .line, tests: [.tests[]? | select(.status == "flaky") | .projectName]} | select(.tests | length > 0)] + | .[] | "- **[\(.tests | join(", "))] \(.title)** (\(.file):\(.line))" + ' "$RESULTS_FILE" 2>/dev/null >> $GITHUB_STEP_SUMMARY fi fi diff --git a/local-environment/infra/main.tf b/local-environment/infra/main.tf index 6dff99cf..80154cf1 100644 --- a/local-environment/infra/main.tf +++ b/local-environment/infra/main.tf @@ -89,6 +89,41 @@ locals { resolved_supplier_service_url = var.local_supplier_service_url_override != null ? var.local_supplier_service_url_override : local.wiremock_container_base_url resolved_use_wiremock_auth = local.resolved_nhs_login_override_container_base_url != null ? length(regexall("wiremock", lower(local.resolved_nhs_login_override_container_base_url))) > 0 : local.use_wiremock_mode + + # Common DB environment variables shared across multiple lambdas + common_db_env = { + DB_USERNAME = "app_user" + DB_ADDRESS = "postgres-db" + DB_PORT = "5432" + DB_NAME = "local_hometest_db" + DB_SCHEMA = "hometest" + DB_SECRET_NAME = "postgres-db-password" + DB_SSL = "false" + } + + # Common base env for all lambdas + common_base_env = { + NODE_OPTIONS = "--enable-source-maps" + ALLOW_ORIGIN = "http://localhost:3000" + } + + # Common CORS settings shared across multiple lambdas + common_cors = { + enable_cors = true + cors_allow_origin = "http://localhost:3000" + cors_allow_credentials = true + } + + # Common lambda module parameters + common_lambda_params = { + project_name = var.project_name + lambda_role_arn = aws_iam_role.lambda_role.arn + environment = var.environment + aws_region = var.aws_region + api_gateway_id = aws_api_gateway_rest_api.api.id + api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id + api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn + } } # Fail early if required secrets are missing @@ -186,63 +221,51 @@ resource "aws_api_gateway_rest_api" "api" { module "eligibility_lookup_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "eligibility-lookup-lambda" - zip_path = "${path.module}/../../lambdas/dist/eligibility-lookup-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "eligibility-lookup" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - http_method = "GET" - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "eligibility-lookup-lambda" + zip_path = "${path.module}/../../lambdas/dist/eligibility-lookup-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "eligibility-lookup" + http_method = "GET" + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["GET", "OPTIONS"] cors_allow_headers = ["Content-Type", "Authorization"] - cors_allow_credentials = true + cors_allow_credentials = local.common_cors.cors_allow_credentials - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - ALLOW_ORIGIN = "http://localhost:3000" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" - } + environment_variables = merge(local.common_base_env, local.common_db_env) } # Login Lambda module "login_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "login" - zip_path = "${path.module}/../../lambdas/dist/login-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "login" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - http_method = "POST" - timeout = 30 - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "login" + zip_path = "${path.module}/../../lambdas/dist/login-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "login" + http_method = "POST" + timeout = 30 + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["POST", "OPTIONS"] cors_allow_headers = ["Content-Type", "Authorization"] - cors_allow_credentials = true + cors_allow_credentials = local.common_cors.cors_allow_credentials - environment_variables = { - NODE_OPTIONS = "--enable-source-maps", - ALLOW_ORIGIN = "http://localhost:3000", + environment_variables = merge(local.common_base_env, { NHS_LOGIN_BASE_ENDPOINT_URL = local.resolved_nhs_login_base_url, NHS_LOGIN_CLIENT_ID = "hometest", NHS_LOGIN_REDIRECT_URL = "http://localhost:3000/callback", @@ -252,58 +275,54 @@ module "login_lambda" { AUTH_REFRESH_TOKEN_EXPIRY_DURATION_MINUTES = "60", AUTH_COOKIE_SAME_SITE = "Lax" AUTH_COOKIE_SECURE = "false" - } + }) } module "session_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "session" - zip_path = "${path.module}/../../lambdas/dist/session-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "session" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - http_method = "GET" - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "session" + zip_path = "${path.module}/../../lambdas/dist/session-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "session" + http_method = "GET" + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["GET", "OPTIONS"] cors_allow_headers = ["Content-Type", "Authorization"] - cors_allow_credentials = true + cors_allow_credentials = local.common_cors.cors_allow_credentials - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - ALLOW_ORIGIN = "http://localhost:3000" + environment_variables = merge(local.common_base_env, { AUTH_COOKIE_KEY_ID = "key" AUTH_COOKIE_PUBLIC_KEY_SECRET_NAME = "nhs-login-private-key" NHS_LOGIN_BASE_ENDPOINT_URL = local.resolved_nhs_login_base_url, - } + }) } # Postcode Lookup Lambda module "postcode_lookup_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "postcode-lookup" - zip_path = "${path.module}/../../lambdas/dist/postcode-lookup-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "postcode-lookup" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - http_method = "GET" - - environment_variables = { - NODE_OPTIONS = "--enable-source-maps", - ALLOW_ORIGIN = "http://localhost:3000", + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "postcode-lookup" + zip_path = "${path.module}/../../lambdas/dist/postcode-lookup-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "postcode-lookup" + http_method = "GET" + + environment_variables = merge(local.common_base_env, { POSTCODE_LOOKUP_CREDENTIALS_SECRET_NAME = "os-places-creds", POSTCODE_LOOKUP_BASE_URL = local.resolved_postcode_lookup_base_url, POSTCODE_LOOKUP_TIMEOUT_MS = "5000", @@ -311,22 +330,22 @@ module "postcode_lookup_lambda" { POSTCODE_LOOKUP_RETRY_DELAY_MS = "1000", POSTCODE_LOOKUP_RETRY_BACKOFF_FACTOR = "2", USE_STUB_POSTCODE_CLIENT = false, - } + }) } module "hello_world_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "hello-world" - zip_path = "${path.module}/../../lambdas/dist/hello-world-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "hello-world" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "hello-world" + zip_path = "${path.module}/../../lambdas/dist/hello-world-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "hello-world" environment_variables = { NODE_OPTIONS = "--enable-source-maps" @@ -344,27 +363,20 @@ resource "aws_sqs_queue" "notify_messages" { module "order_router_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "order-router" - zip_path = "${path.module}/../../lambdas/dist/order-router-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "test-order/order" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" - } + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "order-router" + zip_path = "${path.module}/../../lambdas/dist/order-router-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "test-order/order" + + environment_variables = merge(local.common_db_env, { + NODE_OPTIONS = "--enable-source-maps" + }) } resource "aws_lambda_event_source_mapping" "order_router_order_placement" { @@ -377,161 +389,114 @@ resource "aws_lambda_event_source_mapping" "order_router_order_placement" { module "order_result_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "order-result" - zip_path = "${path.module}/../../lambdas/dist/order-result-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "result" - http_method = "POST" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - ALLOW_ORIGIN = "http://localhost:3000" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "order-result" + zip_path = "${path.module}/../../lambdas/dist/order-result-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "result" + http_method = "POST" + + environment_variables = merge(local.common_base_env, local.common_db_env, { NOTIFY_MESSAGES_QUEUE_URL = aws_sqs_queue.notify_messages.url HOME_TEST_BASE_URL = "http://localhost:3000" - } + }) } module "order_service_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "order-service" - zip_path = "${path.module}/../../lambdas/dist/order-service-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "order" - http_method = "POST" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "order-service" + zip_path = "${path.module}/../../lambdas/dist/order-service-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "order" + http_method = "POST" + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["POST", "OPTIONS"] cors_allow_headers = ["Content-Type", "Authorization", "X-Correlation-ID"] - cors_allow_credentials = true + cors_allow_credentials = local.common_cors.cors_allow_credentials - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" + environment_variables = merge(local.common_base_env, local.common_db_env, { ORDER_PLACEMENT_QUEUE_URL = aws_sqs_queue.order_placement.url - ALLOW_ORIGIN = "http://localhost:3000" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" - } + }) } module "get_order_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "get-order" - zip_path = "${path.module}/../../lambdas/dist/get-order-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "get-order" - http_method = "GET" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "get-order" + zip_path = "${path.module}/../../lambdas/dist/get-order-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "get-order" + http_method = "GET" + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["GET", "OPTIONS"] - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - ALLOW_ORIGIN = "http://localhost:3000" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" - } + environment_variables = merge(local.common_base_env, local.common_db_env) } module "get_results_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "get-results" - zip_path = "${path.module}/../../lambdas/dist/get-results-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "results" - http_method = "GET" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - enable_cors = true - cors_allow_origin = "http://localhost:3000" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "get-results" + zip_path = "${path.module}/../../lambdas/dist/get-results-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "results" + http_method = "GET" + + enable_cors = local.common_cors.enable_cors + cors_allow_origin = local.common_cors.cors_allow_origin cors_allow_methods = ["GET", "OPTIONS"] cors_allow_headers = ["Content-Type", "Authorization", "X-Requested-With", "X-Correlation-ID"] - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" - ALLOW_ORIGIN = "http://localhost:3000" - } + environment_variables = merge(local.common_base_env, local.common_db_env) } module "order_status_lambda" { source = "./modules/lambda" - project_name = var.project_name - function_name = "order-status" - zip_path = "${path.module}/../../lambdas/dist/order-status-lambda.zip" - lambda_role_arn = aws_iam_role.lambda_role.arn - environment = var.environment - api_gateway_id = aws_api_gateway_rest_api.api.id - api_gateway_root_resource_id = aws_api_gateway_rest_api.api.root_resource_id - api_gateway_execution_arn = aws_api_gateway_rest_api.api.execution_arn - api_path = "test-order/status" - http_method = "POST" - lambda_role_policy_attachment = aws_iam_role_policy_attachment.lambda_basic - - environment_variables = { - NODE_OPTIONS = "--enable-source-maps" - ALLOW_ORIGIN = "http://localhost:3000" - DB_USERNAME = "app_user" - DB_ADDRESS = "postgres-db" - DB_PORT = "5432" - DB_NAME = "local_hometest_db" - DB_SCHEMA = "hometest" - DB_SECRET_NAME = "postgres-db-password" - DB_SSL = "false" + project_name = local.common_lambda_params.project_name + aws_region = local.common_lambda_params.aws_region + function_name = "order-status" + zip_path = "${path.module}/../../lambdas/dist/order-status-lambda.zip" + lambda_role_arn = local.common_lambda_params.lambda_role_arn + environment = local.common_lambda_params.environment + api_gateway_id = local.common_lambda_params.api_gateway_id + api_gateway_root_resource_id = local.common_lambda_params.api_gateway_root_resource_id + api_gateway_execution_arn = local.common_lambda_params.api_gateway_execution_arn + api_path = "test-order/status" + http_method = "POST" + + environment_variables = merge(local.common_base_env, local.common_db_env, { NOTIFY_MESSAGES_QUEUE_URL = aws_sqs_queue.notify_messages.url HOME_TEST_BASE_URL = "http://localhost:3000" - } + }) } # API Gateway deployment diff --git a/local-environment/infra/modules/lambda/main.tf b/local-environment/infra/modules/lambda/main.tf index e188e997..7e37e356 100644 --- a/local-environment/infra/modules/lambda/main.tf +++ b/local-environment/infra/modules/lambda/main.tf @@ -10,8 +10,6 @@ resource "aws_lambda_function" "this" { environment { variables = var.environment_variables } - - depends_on = [var.lambda_role_policy_attachment] } locals { @@ -52,7 +50,7 @@ resource "aws_api_gateway_integration" "this" { integration_http_method = "POST" type = "AWS_PROXY" - uri = "arn:aws:apigateway:${data.aws_region.current.id}:lambda:path/2015-03-31/functions/${aws_lambda_function.this.arn}/invocations" + uri = "arn:aws:apigateway:${local.resolved_region}:lambda:path/2015-03-31/functions/${aws_lambda_function.this.arn}/invocations" } resource "aws_lambda_permission" "this" { @@ -63,9 +61,12 @@ resource "aws_lambda_permission" "this" { source_arn = "${var.api_gateway_execution_arn}/*/*" } -data "aws_region" "current" {} +data "aws_region" "current" { + count = var.aws_region == "" ? 1 : 0 +} locals { + resolved_region = var.aws_region != "" ? var.aws_region : data.aws_region.current[0].id cors_allow_methods = join(", ", var.cors_allow_methods) cors_allow_headers = join(", ", [for header in var.cors_allow_headers : lower(header)]) } diff --git a/local-environment/infra/modules/lambda/variables.tf b/local-environment/infra/modules/lambda/variables.tf index 7b3b1bbc..9927db25 100644 --- a/local-environment/infra/modules/lambda/variables.tf +++ b/local-environment/infra/modules/lambda/variables.tf @@ -3,6 +3,11 @@ variable "function_name" { type = string } variable "environment" { type = string } variable "zip_path" { type = string } variable "lambda_role_arn" { type = string } +variable "aws_region" { + type = string + default = "" + description = "AWS region. If empty, falls back to data.aws_region lookup." +} variable "handler" { type = string default = "index.handler" @@ -29,7 +34,6 @@ variable "authorization" { type = string default = "NONE" } -variable "lambda_role_policy_attachment" {} variable "enable_cors" { type = bool diff --git a/package.json b/package.json index 8a8e10e8..fa9cf181 100644 --- a/package.json +++ b/package.json @@ -30,10 +30,10 @@ "local:service:localstack:start": "npm run local:compose:up -- localstack", "local:service:localstack:stop": "npm run local:compose:down -- localstack", "local:terraform": "terraform -chdir=local-environment/infra", - "local:terraform:init": "npm run local:terraform -- init", + "local:terraform:init": "npm run local:terraform -- init -input=false", "local:terraform:plan": "npm run local:terraform -- plan", "local:terraform:apply": "bash local-environment/scripts/localstack/ensure-localstack-running.sh && npm run local:terraform -- apply -auto-approve -parallelism=30 && npm run local:terraform:env", - "local:terraform:destroy": "npm run local:terraform -- destroy -auto-approve", + "local:terraform:destroy": "npm run local:terraform -- destroy -auto-approve -parallelism=30", "local:terraform:env": "bash scripts/terraform/post-apply-env-update.sh", "local:compose": "docker compose -f local-environment/docker-compose.yml", "local:compose:up": "npm run local:compose -- up -d",