Skip to content
Closed
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
92 changes: 92 additions & 0 deletions .github/actions/ccip-e2e-setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: 'CCIP E2E Setup'
description: 'Common setup for CCIP E2E tests - caches, dependencies, and environment'

inputs:
contract_version:
description: 'Contract version to test against (local or commit SHA)'
required: true
default: 'local'
build_contracts:
description: 'Whether to build contracts locally'
required: false
default: 'true'

runs:
using: 'composite'
steps:
- name: Free Disk Space
uses: smartcontractkit/.github/actions/free-disk-space@free-disk-space/v1

- name: Relocate Nix store to /mnt
shell: bash
run: |
sudo mkdir -p /mnt/nix
sudo mkdir -p /nix
sudo mount --bind /mnt/nix /nix
df -h /nix /mnt

- name: Restore cached docker images
uses: actions/cache@v4
id: docker-cache-restore
with:
path: ${{ github.workspace }}/.cache/ccip-e2e-docker-images.tar
key: ccip-e2e-images-v2

- name: Load docker images
if: steps.docker-cache-restore.outputs.cache-hit == 'true'
shell: bash
run: |
echo "Cache hit. Loading images from tarball..."
docker load -i ${{ github.workspace }}/.cache/ccip-e2e-docker-images.tar

- name: Install Nix
uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # v31
with:
nix_path: nixpkgs=channel:nixos-unstable

- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
/home/runner/.cache/go-build
/home/runner/go/pkg/mod
key: go-${{ hashFiles('**/go.sum', 'chainlink/**/go.sum') }}

- name: Read Chainlink Core Ref
id: read_core_ref
shell: bash
run: |
CORE_REF=$(cat ./scripts/.core_version | tr -d '[:space:]')
# Validate it's a 40-char hex SHA (not a branch name)
if [[ ! "$CORE_REF" =~ ^[0-9a-f]{40}$ ]]; then
echo "ERROR: .core_version must be a full commit SHA, got: $CORE_REF"
exit 1
fi
echo "CORE_REF=$CORE_REF" >> $GITHUB_OUTPUT

- name: Cache Chainlink Core repo
uses: actions/cache@v4
id: core-cache
with:
path: chainlink
key: core-${{ steps.read_core_ref.outputs.CORE_REF }}

- name: Checkout Chainlink Core repo
if: steps.core-cache.outputs.cache-hit != 'true'
uses: actions/checkout@v5
with:
repository: smartcontractkit/chainlink
ref: ${{ steps.read_core_ref.outputs.CORE_REF }}
path: chainlink
persist-credentials: false

- name: Build contracts
if: inputs.build_contracts == 'true'
shell: bash
run: |
cd contracts
nix develop .#contracts -c yarn && yarn build

- name: Set contract version environment
shell: bash
run: echo "CCIP_CONTRACTS_TON_VERSION=${{ inputs.contract_version }}" >> $GITHUB_ENV
16 changes: 16 additions & 0 deletions .github/ccip-ton-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# CCIP TON E2E Test Definitions
# This file is the single source of truth for CCIP TON integration tests.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is the single source truth for our tests/apps in .github CI context?

I would prefer this source of truth to be in the core project, some task manager (nix, makefile, just) to define and run common operations, so everybody can easily trigger, and then the CI uses that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm I thought this list is mostly for CI. On local development, devs usually run tests they're interested in(mostly single test). But I can see the point where CI would only pick up predefined test organization, not define by itself

# Both ccip-integration-test.yml and ccip-staging-compat.yml workflows read from this file.
#
# To add a new test:
# 1. Add an entry to the 'tests' list below
# 2. The test will automatically run in both local and staging compatibility checks

tests:
- id: ccip_messaging_ton2evm
name: "TON2EVM Messaging Test"
cmd: "cd integration-tests && go test ./smoke/ccip -run Test_CCIPMessaging_TON2EVM -timeout 20m -test.parallel=1 -count=1 -json"

- id: ccip_messaging_evm2ton
name: "EVM2TON Messaging Test"
cmd: "cd integration-tests && go test ./smoke/ccip -run Test_CCIPMessaging_EVM2TON -timeout 20m -test.parallel=1 -count=1 -json"
118 changes: 34 additions & 84 deletions .github/workflows/ccip-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ env:
DOCKER_CACHE_KEY: ccip-e2e-images-v2
DOCKER_CACHE_DIR: ${{ github.workspace }}/.cache
DOCKER_CACHE_TAR_NAME: ccip-e2e-docker-images.tar
# mylocalton docker image / CCIP E2E test database image
DOCKER_IMAGES: >-
ghcr.io/neodix42/mylocalton-docker:v3.7
postgres:16-alpine

jobs:
prepare-images:
name: Prepare and Cache Docker Images
Expand All @@ -44,116 +44,66 @@ jobs:
docker save ${{ env.DOCKER_IMAGES }} \
-o ${{ env.DOCKER_CACHE_DIR }}/${{ env.DOCKER_CACHE_TAR_NAME }}

integration-test-matrix:
needs: prepare-images
strategy:
fail-fast: false
matrix:
type:
# Note: list of tests, add more tests here
- name: "TON2EVM Messaging Test"
cmd: "cd integration-tests && go test ./smoke/ccip -run Test_CCIPMessaging_TON2EVM -timeout 20m -test.parallel=1 -count=1 -json"
- name: "EVM2TON Messaging Test"
cmd: "cd integration-tests && go test ./smoke/ccip -run Test_CCIPMessaging_EVM2TON -timeout 20m -test.parallel=1 -count=1 -json"

name: ${{ matrix.type.name }}
load-tests:
name: Load Test Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Free Disk Space
uses: smartcontractkit/.github/actions/free-disk-space@free-disk-space/v1

- name: Checkout Repository
uses: actions/checkout@v5

- name: Restore cached docker images
id: docker-cache-restore
uses: actions/cache@v4
with:
path: ${{ env.DOCKER_CACHE_DIR }}/${{ env.DOCKER_CACHE_TAR_NAME }}
key: ${{ env.DOCKER_CACHE_KEY }}

- name: Load docker images
if: steps.docker-cache-restore.outputs.cache-hit == 'true'
- name: Load test definitions
id: set-matrix
run: |
echo "Cache hit for key '${{ env.DOCKER_CACHE_KEY }}'. Loading images from tarball..."
docker load -i ${{ env.DOCKER_CACHE_DIR }}/${{ env.DOCKER_CACHE_TAR_NAME }}

- name: Relocate Nix store to /mnt
run: |
sudo mkdir -p /mnt/nix
sudo mkdir -p /nix
sudo mount --bind /mnt/nix /nix
df -h /nix /mnt

- name: Install Nix
uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f # v31
with:
nix_path: nixpkgs=channel:nixos-unstable
MATRIX=$(yq -o=json -I=0 '.tests' .github/ccip-ton-tests.yml)
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

# cache Go build artifacts and modules to speed up subsequent runs
# key includes go.sum files from both chainlink-ton and chainlink core repos
# paths are standard Go cache locations on GitHub Actions runners
- name: Cache Go modules
uses: actions/cache@v4
with:
path: |
/home/runner/.cache/go-build
/home/runner/go/pkg/mod
key: go-${{ hashFiles('**/go.sum', 'chainlink/**/go.sum') }}

- name: Read Chainlink Core Ref from .core_version
id: read_core_ref
run: echo "CORE_REF=$(cat ./scripts/.core_version | tr -d '[:space:]')" >> $GITHUB_OUTPUT

# cache the entire Chainlink Core repository to avoid re-cloning
# key is based on the exact commit SHA from .core_version file
# only checkout if cache miss occurs
- name: Cache Chainlink Core repo
uses: actions/cache@v4
id: core-cache
with:
path: chainlink
key: core-${{ steps.read_core_ref.outputs.CORE_REF }}

- name: Checkout Chainlink Core repo
if: steps.core-cache.outputs.cache-hit != 'true'
integration-test:
name: ${{ matrix.test.name }}
needs: [prepare-images, load-tests]
runs-on: ubuntu-latest-4cores-16GB
strategy:
fail-fast: false
matrix:
test: ${{ fromJson(needs.load-tests.outputs.matrix) }}
steps:
- name: Checkout Repository
uses: actions/checkout@v5
with:
repository: smartcontractkit/chainlink
ref: ${{ steps.read_core_ref.outputs.CORE_REF }}
path: chainlink

- name: Build contracts
run: |
cd contracts
nix develop .#contracts -c yarn && yarn build
- name: Setup E2E Environment
uses: ./.github/actions/ccip-e2e-setup
with:
contract_version: 'local'
build_contracts: 'true'
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the point of this build_contracts flag you were thinking of?

I think we need it, as the above action should not build project components, but prepare a CI environment (nix, docker, cache, repo ref) in a reusable way, and then the action on top builds and prepares whatever it needs.

We define what we need in specific environments via Nix, an env like nix develop .#ccip-e2e will prepare/build/provide contracts to the e2e env, and whatever is defined in the Nix shell derivation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What's the point of this build_contracts flag you were thinking of?

  • build_contracts: true → Build latest contracts from this branch
  • build_contracts: false → Use released/deployed version

yeah I remember there was a missing piece in e2e Nix shell, contracts flake is already available but we were building them separately. Probably we can use or override it? Let me see if I can iterate on this


- name: Setup Environment and Run Tests
- name: Run Tests
run: |
echo "Testing with contract version: $CCIP_CONTRACTS_TON_VERSION"
nix develop .#ccip-e2e -c scripts/e2e/setup-env.sh --core-dir "${GITHUB_WORKSPACE}/chainlink"
nix develop .#ccip-e2e -c scripts/e2e/run-test.sh --core-dir "${GITHUB_WORKSPACE}/chainlink" --test-command "${{ matrix.type.cmd }}" --clean-logs
nix develop .#ccip-e2e -c scripts/e2e/run-test.sh --core-dir "${GITHUB_WORKSPACE}/chainlink" --test-command "${{ matrix.test.cmd }}" --clean-logs

- name: Upload e2e test logs on success
- name: Upload test logs on success
if: success()
uses: actions/upload-artifact@v4
with:
name: ccip-test-logs-${{ matrix.type.name }}
name: ccip-test-logs-${{ matrix.test.id }}
path: chainlink/integration-tests/smoke/ccip/logs/
retention-days: 3

- name: Upload e2e test logs on failure
- name: Upload test logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ccip-test-logs-${{ matrix.type.name }}
name: ccip-test-logs-${{ matrix.test.id }}
path: chainlink/integration-tests/smoke/ccip/logs/
retention-days: 7

integration-test-ccip:
if: always()
runs-on: ubuntu-latest
needs: [integration-test-matrix]
needs: [integration-test]
steps:
- name: Fail if any CCIP test failed
if: always() && needs.integration-test-matrix.result == 'failure'
- name: Check test results
if: needs.integration-test.result == 'failure'
run: exit 1
101 changes: 101 additions & 0 deletions .github/workflows/ccip-staging-compat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: "TON - CCIP Staging Compatibility"

# This workflow tests plugin compatibility with staging-deployed contracts.
# It serves as an early warning system - failures indicate that merging this PR
# will break staging until contracts are also updated.
#
# This workflow is INFORMATIONAL and should NOT be required for merge.
# Configure branch protection to only require "TON - CCIP Integration Tests".

on:
pull_request:
push:
branches:
- "main"

permissions:
contents: read
actions: read

env:
DOCKER_CACHE_KEY: ccip-e2e-images-v2
DOCKER_CACHE_DIR: ${{ github.workspace }}/.cache
DOCKER_CACHE_TAR_NAME: ccip-e2e-docker-images.tar

jobs:
load-tests:
name: Load Test Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
staging_version: ${{ steps.read-staging.outputs.version }}
steps:
- name: Checkout Repository
uses: actions/checkout@v5

- name: Load test definitions
id: set-matrix
run: |
MATRIX=$(yq -o=json -I=0 '.tests' .github/ccip-ton-tests.yml)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Think it would be great if immediately extend this to compat test matrix per env - it's gonna useful to run this against prod-testnet, and we can imagine we having more than one staging (sandbox?) envs.

We might have prod-testnet live, and need to patch off-chain, this will be useful to run.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We might have prod-testnet live, and need to patch off-chain, this will be useful to run.

yeah that would be great, I'll see how we can extend it targeting different environment(importing each state file seems promising)

echo "matrix=$MATRIX" >> $GITHUB_OUTPUT

- name: Read staging contract version
id: read-staging
run: |
VERSION=$(cat ./scripts/.staging_contract_version | tr -d '[:space:]')
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Staging contract version: $VERSION"

staging-compat-test:
name: "${{ matrix.test.name }} (Staging)"
needs: [load-tests]
runs-on: ubuntu-latest-4cores-16GB
strategy:
fail-fast: false
matrix:
test: ${{ fromJson(needs.load-tests.outputs.matrix) }}
steps:
- name: Checkout Repository
uses: actions/checkout@v5

- name: Setup E2E Environment
uses: ./.github/actions/ccip-e2e-setup
with:
contract_version: ${{ needs.load-tests.outputs.staging_version }}
build_contracts: 'false'

- name: Run Tests
run: |
echo "Testing staging compatibility with contract version: $CCIP_CONTRACTS_TON_VERSION"
nix develop .#ccip-e2e -c scripts/e2e/setup-env.sh --core-dir "${GITHUB_WORKSPACE}/chainlink"
nix develop .#ccip-e2e -c scripts/e2e/run-test.sh --core-dir "${GITHUB_WORKSPACE}/chainlink" --test-command "${{ matrix.test.cmd }}" --clean-logs

- name: Upload test logs on success
if: success()
uses: actions/upload-artifact@v4
with:
name: ccip-staging-compat-logs-${{ matrix.test.id }}
path: chainlink/integration-tests/smoke/ccip/logs/
retention-days: 3

- name: Upload test logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: ccip-staging-compat-logs-${{ matrix.test.id }}
path: chainlink/integration-tests/smoke/ccip/logs/
retention-days: 7

staging-compat-status:
name: Staging Compatibility Status
if: always()
runs-on: ubuntu-latest
needs: [staging-compat-test]
steps:
- name: Report staging compatibility
run: |
if [ "${{ needs.staging-compat-test.result }}" == "failure" ]; then
echo "::warning::Staging compatibility tests failed. After merging, staging contracts must be updated."
exit 1
fi
echo "Staging compatibility tests passed."
1 change: 1 addition & 0 deletions scripts/.staging_contract_version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
43d7a93089fe
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's load this from the CLD state file which should be the source of truth here, right? vs. hardcoding a magic sha

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

4 changes: 3 additions & 1 deletion scripts/e2e/lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ setup_contracts() {
log_info "Linking contracts to chainlink core (no copy, direct reference via symlink)..."
ln -sfn "$ROOT_DIR/contracts" "$chainlink_core_dir/contracts"

export CCIP_CONTRACTS_TON_VERSION="local"
# Default to "local" if not already set externally
export CCIP_CONTRACTS_TON_VERSION="${CCIP_CONTRACTS_TON_VERSION:-local}"
log_info "Contracts version: $CCIP_CONTRACTS_TON_VERSION"
log_info "Contracts ready at $chainlink_core_dir/contracts -> $ROOT_DIR/contracts"
}
Loading