Skip to content
80 changes: 70 additions & 10 deletions .github/workflows/test-on-push-and-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
pull_request:
branches: [ '*' ]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -17,32 +20,89 @@ jobs:

alpine:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
distro_version: ["3.19", "3.20"]
runtime_version: ["3.10", "3.11", "3.12", "3.13"]
include:
- distro_version: "3.21"
runtime_version: "3.14"

steps:
- uses: actions/checkout@v4
- name: Run alpine integration tests
run: DISTRO=alpine make test-integ
- name: Run integration test (alpine ${{ matrix.distro_version }} / python ${{ matrix.runtime_version }})
run: |
docker build -t codebuild-agent - < tests/integration/codebuild-local/Dockerfile.agent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repeated across all jobs, having it in a common job would reduce time further

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, but this is going away with #208 so if that looks good to you let's merge both?

CODEBUILD_IMAGE_TAG=codebuild-agent tests/integration/codebuild-local/test_one.sh \
tests/integration/codebuild/buildspec.os.alpine.yml \
alpine "${{ matrix.distro_version }}" "${{ matrix.runtime_version }}"

amazonlinux:
debian:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
distro_version: ["bookworm", "bullseye"]
runtime_version: ["3.10", "3.11", "3.12", "3.13"]
include:
- distro_version: "bookworm"
runtime_version: "3.14"

steps:
- uses: actions/checkout@v4
- name: Run amazonlinux integration tests
run: DISTRO=amazonlinux make test-integ
- name: Run integration test (debian ${{ matrix.distro_version }} / python ${{ matrix.runtime_version }})
run: |
docker build -t codebuild-agent - < tests/integration/codebuild-local/Dockerfile.agent
CODEBUILD_IMAGE_TAG=codebuild-agent tests/integration/codebuild-local/test_one.sh \
tests/integration/codebuild/buildspec.os.debian.yml \
debian "${{ matrix.distro_version }}" "${{ matrix.runtime_version }}"

debian:
amazonlinux2:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
runtime_version: ["3.10", "3.11"]

steps:
- uses: actions/checkout@v4
- name: Run integration test (amazonlinux 2 / python ${{ matrix.runtime_version }})
run: |
docker build -t codebuild-agent - < tests/integration/codebuild-local/Dockerfile.agent
CODEBUILD_IMAGE_TAG=codebuild-agent tests/integration/codebuild-local/test_one.sh \
tests/integration/codebuild/buildspec.os.amazonlinux.2.yml \
amazonlinux2 "2" "${{ matrix.runtime_version }}"

amazonlinux2023:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
runtime_version: ["3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4
- name: Run debian integration tests
run: DISTRO=debian make test-integ
- name: Run integration test (amazonlinux 2023 / python ${{ matrix.runtime_version }})
run: |
docker build -t codebuild-agent - < tests/integration/codebuild-local/Dockerfile.agent
CODEBUILD_IMAGE_TAG=codebuild-agent tests/integration/codebuild-local/test_one.sh \
tests/integration/codebuild/buildspec.os.amazonlinux.2023.yml \
amazonlinux2023 "2023" "${{ matrix.runtime_version }}"

ubuntu:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
distro_version: ["22.04", "24.04"]
runtime_version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v4
- name: Run ubuntu integration tests
run: DISTRO=ubuntu make test-integ
- name: Run integration test (ubuntu ${{ matrix.distro_version }} / python ${{ matrix.runtime_version }})
run: |
docker build -t codebuild-agent - < tests/integration/codebuild-local/Dockerfile.agent
CODEBUILD_IMAGE_TAG=codebuild-agent tests/integration/codebuild-local/test_one.sh \
tests/integration/codebuild/buildspec.os.ubuntu.yml \
ubuntu "${{ matrix.distro_version }}" "${{ matrix.runtime_version }}"
19 changes: 19 additions & 0 deletions tests/integration/codebuild-local/test_one.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ function usage {
>&2 echo " env Additional environment variables file."
}

function pull_with_retry() {
local image="$1"
local max_retries=3
local wait=10
for attempt in $(seq 1 $max_retries); do
if docker pull "$image"; then
return 0
fi
>&2 echo "Docker pull attempt $attempt/$max_retries failed. Retrying in ${wait}s..."
sleep $wait
wait=$((wait * 2))
done
>&2 echo "Failed to pull $image after $max_retries attempts."
return 1
}

main() {
if (( $# != 3 && $# != 4)); then
>&2 echo "Invalid number of parameters."
Expand Down Expand Up @@ -49,6 +65,9 @@ main() {
ARTIFACTS_DIR="$CODEBUILD_TEMP_DIR/artifacts"
mkdir -p "$ARTIFACTS_DIR"

# Pre-pull the CodeBuild local agent image with retries to handle ECR rate limits.
pull_with_retry "public.ecr.aws/codebuild/local-builds:latest"

# Run CodeBuild local agent.
"$(dirname "$0")"/codebuild_build.sh \
-i "$CODEBUILD_IMAGE_TAG" \
Expand Down
8 changes: 6 additions & 2 deletions tests/test_concurrency.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ def setUp(self):
self.socket = "/tmp/sock"

def test_success_and_failure_isolation(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test needs to be updated to reflect what are actually checking, using fork explicitly hides what's actually being used, so in the context of python 3.14 we force the test to use fork while we know the default now is to use forkserver. I'd use multiprocessing.Manager to track the shared data and this way we won't need to force usage of fork

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, will change this

success_counter = multiprocessing.Value("i", 0)
fail_counter = multiprocessing.Value("i", 0)
ctx = multiprocessing.get_context("fork")
success_counter = ctx.Value("i", 0)
fail_counter = ctx.Value("i", 0)

def fake_bootstrap_run(handler, lambda_runtime_client):
pid = multiprocessing.current_process().pid
Expand All @@ -37,6 +38,9 @@ def fake_bootstrap_run(handler, lambda_runtime_client):
), patch(
"awslambdaric.lambda_multi_concurrent_utils.bootstrap.run",
side_effect=fake_bootstrap_run,
), patch(
"awslambdaric.lambda_multi_concurrent_utils.multiprocessing.Process",
ctx.Process,
):
# spawn 4 multi-concurrent processes
MultiConcurrentRunner.run_concurrent(
Expand Down
Loading