Skip to content

refactor(cloudformation): move the single-service types to provisioners #4608

refactor(cloudformation): move the single-service types to provisioners

refactor(cloudformation): move the single-service types to provisioners #4608

Workflow file for this run

name: Compatibility Tests
on:
pull_request:
paths:
- 'src/**'
- 'pom.xml'
- 'docker/Dockerfile.native-package'
- 'docker/Dockerfile.compat'
- 'docker/entrypoint.sh'
- 'docker/localstack-parity.sh'
- 'compatibility-tests/**'
- '.github/ci/compat-timing-report.py'
- '.github/workflows/compatibility.yml'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
compat-aws-cli-shim:
name: compat / aws CLI endpoint resolution
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build compat image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
file: docker/Dockerfile.compat
build-args: VERSION=latest
load: true
tags: floci-compat-shim-test
# Read-only; warm-compat-caches.yml produces this scope on main. Unlike
# floci-native above, these layers are worth caching: the image builds
# FROM a published floci/floci tag and its cost is a microdnf install
# that changes only when the Dockerfile does. Writing from here would
# put a per-PR copy no other PR can read back into the budget.
cache-from: type=gha,scope=compat-shim
- name: Unflagged aws sqs call routes to AWS_ENDPOINT_URL
run: |
out=$(docker run --rm --entrypoint sh floci-compat-shim-test -c \
"aws sqs create-queue --queue-name smoke-test 2>&1" || true)
echo "$out"
echo "$out" | grep -q "localhost:4566" \
|| { echo "::error::unflagged aws call did not target localhost:4566"; exit 1; }
echo "$out" | grep -qi "queue.amazonaws.com\|InvalidClientTokenId" \
&& { echo "::error::unflagged aws call reached real AWS endpoint"; exit 1; }
exit 0
- name: AWS_ENDPOINT_URL_SQS alone routes correctly
run: |
out=$(docker run --rm --entrypoint sh -e AWS_ENDPOINT_URL= \
-e AWS_ENDPOINT_URL_SQS=http://localhost:4566 \
floci-compat-shim-test -c \
"aws sqs create-queue --queue-name smoke-test-service-override 2>&1" || true)
echo "$out"
echo "$out" | grep -q "localhost:4566" \
|| { echo "::error::AWS_ENDPOINT_URL_SQS was not honored"; exit 1; }
echo "$out" | grep -qi "queue.amazonaws.com\|InvalidClientTokenId" \
&& { echo "::error::AWS_ENDPOINT_URL_SQS call reached real AWS endpoint"; exit 1; }
exit 0
- name: Explicit --endpoint-url before the subcommand overrides AWS_ENDPOINT_URL
run: |
out=$(docker run --rm --entrypoint sh floci-compat-shim-test -c \
"AWS_ENDPOINT_URL=http://example.com aws --endpoint-url http://other.example.com sqs list-queues 2>&1" || true)
echo "$out"
echo "$out" | grep -q "other.example.com" \
|| { echo "::error::pre-subcommand --endpoint-url flag was not honored over AWS_ENDPOINT_URL"; exit 1; }
- name: Explicit --endpoint-url after the subcommand overrides AWS_ENDPOINT_URL
run: |
out=$(docker run --rm --entrypoint sh floci-compat-shim-test -c \
"AWS_ENDPOINT_URL=http://example.com aws sqs list-queues --endpoint-url http://other.example.com 2>&1" || true)
echo "$out"
echo "$out" | grep -q "other.example.com" \
|| { echo "::error::post-subcommand --endpoint-url flag was not honored over AWS_ENDPOINT_URL"; exit 1; }
build-native:
name: Build native floci image
runs-on: ubuntu-24.04-arm
timeout-minutes: 30
steps:
- uses: actions/checkout@v7.0.1
- uses: graalvm/setup-graalvm@0def53c0fd8534bc13416c9469f5be45265824fd # v1
with:
java-version: '25'
distribution: 'mandrel'
# no `cache: maven` — it keys on setup-graalvm-Linux-maven-<hash>, which
# only this pull_request-only workflow ever writes. Actions caches are
# ref-scoped, so those writes land in refs/pull/N/merge and no run can
# read another's: it logged "maven cache is not found" on 6 of 6 sampled
# runs while dutifully saving 211 MB each time. Restore ci.yml's cache
# below instead, which push-to-main genuinely populates.
github-token: ${{ secrets.GITHUB_TOKEN }}
# Restore-only, and deliberately keyed identically to ci.yml:54-59 so this
# reads the ~/.m2 that ci.yml's shard 1 saves on every push to main. ci.yml
# stays the single owner of the save; a second writer would just race it.
# Two known partial-hit caveats, both cheap: `runner.os` is Linux for both
# but ci.yml runs x64 while this runs arm64 (Maven artifacts are
# arch-neutral, so only classifier-based natives re-download), and
# `-Dnative` pulls native-image plugins that ci.yml's `mvn test` never
# fetches. Expect most of the ~66s of cold resolution back, not all of it.
- uses: actions/cache/restore@v6.1.0
with:
path: ~/.m2/repository
key: maven-${{ runner.os }}-${{ hashFiles('pom.xml') }}
restore-keys: maven-${{ runner.os }}-
- name: Build native executable (quick build)
run: mvn clean package -Dnative -DskipTests -B -Dquarkus.native.additional-build-args-append="-Ob"
- name: Stage native binary for packaging
run: |
mkdir -p native/arm64
cp target/*-runner native/arm64/application
# include any sidecar .so the runtime image may need (matches nightly artifact set)
cp target/*.so native/arm64/ 2>/dev/null || true
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build native Docker image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
file: docker/Dockerfile.native-package
tags: floci:test-native
outputs: type=docker,dest=/tmp/floci-native-image.tar
# No layer cache here, deliberately. The `COPY native/$TARGETARCH/`
# below brings in a binary that changes every commit, and Docker layer
# reuse is sequential, so nothing after it can ever be reused. Measured:
# the build imported a cache manifest but reported **zero CACHED
# layers** — it was write-only. `mode=max` still stored the whole image
# including that volatile multi-hundred-MB binary layer, per PR ref,
# which was the largest single consumer of the repo's 10 GB budget.
# The step costs ~19-28s either way.
- name: Compress native image
run: gzip /tmp/floci-native-image.tar
- name: Upload native floci image
uses: actions/upload-artifact@v7
with:
name: floci-native-image
path: /tmp/floci-native-image.tar.gz
retention-days: 1
native-compat-test:
name: native / ${{ matrix.test }}
needs: build-native
runs-on: ubuntu-24.04-arm
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
test:
- sdk-test-node
- sdk-test-python
- sdk-test-java
- sdk-test-go
- sdk-test-awscli
- compat-cdk
- compat-terraform
- compat-opentofu
steps:
- name: Download native floci image
uses: actions/download-artifact@v8
with:
name: floci-native-image
path: /tmp
- name: Load native floci image
run: gunzip -c /tmp/floci-native-image.tar.gz | docker load
- name: Create Docker network
run: docker network create compat-net
- name: Start floci
run: |
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock)
docker run -d --name floci --network compat-net \
-p 4566:4566 \
-v /var/run/docker.sock:/var/run/docker.sock \
--group-add "$DOCKER_GID" \
-e FLOCI_BASE_URL=http://floci:4566 \
-e FLOCI_SERVICES_DOCKER_NETWORK=compat-net \
-e FLOCI_HOSTNAME=floci \
-e FLOCI_SERVICES_IOT_MQTT_ENABLED=true \
-e FLOCI_SERVICES_LAMBDA_HOT_RELOAD_ENABLED=true \
-e FLOCI_TLS_ENABLED=true \
-e FLOCI_SERVICES_EC2_MOCK=true \
floci:test-native
- name: Wait for floci to be ready
run: timeout 60 bash -c 'until curl -sf http://localhost:4566/ >/dev/null 2>&1; do sleep 1; done'
- name: Checkout repository
uses: actions/checkout@v7.0.1
with:
sparse-checkout: |
compatibility-tests
.github/ci
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build test image
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: compatibility-tests/${{ matrix.test }}
load: true
tags: compat-${{ matrix.test }}
# Read-only on purpose. Actions caches are ref-scoped: a pull_request
# run's writes land in refs/pull/N/merge, private to that PR and
# unreadable by any other. Eight images x every open PR overran the
# repo's 10 GB cache budget (13.2 GB measured, 95% of it in four PR
# refs), so entries were evicted between a PR's own runs and this
# build swung 29s-211s at random. `warm-compat-caches.yml` populates
# these scopes on main instead; PRs read that single shared copy.
cache-from: type=gha,scope=${{ matrix.test }}
- name: Run tests
id: tests
run: |
mkdir -p test-results
FLOCI_IP=$(docker inspect -f '{{(index .NetworkSettings.Networks "compat-net").IPAddress}}' floci)
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock)
EXTRA_ARGS=""
# compat-cdk needs Docker access for CDK's DockerImageFunction (docker build + push to emulated ECR)
if [ "${{ matrix.test }}" = "compat-cdk" ]; then
EXTRA_ARGS="-v /var/run/docker.sock:/var/run/docker.sock --group-add $DOCKER_GID"
fi
# sdk-test-java: mount a host-side directory so the Docker daemon can
# bind-mount hot-reload code paths that are written by the test container.
if [ "${{ matrix.test }}" = "sdk-test-java" ]; then
mkdir -p /tmp/floci-hot-reload
EXTRA_ARGS="$EXTRA_ARGS -v /tmp/floci-hot-reload:/tmp/floci-hot-reload -e HOT_RELOAD_BASE_DIR=/tmp/floci-hot-reload"
fi
# --dns injects Floci's embedded DNS so *.floci wildcard subdomains
# (e.g. my-bucket.floci) resolve to Floci's IP inside the test container.
# FLOCI_S3_VHOST_ENDPOINT tells the S3 virtual-host client to use
# http://floci:4566 as the endpoint base instead of the public DNS fallback.
docker run --rm --network compat-net \
--dns "${FLOCI_IP}" \
-e FLOCI_ENDPOINT=http://floci:4566 \
-e FLOCI_S3_VHOST_ENDPOINT=http://floci:4566 \
-v "$(pwd)/test-results:/results" \
$EXTRA_ARGS \
compat-${{ matrix.test }}
- name: Generate test summary
if: always() && steps.tests.outcome != 'skipped'
uses: test-summary/action@37b508cfee6d4d080eedd00b5bb240a6a784a6a5 # v2
with:
paths: test-results/*.xml
# The test body inside the container runs its build tool quietly, so the
# job log carries no per-class timings and the slow legs (sdk-test-java,
# ~10 min) are a black box. Surface the timings from the junit XMLs the
# suites already export, and upload the raw XMLs so the numbers are
# machine-readable across runs.
- name: Report slowest test classes
if: always() && steps.tests.outcome != 'skipped'
# Measurement-only: a reporting bug must never fail an otherwise-green leg.
continue-on-error: true
run: python3 .github/ci/compat-timing-report.py test-results
- name: Upload test results
if: always() && steps.tests.outcome != 'skipped'
uses: actions/upload-artifact@v7
with:
name: compat-results-${{ matrix.test }}
path: test-results/
if-no-files-found: warn
- name: Dump floci logs
if: failure()
run: docker logs floci