Skip to content
Open
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
13 changes: 13 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test configuration for RIE and dockerized tests
# Customize these values as needed for testing both local and on github

# Handlers to build
HANDLERS_TO_BUILD=basic-lambda

HANDLER=basic-lambda

# Output directory for built binaries
OUTPUT_DIR="/tmp/var-task"

# Max concurrent Lambda invocations for LMI mode
RIE_MAX_CONCURRENCY=4
28 changes: 28 additions & 0 deletions .github/workflows/dockerized-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: dockerized-test

permissions:
contents: read

on:
push:
branches: [ main ]
pull_request:
branches: [ '*' ]
workflow_dispatch:


jobs:
dockerized-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v6

- name: Build the image
run: docker build . -t local/test -f Dockerfile.rie

- name: Run tests
uses: aws/containerized-test-runner-for-aws-lambda@main
with:
suiteFileArray: '["./test/dockerized/*.json"]'
dockerImageName: 'local/test'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ target
lambda-runtime/libtest.rmeta
lambda-integration-tests/target
Cargo.lock
.test-runner

# Built AWS Lambda zipfile
lambda.zip
Expand Down
33 changes: 21 additions & 12 deletions Dockerfile.rie
Original file line number Diff line number Diff line change
@@ -1,25 +1,34 @@
FROM public.ecr.aws/lambda/provided:al2023
FROM public.ecr.aws/lambda/provided:al2023 AS builder

RUN dnf install -y gcc
RUN dnf install -y gcc make
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/local/bin/aws-lambda-rie
RUN chmod +x /usr/local/bin/aws-lambda-rie

ARG EXAMPLE=basic-lambda
ARG HANDLERS_TO_BUILD="basic-lambda"
ARG OUTPUT_DIR="/var/task"

COPY Cargo.* /build/
COPY lambda-runtime /build/lambda-runtime
COPY lambda-runtime-api-client /build/lambda-runtime-api-client
COPY lambda-events /build/lambda-events
COPY lambda-http /build/lambda-http
COPY lambda-extension /build/lambda-extension
COPY examples/${EXAMPLE} /build/examples/${EXAMPLE}
COPY examples /build/examples
COPY scripts/build-examples.sh /build/

WORKDIR /build
RUN chmod +x build-examples.sh && HANDLERS_TO_BUILD=${HANDLERS_TO_BUILD} OUTPUT_DIR=${OUTPUT_DIR} ./build-examples.sh

# Final Image
FROM public.ecr.aws/lambda/provided:al2023

ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/local/bin/aws-lambda-rie
RUN chmod +x /usr/local/bin/aws-lambda-rie

COPY scripts/custom-lambda-entrypoint.sh /usr/local/bin/lambda-entrypoint
RUN chmod +x /usr/local/bin/lambda-entrypoint

WORKDIR /build/examples/${EXAMPLE}
RUN cargo build --release
RUN cp target/release/${EXAMPLE} ${LAMBDA_RUNTIME_DIR}/bootstrap
COPY --from=builder /var/task /var/task

ENTRYPOINT []
CMD [ "/usr/local/bin/aws-lambda-rie", "/var/runtime/bootstrap" ]
ENTRYPOINT ["/usr/local/bin/lambda-entrypoint"]
CMD ["basic-lambda"]
28 changes: 28 additions & 0 deletions Dockerfile.test-runner
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM python:3.11-slim

# Install build dependencies for pyjq and Docker CLI
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gcc \
g++ \
make \
autoconf \
automake \
libtool \
ca-certificates \
curl \
&& curl -fsSL https://get.docker.com -o get-docker.sh \
&& sh get-docker.sh \
&& rm get-docker.sh \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the test runner source
COPY .test-runner/ .

# Install the test runner
RUN pip install --no-cache-dir .

# Set the entrypoint
ENTRYPOINT ["python", "-m", "containerized_test_runner.cli"]
74 changes: 72 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ INTEG_EXTENSIONS := extension-fn extension-trait logs-trait
# Using musl to run extensions on both AL1 and AL2
INTEG_ARCH := x86_64-unknown-linux-musl
RIE_MAX_CONCURRENCY ?= 4
OUTPUT_DIR ?= /tmp/var-task
HANDLERS_TO_BUILD ?=
HANDLER ?=

# Load environment variables from .env file if it exists
-include .env
export

.PHONY: help pr-check integration-tests check-event-features fmt build-examples test-rie test-rie-lmi nuke test-dockerized

.DEFAULT_GOAL := help

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

build-examples:
HANDLERS_TO_BUILD=${HANDLERS_TO_BUILD} ./scripts/build-examples.sh

nuke:
docker kill $$(docker ps -q)

test-dockerized:
@echo "Running dockerized tests locally..."
@echo "Building Docker image..."
docker build \
-t local/test \
-f Dockerfile.rie \
--build-arg HANDLERS_TO_BUILD="${HANDLERS_TO_BUILD}" \
--build-arg OUTPUT_DIR="${OUTPUT_DIR}" \
.

@echo "Setting up containerized test runner..."
@if [ ! -d ".test-runner" ]; then \
echo "Cloning containerized-test-runner-for-aws-lambda..."; \
git clone --quiet https://github.com/aws/containerized-test-runner-for-aws-lambda.git .test-runner; \
fi
@echo "Building test runner Docker image..."
@docker build -t test-runner:local -f Dockerfile.test-runner .
@echo "Running tests in Docker..."
@echo "Running actual tests..."
@docker run --rm \
-e DOCKER_API_VERSION=1.44 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$(CURDIR)/test/dockerized:/tests:ro" \
test-runner:local \
--test-image local/test \
--debug \
/tests/*.json

test-rie:
./scripts/test-rie.sh $(EXAMPLE)
HANDLER="$(HANDLER)" ./scripts/test-rie.sh

# Run RIE in Lambda Managed Instance (LMI) mode with concurrent polling.
test-rie-lmi:
RIE_MAX_CONCURRENCY=$(RIE_MAX_CONCURRENCY) ./scripts/test-rie.sh $(EXAMPLE)
RIE_MAX_CONCURRENCY=$(RIE_MAX_CONCURRENCY) HANDLER="$(HANDLER)" ./scripts/test-rie.sh $(EXAMPLE)

help: ## Show this help message
@echo 'Usage: make [target]'
@echo ''
@echo 'Available targets:'
@echo ' pr-check Run pre-commit checks (fmt, clippy, tests)'
@echo ' integration-tests Build and run AWS integration tests'
@echo ' check-event-features Test individual event features'
@echo ' fmt Format code with cargo fmt'
@echo ' build-examples Build example Lambda functions'
@echo ' Usage: EXAMPLES="basic-lambda" OUTPUT_DIR=/make build-examples'
@echo ' test-rie Test Lambda with Runtime Interface Emulator'
@echo ' Usage: HANDLERS_TO_BUILD="basic-lambda basic-sqs" make test-rie'
@echo ' Usage: HANDLERS_TO_BUILD="basic-lambda" HANDLER="basic-lambda" make test-rie'
@echo ' test-rie-lmi Test RIE in Lambda Managed Instance mode'
@echo ' Usage: RIE_MAX_CONCURRENCY=4 HANDLERS_TO_BUILD="basic-lambda-concurrent" make test-rie-lmi'
@echo ' test-dockerized Run dockerized test harness'
@echo ' nuke Kill all running Docker containers'
@echo ''
@echo 'Environment variables:'
@echo ' EXAMPLES Space-separated list of examples to build (for build-examples)'
@echo ' HANDLERS_TO_BUILD Space-separated list of handlers to build for RIE (for test-rie)'
@echo ' HANDLER Specific handler to run (defaults to first in HANDLERS_TO_BUILD)'
@echo ' OUTPUT_DIR Directory for built binaries (default: /tmp/var-task for build-examples, /var/task for Docker)'
@echo ' RIE_MAX_CONCURRENCY Max concurrent Lambda invocations for LMI mode (for test-rie-lmi)'
39 changes: 39 additions & 0 deletions PR_DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
📬 *Issue #, if available:*

N/A

✍️ *Description of changes:*

This PR adds Docker-based testing infrastructure using AWS's [containerized-test-runner-for-aws-lambda](https://github.com/aws/containerized-test-runner-for-aws-lambda), enabling automated testing of Lambda functions in a containerized environment that closely mirrors the AWS Lambda execution environment.

The PR introduces a `test-dockerized` Makefile target that runs test suites defined in `test/dockerized/*.json` files. These test suites specify handlers to test (from the examples directory), request payloads, and expected response assertions with optional jq transforms for validation.

The infrastructure reuses Lambda binaries from the `/examples` folder as test handlers, demonstrating the concept with an initial test case for `basic-lambda`. Additional tests and multi-concurrency scenarios can be added by creating new test suite JSON files.

A GitHub Actions workflow provides CI/CD integration for automated testing on pull requests.

## Testing

Run dockerized tests locally:
```bash
make test-dockerized
```

Run RIE tests:
```bash
make test-rie
HANDLERS_TO_BUILD="basic-lambda basic-sqs" make test-rie
```

Build specific examples:
```bash
EXAMPLES="basic-lambda basic-lambda-concurrent" make build-examples
```

🔏 *By submitting this pull request*

- [x] I confirm that I've ran `cargo +nightly fmt`.
- [x] I confirm that I've ran `cargo clippy --fix`.
- [x] I confirm that I've made a best effort attempt to update all relevant documentation.
- [x] I confirm that my contribution is made under the terms of the Apache 2.0 license.on.
- [x] I confirm that my contribution is made under the terms of the Apache 2.0 license.
52 changes: 39 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,34 +392,60 @@ You can read more about how [cargo lambda watch](https://www.cargo-lambda.info/c

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

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

```bash
make test-rie
```

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

```bash
make test-rie EXAMPLE=basic-sqs
make test-rie EXAMPLE=http-basic-lambda
HANDLER="basic-tenant-id" make test-rie
```

To test Lambda Managed Instances (concurrent polling), use:
To test Lambda Managed Instances (concurrent polling):

```bash
make test-rie-lmi EXAMPLE=basic-lambda-concurrent
RIE_MAX_CONCURRENCY=4 make test-rie
```

This command will:
1. Build a Docker image with Rust toolchain and RIE
2. Compile the specified example inside the Linux container
3. Start the RIE container on port 9000
4. Display the appropriate curl command for testing

Different examples expect different payload formats. Check the example's source code in `examples/EXAMPLE_NAME/src/main.rs`

This provides automated testing with Docker and RIE, ensuring your Lambda functions work in a Linux environment identical to AWS Lambda.
### Dockerized test harness

For automated testing with AWS's containerized test runner:

```bash
make test-dockerized
```

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.

Example test suite (`test/dockerized/core.json`):
```json
{
"tests": [
{
"name": "test_echo",
"handler": "basic-lambda",
"request": {
"command": "test"
},
"assertions": [
{
"response": {
"msg": "Command test executed."
},
"transform": "{msg: .msg}"
}
]
}
]
}
```

The `transform` field uses jq syntax to extract specific fields from responses before comparison, useful when responses include dynamic fields like request IDs.

### Lambda Debug Proxy

Expand Down
23 changes: 23 additions & 0 deletions scripts/build-examples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash
set -e

OUTPUT_DIR="${OUTPUT_DIR:-/tmp/var-task}"
HANDLERS_TO_BUILD="${HANDLERS_TO_BUILD:-}"

mkdir -p "$OUTPUT_DIR"

echo "Building handlers: ${HANDLERS_TO_BUILD}"


for handler in ${HANDLERS_TO_BUILD}; do
dir="examples/$handler"
[ ! -f "$dir/Cargo.toml" ] && echo "✗ $handler not found" && continue

echo "Building $handler..."
(cd "$dir" && cargo build --release) || continue

[ -f "$dir/target/release/$handler" ] && cp "$dir/target/release/$handler" "$OUTPUT_DIR/" && echo "✓ $handler"
done

echo ""
ls -lh "$OUTPUT_DIR/" 2>/dev/null || echo "No binaries built"
15 changes: 15 additions & 0 deletions scripts/custom-lambda-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh
# custom entrypoint script to allow selection of multiple rust binaries for dockerized tests
set -e

HANDLER=${1:-basic-lambda}

if [ -f "/var/task/$HANDLER" ]; then
ln -sf "/var/task/$HANDLER" "${LAMBDA_RUNTIME_DIR}/bootstrap"
exec /usr/local/bin/aws-lambda-rie "${LAMBDA_RUNTIME_DIR}/bootstrap"
else
echo "Error: Handler '$HANDLER' not found in /var/task"
echo "Available handlers:"
ls -la /var/task
exit 1
fi
Loading
Loading