diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index b1643afe8..3b69b629e 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -13,6 +13,10 @@ inputs: description: The path for downloading the built artifacts required: false default: contracts/target/deploy + suites: + description: The test suites to build into the image + default: smoke soak + required: false QA_AWS_ROLE_TO_ASSUME: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action required: true @@ -57,7 +61,7 @@ runs: build-args: | BASE_IMAGE=${{ inputs.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ inputs.QA_AWS_REGION }}.amazonaws.com/test-base-image IMAGE_VERSION=${{ steps.version.outputs.version }} - SUITES="smoke" + SUITES="${{ inputs.suites }}" AWS_REGION: ${{ inputs.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ inputs.QA_AWS_ROLE_TO_ASSUME }} - name: Print Image Built diff --git a/.github/workflows/e2e_custom_cl.yml b/.github/workflows/e2e_custom_cl.yml index cd63b51b1..d58618033 100644 --- a/.github/workflows/e2e_custom_cl.yml +++ b/.github/workflows/e2e_custom_cl.yml @@ -47,6 +47,27 @@ jobs: id: psversion uses: ./.github/actions/projectserum_version + solana-test-image-exists: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + name: Check If Solana Test Image Exists + runs-on: ubuntu-latest + outputs: + exists: ${{ steps.check-image.outputs.exists }} + steps: + - name: Check if image exists + id: check-image + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19 + with: + repository: chainlink-solana-tests + tag: ${{ github.sha }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + e2e_custom_build_artifacts: name: E2E Custom Build Artifacts environment: integration @@ -55,11 +76,6 @@ jobs: contents: read runs-on: ubuntu-latest-32cores-128GB needs: [get_projectserum_version] - # container: - # image: projectserum/build:${{ needs.get_projectserum_version.outputs.projectserum_version }} - # env: - # RUSTUP_HOME: "/root/.rustup" - # FORCE_COLOR: 1 steps: - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 @@ -108,6 +124,36 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + build_test_image: + environment: integration + if: contains(join(github.event.pull_request.labels.*.name, ' '), 'build-test-image') + permissions: + id-token: write + contents: read + name: Build Test Image + runs-on: ubuntu-latest + needs: [e2e_custom_build_artifacts] + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@v1 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Test Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Build Image + uses: ./.github/actions/build-test-image + with: + artifacts_path: ${{ env.CONTRACT_ARTIFACTS_PATH }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + e2e_custom_run_smoke_tests: name: E2E Custom Run Smoke Tests environment: integration diff --git a/.github/workflows/e2e_testnet_daily.yml b/.github/workflows/e2e_testnet_daily.yml index a6acfe644..d1adf5a04 100644 --- a/.github/workflows/e2e_testnet_daily.yml +++ b/.github/workflows/e2e_testnet_daily.yml @@ -23,9 +23,11 @@ on: type: string schedule: - cron: '0 6 * * *' +# Only run 1 of this workflow at a time per PR env: CL_ECR: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink CONTRACT_ARTIFACTS_PATH: contracts/target/deploy + MOD_CACHE_VERSION: 1 # Only run 1 of this workflow at a time per PR concurrency: @@ -33,143 +35,47 @@ concurrency: cancel-in-progress: true jobs: - changes: - environment: integration - name: Check Paths That Require Tests To Run - runs-on: ubuntu-latest - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 - with: - id: solana-e2e-detect-changes - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Check Paths That Require Tests To Run - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 - id: changes - with: - filters: | - src: - - '**/*.go' - - '**/*go.sum' - - '**/*go.mod' - - '.github/workflows/integration-tests.yml' - - '**/*Dockerfile' - - 'core/**/config/**/*.toml' - outputs: - src: ${{ steps.changes.outputs.src }} - get_solana_sha: - name: Get Solana Sha From Go Mod - environment: Integration + check_test_compilation: + name: Check integration test compilation runs-on: ubuntu-latest - outputs: - sha: ${{ github.sha }} steps: - - name: Checkout the repo + - name: Checkout sources uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + - name: Setup go + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Setup Go - uses: ./.github/actions/setup-go - with: - only-modules: "true" - - name: Get the sha from go mod - id: getshortsha - run: | - short_sha=$(git rev-parse --short HEAD) - echo "short sha is: ${short_sha}" - echo "short_sha=${short_sha}" >> "$GITHUB_OUTPUT" - - name: Checkout solana - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - with: - repository: smartcontractkit/chainlink-solana - ref: develop - fetch-depth: 0 - path: solanapath + go-version-file: "go.mod" + check-latest: true + cache: true + - run: cd ./integration-tests && go test -run=xxx ./... get_projectserum_version: name: Get ProjectSerum Version environment: integration runs-on: ubuntu-latest - needs: [ get_solana_sha ] outputs: projectserum_version: ${{ steps.psversion.outputs.projectserum_version }} steps: - - name: Checkout the solana repo + - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - with: - repository: smartcontractkit/chainlink-solana - ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Get ProjectSerum Version id: psversion - uses: smartcontractkit/chainlink-solana/.github/actions/projectserum_version@4b971869e26b79c7ce3fb7c98005cc2e3f350915 # stable action on Oct 12 2022 + uses: ./.github/actions/projectserum_version - solana-test-image-exists: + e2e_custom_build_artifacts: + name: E2E Custom Build Artifacts environment: integration permissions: - checks: write - pull-requests: write id-token: write contents: read - name: Check If Solana Test Image Exists - runs-on: ubuntu-latest - needs: [ get_solana_sha ] - outputs: - exists: ${{ steps.check-image.outputs.exists }} + runs-on: ubuntu-latest-32cores-128GB + needs: [get_projectserum_version] steps: - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 - with: - repository: chainlink-solana-tests - tag: ${{ needs.get_solana_sha.outputs.sha }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - e2e_custom_build_artifacts: - name: Solana Build Artifacts - runs-on: ubuntu20.04-16cores-64GB - needs: - [ - changes, - get_projectserum_version, - solana-test-image-exists, - get_solana_sha, - ] - # container: - # image: projectserum/build:${{ needs.get_projectserum_version.outputs.projectserum_version }} - # env: - # RUSTUP_HOME: "/root/.rustup" - # FORCE_COLOR: 1 - steps: - - name: Collect Metrics - if: needs.changes.outputs.src == 'true' - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 - with: - id: solana-e2e-build-artivacts - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Solana Build Artifacts - continue-on-error: true - - name: Checkout the solana repo - # Use v3.6.0 because the custom runner (container configured above) - # doesn't have node20 installed which is required for versions >=4 + - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - with: - repository: smartcontractkit/chainlink-solana - ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Build contracts - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' uses: ./.github/actions/build_contract_artifacts with: - ref: ${{ needs.get_solana_sha.outputs.sha }} image: projectserum/build image-version: ${{ needs.get_projectserum_version.outputs.projectserum_version }} @@ -180,13 +86,15 @@ jobs: permissions: id-token: write contents: read + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Check if image exists id: check-image uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 with: repository: chainlink - tag: solana.${{ github.sha }} + tag: solana.${{ env.CUSTOM_CORE_REF || github.event.inputs.cl_branch_ref || github.sha }} AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - name: Build Image @@ -195,74 +103,28 @@ jobs: with: should_checkout: true cl_repo: smartcontractkit/chainlink - cl_ref: ${{ github.event.inputs.cl_branch_ref }} + cl_ref: ${{ env.CUSTOM_CORE_REF || github.event.inputs.cl_branch_ref }} dep_solana_sha: ${{ github.event.pull_request.head.sha }} - push_tag: ${{ env.CL_ECR }}:solana.${{ github.sha }} + push_tag: ${{ env.CL_ECR }}:solana.${{ env.CUSTOM_CORE_REF || github.event.inputs.cl_branch_ref || github.sha }} QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - build_test_image: - environment: integration - permissions: - id-token: write - contents: read - name: Build Test Image - runs-on: ubuntu-latest - needs: [e2e_custom_build_artifacts, changes, solana-test-image-exists, get_solana_sha] - steps: - - name: Collect Metrics - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 - with: - id: solana-e2e-build-test-image - org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: Build Test Image - continue-on-error: true - - name: Checkout the repo - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Build Test Image - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' - uses: ./.github/actions/build-test-image - with: - tag: ${{ needs.get_solana_sha.outputs.sha }} - artifacts_path: ${{ env.CONTRACT_ARTIFACTS_PATH }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - - run: echo "this exists so we don't have to run anything else if the build is skipped" - if: needs.changes.outputs.src == 'false' || needs.solana-test-image-exists.outputs.exists == 'true' - - e2e_custom_run_daily_testnet_smoke_tests: - name: E2E Run Daily Smoke Tests + e2e_custom_run_smoke_tests: + name: E2E Custom Run Smoke Tests environment: integration permissions: checks: write pull-requests: write id-token: write contents: read - runs-on: ubuntu-latest + runs-on: ubuntu-latest-16cores-64GB - needs: [e2e_custom_build_artifacts, e2e_custom_build_custom_chainlink_image, build_test_image] + needs: [e2e_custom_build_artifacts, e2e_custom_build_custom_chainlink_image, check_test_compilation] env: TEST_SUITE: smoke TEST_ARGS: -test.timeout 30m - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug - SELECTED_NETWORKS: SIMULATED - RPC_URL: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.RPC_URL || 'https://api.devnet.solana.com' }} - WS_URL: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.WS_URL || 'wss://api.devnet.solana.com/' }} - PROGRAM_ID_OCR2: cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ - PROGRAM_ID_ACCESS_CONTROLLER: 9xi644bRR8birboDGdTiwBq3C7VEeR7VuamRYYXCubUW - PROGRAM_ID_STORE: HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny - LINK_TOKEN: 7CF1GrsZsny5j9JESPj98MdYVZK38RE8ZpmTEMwECK4c - VAULT_ADDRESS: FdM4dnhVpFQfjPqNG6LEfzArhuGhUjtidYu89qtGwJCS - PRIVATE_KEY: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.PRIVATE_KEY || secrets.PRIVATE_KEY }} - INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Collect Metrics id: collect-gha-metrics @@ -272,21 +134,51 @@ jobs: org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} - this-job-name: E2E Run Daily Smoke Tests + this-job-name: E2E Custom Run Daily Smoke Tests test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + - name: Install Solana CLI # required for ensuring the local test validator is configured correctly + run: ./scripts/install-solana-ci.sh + - name: Install gauntlet + uses: ./.github/actions/build-gauntlet + - name: Generate config overrides + run: | # https://github.com/smartcontractkit/chainlink-testing-framework/blob/main/config/README.md + cat << EOF > config.toml + [ChainlinkImage] + image="${{ env.CL_ECR }}" + version="solana.${{ env.CUSTOM_CORE_REF || github.event.inputs.cl_branch_ref || github.sha }}" + [Common] + user="${{ github.actor }}" + network="devnet" + private_key="${{ github.event_name == 'workflow_dispatch' && github.event.inputs.PRIVATE_KEY || secrets.PRIVATE_KEY }}" + internal_docker_repo = "${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com" + rpc_url = "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.RPC_URL || 'https://api.devnet.solana.com' }}" + ws_url = "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.RPC_URL || 'https://api.devnet.solana.com' }}" + EOF + + # shellcheck disable=SC2002 + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + # shellcheck disable=SC2086 + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + # shellcheck disable=SC2086 + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 with: - test_command_to_run: cd ./integration-tests && go test -timeout 24h -count=1 -run TestSolanaGauntletOCRV2Smoke -json $(args) ./smoke 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage + test_command_to_run: cd ./integration-tests && go test -timeout 24h -count=1 -run TestSolanaOCRV2Smoke/embedded -json $(args) ./smoke 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage + test_download_vendor_packages_command: cd ./integration-tests && go mod download + download_contract_artifacts_path: ${{ env.CONTRACT_ARTIFACTS_PATH }} go_mod_path: ./integration-tests/go.mod cl_repo: ${{ env.CL_ECR }} - cl_image_tag: solana.${{ github.sha }} - artifacts_location: /home/runner/work/chainlink-solana/chainlink-solana/integration-tests/logs + cl_image_tag: solana.${{ env.CUSTOM_CORE_REF || github.event.inputs.cl_branch_ref || github.sha }} token: ${{ secrets.GITHUB_TOKEN }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: smoke-test-logs + artifacts_location: ./integration-tests/smoke/logs/ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - should_cleanup: false + cache_key_id: solana-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "false" diff --git a/.github/workflows/soak.yml b/.github/workflows/soak.yml index 182904a82..28bd2f9d2 100644 --- a/.github/workflows/soak.yml +++ b/.github/workflows/soak.yml @@ -1,29 +1,24 @@ -name: E2E Soak Test +name: on_demand_soak_test on: - schedule: - - cron: '0 0 * * *' workflow_dispatch: inputs: - cl_branch_ref: - description: Chainlink repo branch to integrate with + base64_config: + description: Your .toml file as base64 required: true - default: develop - type: string - ttl: - description: The total time for the test to live + cl_image_tag: + description: Core image tag required: true - default: 3h + default: develop type: string - node_count: - description: The number of chainlink nodes to use + test_runner_tag: + description: Remote runner tag that will run the tests + default: develop required: true - default: '5' type: string - env: - REF_NAME: ${{ github.head_ref || github.ref_name }} - ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ github.sha }} + CL_ECR: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink CONTRACT_ARTIFACTS_PATH: contracts/target/deploy + MOD_CACHE_VERSION: 1 jobs: get_projectserum_version: @@ -38,121 +33,81 @@ jobs: - name: Get ProjectSerum Version id: psversion uses: ./.github/actions/projectserum_version - test-image-exists: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - name: Check If Solana Test Image Exists - runs-on: ubuntu-latest - outputs: - exists: ${{ steps.check-image.outputs.exists }} - steps: - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 - with: - repository: chainlink-solana-tests - tag: ${{ github.sha }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - soak_testing_build_contracts: - name: Soak Testing Build Contracts + e2e_custom_build_artifacts: + name: E2E Custom Build Artifacts environment: integration permissions: id-token: write contents: read - runs-on: ubuntu-latest - needs: [get_projectserum_version, test-image-exists] - # container: - # image: projectserum/build:${{ needs.get_projectserum_version.outputs.projectserum_version }} - # env: - # RUSTUP_HOME: "/root/.rustup" - # FORCE_COLOR: 1 + runs-on: ubuntu-latest-32cores-128GB + needs: [get_projectserum_version] steps: - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - name: Build contracts - if: needs.test-image-exists.outputs.exists == 'false' uses: ./.github/actions/build_contract_artifacts with: image: projectserum/build image-version: ${{ needs.get_projectserum_version.outputs.projectserum_version }} - soak_testing_build_custom_chainlink_image: - name: Soak Testing Build Custom Chainlink Image - runs-on: ubuntu-latest - environment: integration - permissions: - id-token: write - contents: read - steps: - - name: Check if image exists - id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 - with: - repository: chainlink - tag: solana.${{ github.sha }} - AWS_REGION: ${{ secrets.QA_AWS_REGION }} - AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - name: Build Image - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-image@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 - with: - should_checkout: true - cl_repo: smartcontractkit/chainlink - cl_ref: ${{ github.event.inputs.cl_branch_ref }} - dep_solana_sha: ${{ github.sha }} - push_tag: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink:solana.${{ github.sha }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - - soak_testing_run_test: - name: Soak Testing Run Test + e2e_custom_run_smoke_tests: + name: Run on demand soak test environment: integration permissions: checks: write pull-requests: write id-token: write contents: read - runs-on: ubuntu-latest - needs: [soak_testing_build_contracts, soak_testing_build_custom_chainlink_image] + runs-on: ubuntu-latest-16cores-64GB + + needs: [e2e_custom_build_artifacts] env: - DETACH_RUNNER: false - TEST_SUITE: soak - TEST_ARGS: -test.timeout 4h - CHAINLINK_COMMIT_SHA: ${{ github.sha }} - CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_ARGS: -test.timeout 30m TEST_LOG_LEVEL: debug - TTL: ${{ github.event.inputs.ttl }} - NODE_COUNT: ${{ github.event.inputs.node_count }} - SELECTED_NETWORKS: SIMULATED + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TEST_SUITE: soak + DETACH_RUNNER: true + ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ github.event.inputs.test_runner_tag }} steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@dea9b546553cb4ca936607c2267a09c004e4ab3f # v3.0.0 + with: + id: solana-e2e-soak + org-id: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} + basic-auth: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_INTERNAL_HOST }} + this-job-name: Run on demand soak test + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true - name: Checkout the repo uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - with: - ref: ${{ env.REF_NAME }} - - name: Build Test Image - uses: ./.github/actions/build-test-image - with: - artifacts_path: ${{ env.CONTRACT_ARTIFACTS_PATH }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ACCOUNT_NUMBER: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + - name: Install Solana CLI # required for ensuring the local test validator is configured correctly + run: ./scripts/install-solana-ci.sh + - name: Install gauntlet + uses: ./.github/actions/build-gauntlet + - name: Mask base64 config + # shellcheck disable=SC2086 + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64_config' "$GITHUB_EVENT_PATH") + echo "::add-mask::$BASE64_CONFIG_OVERRIDE" + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> "$GITHUB_ENV" - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@b49a9d04744b0237908831730f8553f26d73a94b # v2.3.17 with: - test_command_to_run: cd ./integration-tests && go test -timeout 5h -count=1 -json $(args) ./soak 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage + test_command_to_run: cd ./integration-tests && go test -timeout 24h -count=1 -run TestSolanaOCRV2Soak/embedded -json $(args) ./soak 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage + test_download_vendor_packages_command: cd ./integration-tests && go mod download + download_contract_artifacts_path: ${{ env.CONTRACT_ARTIFACTS_PATH }} go_mod_path: ./integration-tests/go.mod - cl_repo: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - cl_image_tag: solana.${{ github.sha }} - artifacts_location: /home/runner/work/chainlink-solana/chainlink-solana/integration-tests/soak/logs - publish_report_paths: ./tests-soak-report.xml - publish_check_name: Soak Test Results + cl_repo: ${{ env.CL_ECR }} + cl_image_tag: ${{ github.event.inputs.cl_image_tag }} token: ${{ secrets.GITHUB_TOKEN }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: smoke-test-logs + artifacts_location: ./integration-tests/smoke/logs/ QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - should_cleanup: false + cache_key_id: solana-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "false" diff --git a/.gitignore b/.gitignore index e87046e53..e13c19b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ eslint-report.json override*.toml # go work files go.work* +gauntlet-*/ diff --git a/docs/RunningE2eTests.md b/docs/RunningE2eTests.md index babdf6b94..5c44dbcfa 100644 --- a/docs/RunningE2eTests.md +++ b/docs/RunningE2eTests.md @@ -34,4 +34,24 @@ By default all values are pulled either from `default.toml` or if we create an ` `cd integration-tests/smoke && go test -timeout 24h -count=1 -run TestSolanaOCRV2Smoke -test.timeout 30m;` +### On demand soak test +Navigate to the [workflow](https://github.com/smartcontractkit/chainlink-solana/actions/workflows/soak.yml). The workflow takes in 3 parameters: + +- Base64 string of the .toml configuration +- Core image tag which defaults to develop +- Test runner tag, only tag needs to be supplied + - In order to create the test image a label needs to be added to the PR `build-test-image` which will start building it on every push. + +Create an `overrides.toml` file in `integration-tests/testconfig` and run `cat overrides.toml | base64`. `inside_k8` needs to be set to true in the .toml in order to run the tests in kubernetes. + +#### Local + +If you want to kick off the test from local: + +- `export TEST_SUITE: soak` +- `export DETACH_RUNNER: true` +- `export ENV_JOB_IMAGE: /chainlink-solana-tests:` +- Base64 the .toml config +- Run `export BASE64_CONFIG_OVERRIDE=""` +- cd integration-tests/soak && go test -timeout 24h -count=1 -run TestSolanaOCRV2Soak -test.timeout 30m; diff --git a/integration-tests/common/test_common.go b/integration-tests/common/test_common.go index 20565ec4d..ec6764faa 100644 --- a/integration-tests/common/test_common.go +++ b/integration-tests/common/test_common.go @@ -107,6 +107,10 @@ func (m *OCRv2TestState) DeployCluster(contractsDir string) { if *m.Config.TestConfig.Common.InsideK8s { m.DeployEnv(contractsDir) + if m.Common.Env.WillUseRemoteRunner() { + return + } + // Setting up the URLs m.Common.ChainDetails.RPCURLExternal = m.Common.Env.URLs["sol"][0] m.Common.ChainDetails.WSURLExternal = m.Common.Env.URLs["sol"][1] @@ -181,7 +185,9 @@ func (m *OCRv2TestState) DeployEnv(contractsDir string) { err := m.Common.Env.Run() require.NoError(m.Config.T, err) - m.UploadProgramBinaries(contractsDir) + if !m.Common.Env.WillUseRemoteRunner() { + m.UploadProgramBinaries(contractsDir) + } } func (m *OCRv2TestState) NewSolanaClientSetup(networkSettings *solclient.SolNetwork) (*solclient.Client, error) { diff --git a/integration-tests/scripts/buildTestImage b/integration-tests/scripts/buildTestImage index 22c70e098..9a883da4a 100755 --- a/integration-tests/scripts/buildTestImage +++ b/integration-tests/scripts/buildTestImage @@ -13,7 +13,7 @@ cd "$SCRIPT_DIR"/../../ || exit 1 TAG_VERSION="${1}" BASE_IMAGE_VERSION="${2}" SUITES=$3 -DEFAULT_SUITES="smoke" +DEFAULT_SUITES="smoke soak" ACCOUNT=$(aws sts get-caller-identity | jq -r .Account) AWS_BASE="${ACCOUNT}".dkr.ecr.us-west-2.amazonaws.com TAG="${AWS_BASE}"/chainlink-solana-tests:"${TAG_VERSION}" @@ -34,7 +34,7 @@ if [ "${SUITES}" = "" ]; then SUITES=${DEFAULT_SUITES} fi -aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin "${AWS_BASE}" +aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin ${AWS_BASE} docker build -t "${TAG}" -f "./integration-tests/test.Dockerfile" --build-arg BASE_IMAGE="${BASE_IMAGE}" --build-arg IMAGE_VERSION="${BASE_IMAGE_VERSION}" --build-arg SUITES="${SUITES}" . if "${4}" = "true"]; then docker push "${TAG}" diff --git a/integration-tests/scripts/buildTests b/integration-tests/scripts/buildTests index 86fa5a8e8..b6033c1c4 100755 --- a/integration-tests/scripts/buildTests +++ b/integration-tests/scripts/buildTests @@ -8,10 +8,10 @@ set -ex # get this scripts directory SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) -helm repo update - cd "$SCRIPT_DIR"/../ || exit 1 +helm repo update + # parse out quotes if they exist in the string temp="${1%\"}" tosplit="${temp#\"}" @@ -21,6 +21,12 @@ OIFS=$IFS IFS=' ' for x in $tosplit do - go test -c ./"${x}" + if [ "$x" = "load" ]; then + echo "Changing directory and executing go test -c ./... for 'load' package" + pushd "./load" && go test -c -tags embed -o .. ./... + popd + else + go test -c -tags embed ./"${x}" + fi done IFS=$OIFS diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index 156b20d34..cc9a498cb 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -2,7 +2,7 @@ # Runs tests for a specific product -set -ex +set -x # get this scripts directory SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) @@ -16,3 +16,21 @@ cd "$SCRIPT_DIR"/../ || exit 1 # run the tests ./${SUITE}.test -test.v -test.count 1 ${ARGS} -test.run ^${TEST_NAME}$ + +exit_code=$? + +echo "Test exit code: ${exit_code}" + +# Check if the test did not pass (non-zero exit code) +if [ $exit_code -ne 0 ]; then + # 3 is the code for an interrupted test, we only want to restart the test when the test is interrupted and in a state + # that it can recover from. Otherwise we mark the test as "passed" as far as K8s is concerned so it doesn't restart it. + if [ $exit_code -eq 3 ]; then + echo "Test was interrupted, exiting with 1 exit code to trigger K8s to restart" + exit 1 # Exiting with non-zero status to trigger pod restart + else + echo "Test either panicked or had some sort of failure. We're exiting with a non-zero exit code so that K8s doesn't restart the pod." + echo "TEST_FAILED" + fi +fi + diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index dd878cdb6..c10ee820c 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -10,7 +10,6 @@ import ( "github.com/rs/zerolog/log" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink-solana/integration-tests/common" @@ -53,6 +52,9 @@ func TestSolanaOCRV2Smoke(t *testing.T) { } state.DeployCluster(utils.ContractsDir) + if state.Common.Env.WillUseRemoteRunner() { + return + } // copy gauntlet folder to run in parallel (gauntlet generates an output file that is read by the e2e tests - causes conflict if shared) gauntletCopyPath := utils.ProjectRoot + "/" + name @@ -66,11 +68,13 @@ func TestSolanaOCRV2Smoke(t *testing.T) { if *config.Common.InsideK8s { t.Cleanup(func() { - if err = actions.TeardownRemoteSuite(t, state.Common.Env.Cfg.Namespace, state.Clients.ChainlinkClient.ChainlinkClientK8s, nil, nil, nil); err != nil { - log.Error().Err(err).Msg("Error tearing down environment") + err = state.Common.Env.Shutdown() + if err != nil { + log.Err(err) } }) } + state.SetupClients() require.NoError(t, err) @@ -127,7 +131,7 @@ func TestSolanaOCRV2Smoke(t *testing.T) { prevRound := gauntlet.Transmission{ RoundID: 0, } - for successFullRounds < *config.OCR2.Smoke.NumberOfRounds { + for successFullRounds < *config.OCR2.NumberOfRounds { time.Sleep(time.Second * 6) require.Less(t, stuck, 10, fmt.Sprintf("%s: Rounds have been stuck for more than 10 iterations", name)) log.Info().Str("Transmission", sg.OcrAddress).Msg("Inspecting transmissions") @@ -147,7 +151,7 @@ func TestSolanaOCRV2Smoke(t *testing.T) { stuck++ continue } - log.Info().Str("Contract", sg.OcrAddress).Interface("Answer", currentRound.Answer).Int64("RoundID", currentRound.Answer).Msg(fmt.Sprintf("%s: New answer found", name)) + log.Info().Str("Contract", sg.OcrAddress).Interface("Answer", currentRound.Answer).Int64("RoundID", currentRound.RoundID).Msg(fmt.Sprintf("%s: New answer found", name)) require.Equal(t, currentRound.Answer, int64(5), fmt.Sprintf("Actual: %d, Expected: 5", currentRound.Answer)) require.Less(t, prevRound.RoundID, currentRound.RoundID, fmt.Sprintf("Expected round %d to be less than %d", prevRound.RoundID, currentRound.RoundID)) prevRound = currentRound diff --git a/integration-tests/soak/ocr2_test.go b/integration-tests/soak/ocr2_test.go new file mode 100644 index 000000000..1c53727af --- /dev/null +++ b/integration-tests/soak/ocr2_test.go @@ -0,0 +1,170 @@ +package soak + +import ( + "fmt" + "maps" + "os/exec" + "testing" + "time" + + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + "github.com/smartcontractkit/chainlink-solana/integration-tests/common" + ocr_config "github.com/smartcontractkit/chainlink-solana/integration-tests/config" + "github.com/smartcontractkit/chainlink-solana/integration-tests/gauntlet" + tc "github.com/smartcontractkit/chainlink-solana/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink-solana/integration-tests/utils" +) + +func TestSolanaOCRV2Soak(t *testing.T) { + for _, test := range []struct { + name string + env map[string]string + }{ + {name: "embedded"}, + {name: "plugins", env: map[string]string{ + "CL_MEDIAN_CMD": "chainlink-feeds", + "CL_SOLANA_CMD": "chainlink-solana", + }}, + } { + config, err := tc.GetConfig("Soak", tc.OCR2) + if err != nil { + t.Fatal(err) + } + + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + name := "gauntlet-" + test.name + state, err := common.NewOCRv2State(t, 1, name, &config) + require.NoError(t, err, "Could not setup the ocrv2 state") + if len(test.env) > 0 { + state.Common.TestEnvDetails.NodeOpts = append(state.Common.TestEnvDetails.NodeOpts, func(n *test_env.ClNode) { + if n.ContainerEnvs == nil { + n.ContainerEnvs = map[string]string{} + } + maps.Copy(n.ContainerEnvs, test.env) + }) + } + + state.DeployCluster(utils.ContractsDir) + + if state.Common.Env.WillUseRemoteRunner() { + return + } + + // copy gauntlet folder to run in parallel (gauntlet generates an output file that is read by the e2e tests - causes conflict if shared) + gauntletCopyPath := utils.ProjectRoot + "/" + name + if out, cpErr := exec.Command("cp", "-r", utils.ProjectRoot+"/gauntlet", gauntletCopyPath).Output(); cpErr != nil { // nolint:gosec + require.NoError(t, err, "output: "+string(out)) + } + + sg, err := gauntlet.NewSolanaGauntlet(gauntletCopyPath) + require.NoError(t, err) + state.Gauntlet = sg + + if *config.Common.InsideK8s { + t.Cleanup(func() { + err = state.Common.Env.Shutdown() + if err != nil { + log.Err(err) + } + }) + } + state.SetupClients() + require.NoError(t, err) + + gauntletConfig := map[string]string{ + "SECRET": fmt.Sprintf("\"%s\"", *config.SolanaConfig.Secret), + "NODE_URL": state.Common.ChainDetails.RPCURLExternal, + "WS_URL": state.Common.ChainDetails.WSURLExternal, + "PRIVATE_KEY": state.Common.AccountDetails.PrivateKey, + } + + err = sg.SetupNetwork(gauntletConfig) + require.NoError(t, err, "Error setting gauntlet network") + err = sg.InstallDependencies() + require.NoError(t, err, "Error installing gauntlet dependencies") + + if *config.Common.Network == "devnet" { + state.Common.ChainDetails.ProgramAddresses.OCR2 = *config.SolanaConfig.OCR2ProgramID + state.Common.ChainDetails.ProgramAddresses.AccessController = *config.SolanaConfig.AccessControllerProgramID + state.Common.ChainDetails.ProgramAddresses.Store = *config.SolanaConfig.StoreProgramID + sg.LinkAddress = *config.SolanaConfig.LinkTokenAddress + sg.VaultAddress = *config.SolanaConfig.VaultAddress + } else { + // Deploying LINK in case of localnet + err = sg.DeployLinkToken() + require.NoError(t, err) + } + + err = sg.G.WriteNetworkConfigVar(sg.NetworkFilePath, "PROGRAM_ID_OCR2", state.Common.ChainDetails.ProgramAddresses.OCR2) + require.NoError(t, err, "Error adding gauntlet variable") + err = sg.G.WriteNetworkConfigVar(sg.NetworkFilePath, "PROGRAM_ID_ACCESS_CONTROLLER", state.Common.ChainDetails.ProgramAddresses.AccessController) + require.NoError(t, err, "Error adding gauntlet variable") + err = sg.G.WriteNetworkConfigVar(sg.NetworkFilePath, "PROGRAM_ID_STORE", state.Common.ChainDetails.ProgramAddresses.Store) + require.NoError(t, err, "Error adding gauntlet variable") + err = sg.G.WriteNetworkConfigVar(sg.NetworkFilePath, "LINK", sg.LinkAddress) + require.NoError(t, err, "Error adding gauntlet variable") + err = sg.G.WriteNetworkConfigVar(sg.NetworkFilePath, "VAULT_ADDRESS", sg.VaultAddress) + require.NoError(t, err, "Error adding gauntlet variable") + + _, err = sg.DeployOCR2() + require.NoError(t, err, "Error deploying OCR") + // Generating default OCR2 config + ocr2Config := ocr_config.NewOCR2Config(state.Clients.ChainlinkClient.NKeys, sg.ProposalAddress, sg.VaultAddress, *config.SolanaConfig.Secret) + ocr2Config.Default() + sg.OCR2Config = ocr2Config + + err = sg.ConfigureOCR2() + require.NoError(t, err) + + state.CreateJobs() + + // Test start + stuck := 0 + successFullRounds := 0 + prevRound := gauntlet.Transmission{ + RoundID: 0, + } + for successFullRounds < *config.OCR2.NumberOfRounds { + // Since it is a soak bumping the stuck count + require.Less(t, stuck, 100, "Rounds have been stuck for more than 10 iterations") + log.Info().Str("Transmission", sg.OcrAddress).Msg("Inspecting transmissions") + transmissions, err := sg.FetchTransmissions(sg.OcrAddress) + if err != nil { + log.Error().Str("Contract", "Error fetching transmissions").Msg(fmt.Sprintf("%v", err)) + } + if len(transmissions) <= 1 { + log.Info().Str("Contract", sg.OcrAddress).Str("No", "Transmissions") + stuck++ + continue + } + currentRound := common.GetLatestRound(transmissions) + if prevRound.RoundID == 0 { + prevRound = currentRound + } + if currentRound.RoundID <= prevRound.RoundID { + log.Info().Str("Transmission", sg.OcrAddress).Msg("No new transmissions") + stuck++ + continue + } + log.Info().Str("Contract", sg.OcrAddress).Interface("Answer", currentRound.Answer).Int64("RoundID", currentRound.RoundID).Msg("New answer found") + if currentRound.Answer != 5 { + log.Error().Str("Answer", "difference in answer").Msg(fmt.Sprintf("Expected %d, got %d", 5, currentRound.Answer)) + } + if prevRound.RoundID > currentRound.RoundID { + log.Error().Str("Answer", "difference in answer").Msg(fmt.Sprintf("Expected round %d to be less than %d", prevRound.RoundID, currentRound.RoundID)) + } + prevRound = currentRound + successFullRounds++ + time.Sleep(time.Second * 6) + stuck = 0 + } + }) + } +} diff --git a/integration-tests/test.Dockerfile b/integration-tests/test.Dockerfile index 8b7feeafc..5964b75df 100644 --- a/integration-tests/test.Dockerfile +++ b/integration-tests/test.Dockerfile @@ -2,7 +2,7 @@ ARG BASE_IMAGE ARG IMAGE_VERSION=latest FROM ${BASE_IMAGE}:${IMAGE_VERSION} -ARG SUITES=smoke +ARG SUITES=smoke soak COPY . testdir/ WORKDIR /go/testdir diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml index 5790560e6..76239df54 100644 --- a/integration-tests/testconfig/default.toml +++ b/integration-tests/testconfig/default.toml @@ -42,7 +42,12 @@ devnet_image = "solanalabs/solana:v1.18.15" [OCR2] node_count = 6 test_duration = "50m" +number_of_rounds = 2 [OCR2.Smoke] -number_of_rounds = 2 +enabled = true + +[OCR2.Soak] +enabled = false + diff --git a/integration-tests/testconfig/ocr2/ocr2.go b/integration-tests/testconfig/ocr2/ocr2.go index 8a27552fe..74260c3af 100644 --- a/integration-tests/testconfig/ocr2/ocr2.go +++ b/integration-tests/testconfig/ocr2/ocr2.go @@ -6,9 +6,9 @@ import ( ) type Config struct { - Smoke *SmokeConfig `toml:"Smoke"` - NodeCount *int `toml:"node_count"` - TestDuration *string `toml:"test_duration"` + NodeCount *int `toml:"node_count"` + NumberOfRounds *int `toml:"number_of_rounds"` + TestDuration *string `toml:"test_duration"` TestDurationParsed *time.Duration } @@ -26,24 +26,9 @@ func (o *Config) Validate() error { } o.TestDurationParsed = &duration - if o.Smoke == nil { - return errors.New("smoke must be defined") - } - err = o.Smoke.Validate() - if err != nil { - return err - } - - return nil -} - -type SmokeConfig struct { - NumberOfRounds *int `toml:"number_of_rounds"` -} - -func (o *SmokeConfig) Validate() error { if o.NumberOfRounds == nil { - return errors.New("number_of_rounds must be set") + return errors.New("number_of_rounds must be set for OCR2") } + return nil }