Skip to content

Commit 30a0963

Browse files
darklight3itDavide Melfi
andauthored
Introducing Harness Testing (#1103)
* refactor: ♻️ adding a new script that selectively builds specific examples * refactor: ♻️ add a custom lambda-entrypoint to select different binaries when called in the dockerfile. * refactor: ♻️ modifying dockerfile to include both the build script and the custom entrypoint. Changing test-rie signature. * refactor: :recycle add nuke continaers to the makefile * test: ✨ add harness testing capability * refactor: ♻️ some small fixes --------- Co-authored-by: Davide Melfi <dmelfi@amazon.com>
1 parent c94398f commit 30a0963

10 files changed

Lines changed: 244 additions & 16 deletions

File tree

.env

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Test configuration for RIE and dockerized tests
2+
# Customize these values as needed for testing both local and on github
3+
4+
# Handlers to build
5+
HANDLERS_TO_BUILD=basic-lambda
6+
7+
HANDLER=basic-lambda
8+
9+
# Output directory for built binaries
10+
OUTPUT_DIR=test/dockerized/tasks
11+
12+
# Max concurrent Lambda invocations for LMI mode
13+
RIE_MAX_CONCURRENCY=4
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: dockerized-test
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
push:
8+
branches: [ main ]
9+
pull_request:
10+
branches: [ '*' ]
11+
workflow_dispatch:
12+
13+
14+
jobs:
15+
dockerized-test:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v6
19+
20+
- uses: dtolnay/rust-toolchain@stable
21+
- uses: Swatinem/rust-cache@v2
22+
- name: Load environment variables
23+
run: |
24+
if [ -f .env ]; then
25+
set -a
26+
source .env
27+
set +a
28+
echo "HANDLERS_TO_BUILD=${HANDLERS_TO_BUILD}" >> $GITHUB_ENV
29+
echo "OUTPUT_DIR=${OUTPUT_DIR}" >> $GITHUB_ENV
30+
fi
31+
32+
- name: Build Lambda artifacts for testing
33+
run: |
34+
mkdir -p test/dockerized/tasks
35+
OUTPUT_DIR="$(pwd)/test/dockerized/tasks" make build-examples
36+
ls -la test/dockerized/tasks/
37+
38+
- name: Build base test image with RIE and custom entrypoint
39+
run: |
40+
docker build . -t local/test-base -f Dockerfile.test
41+
42+
- name: Run tests
43+
uses: aws/containerized-test-runner-for-aws-lambda@main
44+
with:
45+
suiteFileArray: '["./test/dockerized/suites/*.json"]'
46+
dockerImageName: 'local/test-base'
47+
taskFolder: './test/dockerized/tasks'

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ target
33
lambda-runtime/libtest.rmeta
44
lambda-integration-tests/target
55
Cargo.lock
6+
.test-runner
67

78
# Built AWS Lambda zipfile
89
lambda.zip
@@ -16,3 +17,7 @@ build
1617

1718
node_modules
1819
cdk.out
20+
21+
# Test artifacts
22+
Dockerfile.test-with-tasks
23+
test/dockerized/tasks/

Dockerfile.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM public.ecr.aws/lambda/provided:al2023
2+
3+
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/local/bin/aws-lambda-rie
4+
RUN chmod +x /usr/local/bin/aws-lambda-rie
5+
6+
COPY scripts/custom-lambda-entrypoint.sh /usr/local/bin/lambda-entrypoint
7+
RUN chmod +x /usr/local/bin/lambda-entrypoint
8+
9+
ENTRYPOINT ["/usr/local/bin/lambda-entrypoint"]
10+
CMD ["basic-lambda"]

Makefile

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ INTEG_EXTENSIONS := extension-fn extension-trait logs-trait
66
# Using musl to run extensions on both AL1 and AL2
77
INTEG_ARCH := x86_64-unknown-linux-musl
88
RIE_MAX_CONCURRENCY ?= 4
9+
OUTPUT_DIR ?= test/dockerized/tasks
10+
HANDLERS_TO_BUILD ?=
11+
HANDLER ?=
12+
13+
# Load environment variables from .env file if it exists
14+
-include .env
15+
export
16+
17+
.PHONY: help pr-check integration-tests check-event-features fmt build-examples test-rie test-rie-lmi nuke test-dockerized
18+
19+
.DEFAULT_GOAL := help
920

1021
define uppercase
1122
$(shell sed -r 's/(^|-)(\w)/\U\2/g' <<< $(1))
@@ -112,9 +123,68 @@ check-event-features:
112123
fmt:
113124
cargo +nightly fmt --all
114125

126+
build-examples:
127+
HANDLERS_TO_BUILD=${HANDLERS_TO_BUILD} OUTPUT_DIR=${OUTPUT_DIR} ./scripts/build-examples.sh
128+
129+
nuke:
130+
docker kill $$(docker ps -q)
131+
132+
test-dockerized: build-examples
133+
@echo "Running dockerized tests locally..."
134+
135+
@echo "Building base Docker image with RIE and custom entrypoint..."
136+
docker build \
137+
-t local/test-base \
138+
-f Dockerfile.test \
139+
.
140+
141+
@echo "Setting up containerized test runner..."
142+
@if [ ! -d ".test-runner" ]; then \
143+
echo "Cloning containerized-test-runner-for-aws-lambda..."; \
144+
git clone --quiet https://github.com/aws/containerized-test-runner-for-aws-lambda.git .test-runner; \
145+
fi
146+
@echo "Building test runner Docker image..."
147+
@docker build -t test-runner:local -f .test-runner/Dockerfile .test-runner
148+
149+
@echo "Running tests in Docker..."
150+
@docker run --rm \
151+
-e INPUT_SUITE_FILE_ARRAY='["./test/dockerized/suites/*.json"]' \
152+
-e DOCKER_IMAGE_NAME=local/test-base \
153+
-e TASK_FOLDER=./test/dockerized/tasks \
154+
-e GITHUB_WORKSPACE=/workspace \
155+
-v /var/run/docker.sock:/var/run/docker.sock \
156+
-v "$(CURDIR):/workspace" \
157+
-w /workspace \
158+
test-runner:local
159+
115160
test-rie:
116-
./scripts/test-rie.sh $(EXAMPLE)
161+
HANDLER="$(HANDLER)" ./scripts/test-rie.sh
117162

118163
# Run RIE in Lambda Managed Instance (LMI) mode with concurrent polling.
119164
test-rie-lmi:
120-
RIE_MAX_CONCURRENCY=$(RIE_MAX_CONCURRENCY) ./scripts/test-rie.sh $(EXAMPLE)
165+
RIE_MAX_CONCURRENCY=$(RIE_MAX_CONCURRENCY) HANDLER="$(HANDLER)" ./scripts/test-rie.sh $(EXAMPLE)
166+
167+
help: ## Show this help message
168+
@echo 'Usage: make [target]'
169+
@echo ''
170+
@echo 'Available targets:'
171+
@echo ' pr-check Run pre-commit checks (fmt, clippy, tests)'
172+
@echo ' integration-tests Build and run AWS integration tests'
173+
@echo ' check-event-features Test individual event features'
174+
@echo ' fmt Format code with cargo fmt'
175+
@echo ' build-examples Build example Lambda functions'
176+
@echo ' Usage: EXAMPLES="basic-lambda" OUTPUT_DIR=/make build-examples'
177+
@echo ' test-rie Test Lambda with Runtime Interface Emulator'
178+
@echo ' Usage: HANDLERS_TO_BUILD="basic-lambda basic-sqs" make test-rie'
179+
@echo ' Usage: HANDLERS_TO_BUILD="basic-lambda" HANDLER="basic-lambda" make test-rie'
180+
@echo ' test-rie-lmi Test RIE in Lambda Managed Instance mode'
181+
@echo ' Usage: RIE_MAX_CONCURRENCY=4 HANDLERS_TO_BUILD="basic-lambda-concurrent" make test-rie-lmi'
182+
@echo ' test-dockerized Run dockerized test harness'
183+
@echo ' nuke Kill all running Docker containers'
184+
@echo ''
185+
@echo 'Environment variables:'
186+
@echo ' EXAMPLES Space-separated list of examples to build (for build-examples)'
187+
@echo ' HANDLERS_TO_BUILD Space-separated list of handlers to build for RIE (for test-rie)'
188+
@echo ' HANDLER Specific handler to run (defaults to first in HANDLERS_TO_BUILD)'
189+
@echo ' OUTPUT_DIR Directory for built binaries (default: /tmp/var-task for build-examples, /var/task for Docker)'
190+
@echo ' RIE_MAX_CONCURRENCY Max concurrent Lambda invocations for LMI mode (for test-rie-lmi)'

README.md

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -392,34 +392,60 @@ You can read more about how [cargo lambda watch](https://www.cargo-lambda.info/c
392392

393393
### Local testing with Runtime Interface Emulator (RIE)
394394

395-
For testing with the official AWS Lambda Runtime Interface Emulator, use the provided RIE testing infrastructure:
395+
For testing with the official AWS Lambda Runtime Interface Emulator:
396396

397397
```bash
398398
make test-rie
399399
```
400400

401-
By default, this uses the `basic-lambda` example. To test a different example:
401+
By default, this builds and tests the `basic-lambda` example. To build and test a custom handler:
402402

403403
```bash
404-
make test-rie EXAMPLE=basic-sqs
405-
make test-rie EXAMPLE=http-basic-lambda
404+
HANDLER="basic-tenant-id" make test-rie
406405
```
407406

408-
To test Lambda Managed Instances (concurrent polling), use:
407+
To test Lambda Managed Instances (concurrent polling):
409408

410409
```bash
411-
make test-rie-lmi EXAMPLE=basic-lambda-concurrent
410+
RIE_MAX_CONCURRENCY=4 make test-rie
412411
```
413412

414-
This command will:
415-
1. Build a Docker image with Rust toolchain and RIE
416-
2. Compile the specified example inside the Linux container
417-
3. Start the RIE container on port 9000
418-
4. Display the appropriate curl command for testing
419-
420413
Different examples expect different payload formats. Check the example's source code in `examples/EXAMPLE_NAME/src/main.rs`
421414

422-
This provides automated testing with Docker and RIE, ensuring your Lambda functions work in a Linux environment identical to AWS Lambda.
415+
### Dockerized test harness
416+
417+
For automated testing with AWS's containerized test runner:
418+
419+
```bash
420+
make test-dockerized
421+
```
422+
423+
This runs test suites defined in `test/dockerized/*.json` files using the [containerized-test-runner-for-aws-lambda](https://github.com/aws/containerized-test-runner-for-aws-lambda). Test suites specify handlers to test (from examples), request payloads, and expected response assertions.
424+
425+
Example test suite (`test/dockerized/core.json`):
426+
```json
427+
{
428+
"tests": [
429+
{
430+
"name": "test_echo",
431+
"handler": "basic-lambda",
432+
"request": {
433+
"command": "test"
434+
},
435+
"assertions": [
436+
{
437+
"response": {
438+
"msg": "Command test executed."
439+
},
440+
"transform": "{msg: .msg}"
441+
}
442+
]
443+
}
444+
]
445+
}
446+
```
447+
448+
The `transform` field uses jq syntax to extract specific fields from responses before comparison, useful when responses include dynamic fields like request IDs.
423449

424450
### Lambda Debug Proxy
425451

scripts/build-examples.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
set -e
3+
4+
OUTPUT_DIR="${OUTPUT_DIR:-/tmp/var-task}"
5+
HANDLERS_TO_BUILD="${HANDLERS_TO_BUILD:-}"
6+
7+
mkdir -p "$OUTPUT_DIR"
8+
9+
echo "Building handlers: ${HANDLERS_TO_BUILD}"
10+
11+
12+
for handler in ${HANDLERS_TO_BUILD}; do
13+
dir="examples/$handler"
14+
[ ! -f "$dir/Cargo.toml" ] && echo "$handler not found" && continue
15+
16+
echo "Building $handler..."
17+
(cd "$dir" && cargo build --release) || continue
18+
19+
[ -f "$dir/target/release/$handler" ] && cp "$dir/target/release/$handler" "$OUTPUT_DIR/" && echo "$handler"
20+
done
21+
22+
echo ""
23+
ls -lh "$OUTPUT_DIR/" 2>/dev/null || echo "No binaries built"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
# custom entrypoint script to allow selection of multiple rust binaries for dockerized tests
3+
set -e
4+
5+
HANDLER=${1:-basic-lambda}
6+
7+
if [ -f "/var/task/$HANDLER" ]; then
8+
ln -sf "/var/task/$HANDLER" "${LAMBDA_RUNTIME_DIR}/bootstrap"
9+
exec /usr/local/bin/aws-lambda-rie "${LAMBDA_RUNTIME_DIR}/bootstrap"
10+
else
11+
echo "Error: Handler '$HANDLER' not found in /var/task"
12+
echo "Available handlers:"
13+
ls -la /var/task
14+
exit 1
15+
fi

scripts/test-rie.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ fi
2626
echo ""
2727
echo "Press Ctrl+C to stop the container."
2828

29-
wait $CONTAINER_PID
29+
wait $CONTAINER_PID

test/dockerized/suites/core.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"tests": [
3+
{
4+
"name": "test_echo",
5+
"handler": "basic-lambda",
6+
"request": {
7+
"command": "test"
8+
},
9+
"assertions": [
10+
{
11+
"response": {
12+
"msg": "Command test executed."
13+
},
14+
"transform": "{msg: .msg}"
15+
}
16+
]
17+
}
18+
]
19+
}

0 commit comments

Comments
 (0)