Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions database/03-seed-hometest-data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ INSERT INTO supplier (
VALUES (
'c1a2b3c4-1234-4def-8abc-123456789abc',
'Preventx',
'http://wiremock:8080',
'http://mock-service-placeholder',
'https://www.preventx.com/',
'test_supplier_client_secret',
'preventx-client-id',
Expand All @@ -49,7 +49,7 @@ INSERT INTO supplier (
VALUES (
'd2b3c4d5-2345-4abc-8def-23456789abcd',
'SH:24',
'http://wiremock:8080',
'http://mock-service-placeholder',
'https://sh24.org.uk/',
'test_supplier_client_secret',
'sh24-client-id',
Expand Down
12 changes: 0 additions & 12 deletions local-environment/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,6 @@ services:
timeout: 5s
retries: 10

wiremock:
image: wiremock/wiremock:latest
container_name: wiremock
profiles:
- backend
ports:
- "8080:8080"
volumes:
- ./wiremock/mappings:/home/wiremock/mappings
- ./wiremock/__files:/home/wiremock/__files
command: ["--verbose"]

db-migrate:
build:
context: ./scripts/database
Expand Down
105 changes: 105 additions & 0 deletions local-environment/infra/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -538,3 +538,108 @@ resource "aws_api_gateway_stage" "api_stage" {
data "external" "supplier_id" {
program = ["bash", "${path.module}/../scripts/localstack/get_supplier_id.sh"]
}

################################################################################
# Mock Service — replaces WireMock container
# Runs as a Lambda on LocalStack with its own API Gateway (proxy integration)
################################################################################

resource "aws_api_gateway_rest_api" "mock_api" {
name = "${var.project_name}-mock-api"
description = "Mock API for supplier, Cognito JWKS, postcode lookup"
}

resource "aws_lambda_function" "mock_service" {
filename = "${path.module}/../../mock-service/dist/mock-service-lambda.zip"
function_name = "${var.project_name}-mock-service"
role = aws_iam_role.lambda_role.arn
handler = "bootstrap"
runtime = "provided.al2023"
architectures = ["arm64"]
source_code_hash = filebase64sha256("${path.module}/../../mock-service/dist/mock-service-lambda.zip")
timeout = 30

environment {
variables = {
ENVIRONMENT = var.environment
}
}

depends_on = [aws_iam_role_policy_attachment.lambda_basic]
}

# Proxy resource: {proxy+}
resource "aws_api_gateway_resource" "mock_proxy" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id
parent_id = aws_api_gateway_rest_api.mock_api.root_resource_id
path_part = "{proxy+}"
}

resource "aws_api_gateway_method" "mock_proxy_any" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id
resource_id = aws_api_gateway_resource.mock_proxy.id
http_method = "ANY"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "mock_proxy" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id
resource_id = aws_api_gateway_resource.mock_proxy.id
http_method = aws_api_gateway_method.mock_proxy_any.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${var.aws_region}:lambda:path/2015-03-31/functions/${aws_lambda_function.mock_service.arn}/invocations"
}

resource "aws_api_gateway_method" "mock_root" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id
resource_id = aws_api_gateway_rest_api.mock_api.root_resource_id
http_method = "ANY"
authorization = "NONE"
}

resource "aws_api_gateway_integration" "mock_root" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id
resource_id = aws_api_gateway_rest_api.mock_api.root_resource_id
http_method = aws_api_gateway_method.mock_root.http_method
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "arn:aws:apigateway:${var.aws_region}:lambda:path/2015-03-31/functions/${aws_lambda_function.mock_service.arn}/invocations"
}

resource "aws_lambda_permission" "mock_api_gateway" {
statement_id = "AllowMockAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.mock_service.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.mock_api.execution_arn}/*/*"
}

resource "aws_api_gateway_deployment" "mock_deployment" {
rest_api_id = aws_api_gateway_rest_api.mock_api.id

depends_on = [
aws_api_gateway_integration.mock_proxy,
aws_api_gateway_integration.mock_root,
]

triggers = {
redeployment = sha1(jsonencode([
aws_api_gateway_resource.mock_proxy.id,
aws_api_gateway_method.mock_proxy_any.id,
aws_api_gateway_integration.mock_proxy.id,
aws_api_gateway_method.mock_root.id,
aws_api_gateway_integration.mock_root.id,
]))
}

lifecycle {
create_before_destroy = true
}
}

resource "aws_api_gateway_stage" "mock_stage" {
deployment_id = aws_api_gateway_deployment.mock_deployment.id
rest_api_id = aws_api_gateway_rest_api.mock_api.id
stage_name = var.environment
}
31 changes: 30 additions & 1 deletion local-environment/infra/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ output "postcode_lookup_endpoint" {

output "seed_supplier_id" {
value = data.external.supplier_id.result["supplier_id"]
description = "The supplier_id of the seeded supplier with service_url http://wiremock:8080"
description = "The supplier_id of the seeded supplier (service_url points at mock-service Lambda on LocalStack)"
}

output "order_placement_queue_url" {
Expand All @@ -87,3 +87,32 @@ output "order_status_endpoint" {
description = "Order Status Lambda endpoint"
value = module.order_status_lambda.localstack_endpoint_url
}

################################################################################
# Mock Service Outputs
################################################################################

output "mock_api_base_url" {
description = "Base URL for the mock API on LocalStack"
value = "http://localhost:4566/_aws/execute-api/${aws_api_gateway_rest_api.mock_api.id}/${var.environment}"
}

output "mock_supplier_base_url" {
description = "Supplier mock base URL (use as service_url in supplier table)"
value = "http://localstack-main:4566/_aws/execute-api/${aws_api_gateway_rest_api.mock_api.id}/${var.environment}/mock/supplier"
}

output "mock_supplier_base_url_host" {
description = "Supplier mock base URL accessible from host machine"
value = "http://localhost:4566/_aws/execute-api/${aws_api_gateway_rest_api.mock_api.id}/${var.environment}/mock/supplier"
}

output "mock_cognito_jwks_url" {
description = "Mock Cognito JWKS URL"
value = "http://localhost:4566/_aws/execute-api/${aws_api_gateway_rest_api.mock_api.id}/${var.environment}/mock/cognito/.well-known/jwks.json"
}
Comment on lines +95 to +113

output "mock_postcode_base_url" {
description = "Mock postcode lookup base URL"
value = "http://localhost:4566/_aws/execute-api/${aws_api_gateway_rest_api.mock_api.id}/${var.environment}/mock/postcode"
}
17 changes: 17 additions & 0 deletions local-environment/wiremock/mappings/health.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"priority": 1,
"request": {
"method": "GET",
"urlPath": "/health"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"status": "ok",
"service": "mock-service"
}
}
}
26 changes: 26 additions & 0 deletions local-environment/wiremock/mappings/jwks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"priority": 1,
"request": {
"method": "GET",
"urlPathPattern": "/\\.well-known/jwks(\\.json)?"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=3600"
},
"jsonBody": {
"keys": [
{
"kty": "RSA",
"kid": "mock-key-1",
"use": "sig",
"alg": "RS256",
"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"e": "AQAB"
}
]
}
}
}
22 changes: 22 additions & 0 deletions local-environment/wiremock/mappings/postcode-lookup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"priority": 5,
"request": {
"method": "GET",
"urlPathPattern": "/postcode/[A-Za-z0-9%20 ]+"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"postcode": "SW1A 1AA",
"localAuthority": {
"code": "E09000033",
"name": "City of Westminster"
},
"country": "England",
"region": "London"
}
}
}
17 changes: 17 additions & 0 deletions local-environment/wiremock/mappings/postcode-not-found.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"priority": 3,
"request": {
"method": "GET",
"urlPathPattern": "/postcode/INVALID.*"
},
"response": {
"status": 404,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"error": "Not Found",
"message": "Postcode not found"
}
}
}
13 changes: 13 additions & 0 deletions mock-service/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = "mock-service"
version = "0.1.0"
edition = "2021"

[dependencies]
lambda_http = "0.13"
lambda_runtime = "0.13"
tokio = { version = "1", features = ["full"] }
stubr = "0.6"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
Loading
Loading