diff --git a/.github/workflows/test-rie.yml b/.github/workflows/test-rie.yml new file mode 100644 index 00000000..5d777e2d --- /dev/null +++ b/.github/workflows/test-rie.yml @@ -0,0 +1,50 @@ +name: Test with RIE + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + test-rie: + runs-on: ubuntu-latest + strategy: + matrix: + example: [basic-lambda, basic-sqs] + + steps: + - uses: actions/checkout@v4 + + - name: Build and test ${{ matrix.example }} with RIE + run: | + docker build -f Dockerfile.rie --build-arg EXAMPLE=${{ matrix.example }} -t rust-lambda-rie-test-${{ matrix.example }} . + + # Start container in background + docker run -d -p 9000:8080 --name rie-test-${{ matrix.example }} rust-lambda-rie-test-${{ matrix.example }} + + # Wait for container to be ready + sleep 5 + + # Test the function based on example type + if [ "${{ matrix.example }}" = "basic-lambda" ]; then + PAYLOAD='{"command": "test from CI"}' + elif [ "${{ matrix.example }}" = "basic-sqs" ]; then + PAYLOAD='{"Records": [{"body": "{\"id\": \"123\", \"text\": \"hello from SQS\"}", "messageId": "test-id", "receiptHandle": "test-handle", "attributes": {}, "messageAttributes": {}, "md5OfBody": "test-md5", "eventSource": "aws:sqs", "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:test-queue", "awsRegion": "us-east-1"}]}' + fi + + # Make request and verify response + RESPONSE=$(curl -s -XPOST 'http://localhost:9000/2015-03-31/functions/function/invocations' \ + -d "$PAYLOAD" \ + -H 'Content-Type: application/json') + + echo "Response: $RESPONSE" + + # Basic validation that we got a response (not empty) + if [ -z "$RESPONSE" ]; then + echo "Error: Empty response" + exit 1 + fi + + # Stop container + docker stop rie-test-${{ matrix.example }} \ No newline at end of file diff --git a/Dockerfile.rie b/Dockerfile.rie new file mode 100644 index 00000000..1a46b577 --- /dev/null +++ b/Dockerfile.rie @@ -0,0 +1,25 @@ +FROM public.ecr.aws/lambda/provided:al2023 + +RUN dnf install -y gcc +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 + +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} + +WORKDIR /build/examples/${EXAMPLE} +RUN cargo build --release +RUN cp target/release/${EXAMPLE} ${LAMBDA_RUNTIME_DIR}/bootstrap + +ENTRYPOINT [] +CMD [ "/usr/local/bin/aws-lambda-rie", "/var/runtime/bootstrap" ] \ No newline at end of file diff --git a/Makefile b/Makefile index ecfd7623..155b7ea1 100644 --- a/Makefile +++ b/Makefile @@ -108,4 +108,7 @@ check-event-features: cargo test --package aws_lambda_events --no-default-features --features streams fmt: - cargo +nightly fmt --all \ No newline at end of file + cargo +nightly fmt --all + +test-rie: + ./scripts/test-rie.sh $(EXAMPLE) \ No newline at end of file diff --git a/README.md b/README.md index 5426c0c9..fdec26a5 100644 --- a/README.md +++ b/README.md @@ -392,6 +392,31 @@ curl -v -X POST \ You can read more about how [cargo lambda watch](https://www.cargo-lambda.info/commands/watch.html) and [cargo lambda invoke](https://www.cargo-lambda.info/commands/invoke.html) work on the project's [documentation page](https://www.cargo-lambda.info). +### Local testing with Runtime Interface Emulator (RIE) + +For testing with the official AWS Lambda Runtime Interface Emulator, use the provided RIE testing infrastructure: + +```bash +make test-rie +``` + +By default, this uses the `basic-lambda` example. To test a different example: + +```bash +make test-rie EXAMPLE=basic-sqs +make test-rie EXAMPLE=http-basic-lambda +``` + +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. + ### Lambda Debug Proxy Lambdas can be run and debugged locally using a special [Lambda debug proxy](https://github.com/rimutaka/lambda-debug-proxy) (a non-AWS repo maintained by @rimutaka), which is a Lambda function that forwards incoming requests to one AWS SQS queue and reads responses from another queue. A local proxy running on your development computer reads the queue, calls your Lambda locally and sends back the response. This approach allows debugging of Lambda functions locally while being part of your AWS workflow. The Lambda handler code does not need to be modified between the local and AWS versions. diff --git a/scripts/test-rie.sh b/scripts/test-rie.sh new file mode 100755 index 00000000..911cb390 --- /dev/null +++ b/scripts/test-rie.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -euo pipefail + +EXAMPLE=${1:-basic-lambda} + +echo "Building Docker image with RIE for example: $EXAMPLE..." +docker build -f Dockerfile.rie --build-arg EXAMPLE=$EXAMPLE -t rust-lambda-rie-test . + +echo "Starting RIE container on port 9000..." +docker run -p 9000:8080 rust-lambda-rie-test & +CONTAINER_PID=$! + +echo "Container started. Test with:" +if [ "$EXAMPLE" = "basic-lambda" ]; then + echo "curl -XPOST 'http://localhost:9000/2015-03-31/functions/function/invocations' -d '{\"command\": \"test from RIE\"}' -H 'Content-Type: application/json'" +else + echo "For example '$EXAMPLE', check examples/$EXAMPLE/src/main.rs for the expected payload format." +fi +echo "" +echo "Press Ctrl+C to stop the container." + +wait $CONTAINER_PID \ No newline at end of file