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
34 changes: 34 additions & 0 deletions .github/actions/cache-jni-base-images/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Cache the JNI build base images
description: >
Load the JNI build base images into the local Docker image store from the
Actions cache, pulling them from public.ecr.aws only on a cache miss. The JNI
build then reuses them, provided buildx uses the docker driver.

runs:
using: composite
steps:
# Weekly key, so the images are refreshed once a week.
- id: key
shell: bash
run: echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT"

- id: cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ runner.temp }}/jni-base-images.tar
key: jni-base-images-${{ runner.os }}-${{ runner.arch }}-${{ steps.key.outputs.week }}

# Pulls on a cache miss, or when the cached tar can't be loaded.
- shell: bash
env:
CACHE_HIT: ${{ steps.cache.outputs.cache-hit }}
TAR: ${{ runner.temp }}/jni-base-images.tar
run: |
if [[ "$CACHE_HIT" == "true" ]] && docker load -i "$TAR"; then
exit 0
fi
images="public.ecr.aws/amazonlinux/amazonlinux:2 public.ecr.aws/docker/library/alpine:3"
for image in $images; do
aws-lambda-java-runtime-interface-client/test/integration/codebuild/scripts/docker-retry.sh docker pull "$image"
done
docker save -o "$TAR" $images
27 changes: 27 additions & 0 deletions .github/actions/use-runner-corretto8/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Use the runner image's preinstalled Corretto 8
description: >
Point JAVA_HOME at the CodeBuild image's Corretto 8 and declare it as the JDK 8
maven toolchain. For CodeBuild-hosted runners in the egress-locked network,
where actions/setup-java cannot download a JDK.

runs:
using: composite
steps:
# The image ships Corretto 8 at $JAVA_8_HOME (per arch) but defaults
# JAVA_HOME to a newer JDK.
- shell: bash
run: |
echo "JAVA_HOME=$JAVA_8_HOME" >> "$GITHUB_ENV"
echo "$JAVA_8_HOME/bin" >> "$GITHUB_PATH"
"$JAVA_8_HOME/bin/java" -version
mkdir -p "$HOME/.m2"
cat > "$HOME/.m2/toolchains.xml" <<TOOLCHAINS
<?xml version="1.0" encoding="UTF-8"?>
<toolchains>
<toolchain>
<type>jdk</type>
<provides><version>8</version></provides>
<configuration><jdkHome>$JAVA_8_HOME</jdkHome></configuration>
</toolchain>
</toolchains>
TOOLCHAINS
5 changes: 5 additions & 0 deletions .github/workflows/dockerized-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- 'aws-lambda-java-serialization/**'
- 'aws-lambda-java-runtime-interface-client/**'
- '.github/workflows/dockerized-test.yml'
- '.github/actions/cache-jni-base-images/**'
workflow_dispatch:

jobs:
Expand All @@ -32,6 +33,10 @@ jobs:
distribution: corretto
cache: maven

# The default buildx driver (docker) uses the local image store.
- name: Load the JNI build base images
uses: ./.github/actions/cache-jni-base-images

- name: Build core, serialization and the RIC under test
run: |
mvn -B -q install -DskipTests --file aws-lambda-java-core/pom.xml
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/runtime-interface-client_merge_to_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ jobs:
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
with:
install: true
# Uses the local image store, so the JNI build reuses the cached base images.
driver: docker

- name: Load the JNI build base images
uses: ./.github/actions/cache-jni-base-images

- name: Build and install core dependency locally
working-directory: ./aws-lambda-java-core
Expand Down
139 changes: 58 additions & 81 deletions .github/workflows/runtime-interface-client_pr.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This workflow builds and tests the aws-lambda-java-runtime-interface-client package.
# It runs on every pull request (no path filter) so that the smoke-test and
# It runs on every pull request (no path filter) so that the build and
# integration-test required status checks always report a result and never get
# stuck "pending" on PRs that don't touch the RIC/core/serialization paths.

Expand All @@ -15,41 +15,6 @@ permissions:

jobs:

smoke-test-arch:
strategy:
fail-fast: true
matrix:
include:
- arch: x86_64
runner: ubuntu-latest
- arch: aarch64
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
name: "smoke-test (${{ matrix.arch }})"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up JDK 1.8
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
java-version: 8
distribution: corretto
cache: maven

- name: Build and install core dependency locally
working-directory: ./aws-lambda-java-core
run: mvn clean install

- name: Build and install serialization dependency locally
working-directory: ./aws-lambda-java-serialization
run: mvn clean install

- name: Runtime Interface Client smoke tests - Run 'pr-${{ matrix.arch }}' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make pr-${{ matrix.arch }}
env:
IS_JAVA_8: true

build-arch:
strategy:
fail-fast: true
Expand All @@ -75,6 +40,11 @@ jobs:
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
with:
install: true
# Uses the local image store, so the JNI build reuses the cached base images.
driver: docker

- name: Load the JNI build base images
uses: ./.github/actions/cache-jni-base-images

- name: Build and install core dependency locally
working-directory: ./aws-lambda-java-core
Expand Down Expand Up @@ -106,51 +76,70 @@ jobs:
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

# Runs on the release CodeBuild runners, so base images come from the ECR
# pull-through cache instead of rate-limited anonymous public.ecr.aws pulls.
integration-test-matrix:
runs-on: ${{ matrix.arch.runner }}
runs-on: codebuild-aws-lambda-java-libs-test-trigger-${{ matrix.arch.runner }}-${{ github.run_id }}-${{ github.run_attempt }}
strategy:
# Run every OS/arch combination to completion so one failure doesn't mask the others.
fail-fast: false
# Every shard pulls its images anonymously from public.ecr.aws, and shards
# started together trip its rate limit (429), so cap how many run at once.
max-parallel: 4
# Stays within the account's concurrent CodeBuild build quota.
max-parallel: 8
matrix:
buildspec:
- buildspec.os.alpine.yml
- buildspec.os.amazoncorretto.yml
- buildspec.os.amazonlinux.1.yml
- buildspec.os.amazonlinux.2.yml
- buildspec.os.debian.yml
- buildspec.os.ubuntu.yml
target:
- { os: alpine, distro: "3.15", runtime: corretto11 }
- { os: amazoncorretto, distro: amazoncorretto, runtime: "8" }
- { os: amazoncorretto, distro: amazoncorretto, runtime: "11" }
- { os: amazonlinux, distro: "1", runtime: openjdk8 }
- { os: amazonlinux, distro: "2", runtime: openjdk8 }
- { os: debian, distro: bookworm, runtime: corretto11 }
- { os: debian, distro: trixie, runtime: corretto11 }
- { os: ubuntu, distro: "22.04", runtime: corretto11 }
- { os: ubuntu, distro: "24.04", runtime: corretto11 }
arch:
- label: x64
runner: ubuntu-latest
platform: linux/amd64
- label: arm64
runner: ubuntu-24.04-arm
platform: linux/arm64/v8
- { label: x64, runner: x86, platform: linux/amd64 }
- { label: arm64, runner: arm64, platform: linux/arm64/v8 }
exclude:
# Amazon Linux 1 was never published for ARM64 (x86_64 only), so
# public.ecr.aws/amazonlinux/amazonlinux:1 has no arm64 manifest.
- buildspec: buildspec.os.amazonlinux.1.yml
arch:
label: arm64
runner: ubuntu-24.04-arm
platform: linux/arm64/v8
name: "integration-test (${{ matrix.buildspec }} / ${{ matrix.arch.label }})"
# Amazon Linux 1 has no arm64 image.
- target: { os: amazonlinux, distro: "1", runtime: openjdk8 }
arch: { label: arm64, runner: arm64, platform: linux/arm64/v8 }
name: "integration-test (${{ matrix.target.os }} ${{ matrix.target.distro }} ${{ matrix.target.runtime }} / ${{ matrix.arch.label }})"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Cache Maven repository
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
install: true

- name: Run OS integration test - 'test-integ' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make test-integ BUILDSPEC=test/integration/codebuild/${{ matrix.buildspec }}
path: ~/.m2/repository
key: ${{ runner.os }}-${{ runner.arch }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-maven-

# The runners can't reach Maven Central or the setup-java JDK downloads.
- name: Use the runner image's preinstalled Corretto 8
uses: ./.github/actions/use-runner-corretto8

- name: Configure Maven CodeArtifact mirror
uses: ./.github/actions/configure-maven-mirror

# Uses the runner's ambient credentials and region, not repository secrets,
# which fork PRs don't get. BASE_REGISTRY is read by run_os_test.sh.
- name: Log in to Amazon ECR (pull-through cache)
run: |
region="${AWS_REGION:-$AWS_DEFAULT_REGION}"
account="$(aws sts get-caller-identity --query Account --output text)"
registry="${account}.dkr.ecr.${region}.amazonaws.com"
aws ecr get-login-password --region "$region" \
| docker login --username AWS --password-stdin "$registry"
echo "BASE_REGISTRY=${registry}/ecr-public" >> "$GITHUB_ENV"

- name: Run OS integration test
run: aws-lambda-java-runtime-interface-client/test/integration/codebuild/scripts/run_os_test.sh
env:
PLATFORM_FILTER: ${{ matrix.arch.platform }}
OS_DISTRIBUTION: ${{ matrix.target.os }}
DISTRO_VERSION: ${{ matrix.target.distro }}
RUNTIME_VERSION: ${{ matrix.target.runtime }}
PLATFORM: ${{ matrix.arch.platform }}

integration-test:
needs: integration-test-matrix
Expand All @@ -164,18 +153,6 @@ jobs:
exit 1
fi

smoke-test:
needs: smoke-test-arch
if: always()
runs-on: ubuntu-latest
steps:
- name: Check smoke-test results
run: |
if [ "${{ needs.smoke-test-arch.result }}" != "success" ]; then
echo "Smoke tests failed on one or more architectures"
exit 1
fi

build:
needs: build-arch
if: always()
Expand Down
56 changes: 8 additions & 48 deletions aws-lambda-java-runtime-interface-client/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
x86_64_ALIAS := amd64
aarch64_ALIAS := arm64
ARCHITECTURE := $(shell arch)
ARCHITECTURE_ALIAS := $($(shell echo "$(ARCHITECTURE)_ALIAS"))
ARCHITECTURE_ALIAS := $(or $(ARCHITECTURE_ALIAS),amd64) # on any other archs defaulting to amd64

# Java 8 does not support passing some args (such add --add-opens) so we need to clear them
ifeq ($(IS_JAVA_8),true)
EXTRA_LOAD_ARG := -DargLineForReflectionTestOnly=""
Expand All @@ -20,56 +14,22 @@ target:
test:
mvn test $(EXTRA_LOAD_ARG)

.PHONY: setup-codebuild-agent
setup-codebuild-agent:
test/integration/codebuild-local/docker-retry.sh docker build --load -t codebuild-agent \
--build-arg ARCHITECTURE=$(ARCHITECTURE_ALIAS) \
-f test/integration/codebuild-local/Dockerfile.agent \
test/integration/codebuild-local

# Smoke tests are split per-architecture so CI can run each set on a native
# runner. Running the linux/arm64/v8 combos under QEMU on an x86_64 host makes
# `mvn install` recompile curl for aarch64 emulated, which takes ~30 minutes.
.PHONY: test-smoke
test-smoke: test-smoke-x86_64 test-smoke-aarch64

# amazoncorretto 11 is left out of the CI integration matrix
# (buildspec.os.amazoncorretto.yml) because smoke already covers it. Changing it
# here changes integration coverage too.
.PHONY: test-smoke-x86_64
test-smoke-x86_64: setup-codebuild-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.alpine.yml alpine 3.15 corretto11 linux/amd64
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.amazoncorretto.yml amazoncorretto amazoncorretto 11 linux/amd64

.PHONY: test-smoke-aarch64
test-smoke-aarch64: setup-codebuild-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.alpine.yml alpine 3.15 corretto11 linux/arm64/v8
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_one.sh test/integration/codebuild/buildspec.os.amazoncorretto.yml amazoncorretto amazoncorretto 11 linux/arm64/v8

# BUILDSPEC can point to the buildspec directory (default, runs every OS) or to a
# single buildspec file, which is how CI parallelizes the run across OSes.
BUILDSPEC ?= test/integration/codebuild

# One OS integration test (see test/integration/codebuild/scripts/run_os_test.sh;
# the combinations CI runs are in .github/workflows/runtime-interface-client_pr.yml), e.g.
# make test-integ OS_DISTRIBUTION=debian DISTRO_VERSION=bookworm RUNTIME_VERSION=corretto11 PLATFORM=linux/amd64
# A PLATFORM other than the host's needs emulation: built into Docker Desktop; on
# Linux, run once: docker run --rm --privileged public.ecr.aws/eks-distro-build-tooling/binfmt-misc:qemu-v6.1.0 --install all
.PHONY: test-integ
test-integ: setup-codebuild-agent
CODEBUILD_IMAGE_TAG=codebuild-agent test/integration/codebuild-local/test_all.sh $(BUILDSPEC)
test-integ:
OS_DISTRIBUTION=$(OS_DISTRIBUTION) DISTRO_VERSION=$(DISTRO_VERSION) RUNTIME_VERSION=$(RUNTIME_VERSION) PLATFORM=$(PLATFORM) test/integration/codebuild/scripts/run_os_test.sh

# Command to run everytime you make changes to verify everything works
.PHONY: dev
dev: test

# Verifications to run before sending a pull request
.PHONY: pr
pr: test test-smoke

# Per-architecture PR checks so CI can run each on a native runner (no QEMU).
# No `test` here: the required `build` check already runs the unit tests
# (build-<arch>), so CI would only run them twice.
.PHONY: pr-x86_64
pr-x86_64: test-smoke-x86_64

.PHONY: pr-aarch64
pr-aarch64: test-smoke-aarch64
pr: test

.PHONY: build
build: build-x86_64 build-aarch64
Expand Down
28 changes: 28 additions & 0 deletions aws-lambda-java-runtime-interface-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,34 @@ This single command will:

The test uses a simple EchoHandler that returns the input event, making it easy to verify the runtime interface client is working correctly.

### OS Integration Tests

CI runs the runtime interface client on a matrix of base images (Alpine, Amazon Corretto, Amazon Linux, Debian, Ubuntu), JDKs and platforms; the combinations are in `.github/workflows/runtime-interface-client_pr.yml`. Each test builds the RIC, builds a function image with RIE for one combination, invokes it and checks the response.

*Prerequisites:*
- Docker, Maven and a JDK 8 as `JAVA_HOME`
- The same JDK declared as the JDK 8 Maven toolchain in `~/.m2/toolchains.xml`:

```xml
<toolchains>
<toolchain>
<type>jdk</type>
<provides><version>8</version></provides>
<configuration><jdkHome>/path/to/jdk8</jdkHome></configuration>
</toolchain>
</toolchains>
```

*To run one combination:*

```shell script
make test-integ OS_DISTRIBUTION=debian DISTRO_VERSION=bookworm RUNTIME_VERSION=corretto11 PLATFORM=linux/amd64
```

`PLATFORM` is `linux/amd64` or `linux/arm64/v8`. A platform other than your machine's runs under emulation, which is much slower:
- macOS and Windows: Docker Desktop emulates it out of the box. On Windows, run the commands inside WSL2.
- Linux: register the emulator once with `docker run --rm --privileged public.ecr.aws/eks-distro-build-tooling/binfmt-misc:qemu-v6.1.0 --install all`.

## Test Coverage

This project uses JaCoCo for code coverage analysis. To exclude classes from JaCoCo coverage, add them to the `jacoco-maven-plugin` configuration:
Expand Down
Loading
Loading