diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 9174d7de1f5..0d4f0fb4c0a 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -179,23 +179,13 @@ jobs: run: | echo "TIMEOUT=10m" >> $GITHUB_ENV echo "COUNT=50" >> $GITHUB_ENV - - name: Install gotestloghelper - if: ${{ needs.filter.outputs.changes == 'true' }} - run: go install github.com/smartcontractkit/chainlink-testing-framework/tools/gotestloghelper@v1.50.0 - name: Run tests if: ${{ needs.filter.outputs.changes == 'true' }} id: run-tests env: OUTPUT_FILE: ./output.txt - USE_TEE: false CL_DATABASE_URL: ${{ env.DB_URL }} run: ./tools/bin/${{ matrix.type.cmd }} ./... - - name: Print Filtered Test Results - if: ${{ failure() && needs.filter.outputs.changes == 'true' && steps.run-tests.conclusion == 'failure' }} - run: | - if [[ "${{ matrix.type.printResults }}" == "true" ]]; then - cat output.txt | gotestloghelper -ci - fi - name: Print Races id: print-races if: ${{ failure() && matrix.type.cmd == 'go_core_race_tests' && needs.filter.outputs.changes == 'true' }} @@ -243,94 +233,6 @@ jobs: echo "path_output=${resultsFile}" >> $GITHUB_OUTPUT fi - detect-flakey-tests: - needs: [filter, core] - name: Flakey Test Detection - runs-on: ubuntu-latest - if: ${{ always() && github.actor != 'dependabot[bot]' }} - env: - CL_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/chainlink_test?sslmode=disable - permissions: - id-token: write - contents: read - steps: - - name: Checkout the repo - uses: actions/checkout@v4.2.1 - - name: Setup node - if: ${{ needs.filter.outputs.changes == 'true' }} - uses: actions/setup-node@v4.0.4 - - name: Setup NodeJS - if: ${{ needs.filter.outputs.changes == 'true' }} - uses: ./.github/actions/setup-nodejs - with: - prod: "true" - - name: Setup Go - if: ${{ needs.filter.outputs.changes == 'true' }} - uses: ./.github/actions/setup-go - - name: Setup Postgres - if: ${{ needs.filter.outputs.changes == 'true' }} - uses: ./.github/actions/setup-postgres - - name: Touching core/web/assets/index.html - if: ${{ needs.filter.outputs.changes == 'true' }} - run: mkdir -p core/web/assets && touch core/web/assets/index.html - - name: Download Go vendor packages - if: ${{ needs.filter.outputs.changes == 'true' }} - run: go mod download - - name: Replace chainlink-evm deps - if: ${{ needs.filter.outputs.changes == 'true' && inputs.evm-ref != ''}} - shell: bash - run: go get github.com/smartcontractkit/chainlink-integrations/evm/relayer@${{ inputs.evm-ref }} - - name: Build binary - if: ${{ needs.filter.outputs.changes == 'true' }} - run: go build -o chainlink.test . - - name: Setup DB - if: ${{ needs.filter.outputs.changes == 'true' }} - run: ./chainlink.test local db preparetest - - name: Load test outputs - if: ${{ needs.filter.outputs.changes == 'true' }} - uses: actions/download-artifact@v4.1.8 - with: - name: go_core_tests_logs - path: ./artifacts - - name: Delete go_core_tests_logs/coverage.txt - if: ${{ needs.filter.outputs.changes == 'true' }} - shell: bash - run: | - # Need to delete coverage.txt so the disk doesn't fill up - rm -f ./artifacts/go_core_tests_logs/coverage.txt - - name: Build flakey test runner - if: ${{ needs.filter.outputs.changes == 'true' }} - run: go build ./tools/flakeytests/cmd/runner - - name: Re-run tests - if: ${{ needs.filter.outputs.changes == 'true' }} - env: - GRAFANA_INTERNAL_BASIC_AUTH: ${{ secrets.GRAFANA_INTERNAL_BASIC_AUTH }} - GRAFANA_INTERNAL_HOST: ${{ secrets.GRAFANA_INTERNAL_HOST }} - GRAFANA_INTERNAL_TENANT_ID: ${{ secrets.GRAFANA_INTERNAL_TENANT_ID }} - GITHUB_EVENT_PATH: ${{ github.event_path }} - GITHUB_EVENT_NAME: ${{ github.event_name }} - GITHUB_REPO: ${{ github.repository }} - GITHUB_RUN_ID: ${{ github.run_id }} - run: | - ./runner \ - -grafana_auth=$GRAFANA_INTERNAL_BASIC_AUTH \ - -grafana_host=$GRAFANA_INTERNAL_HOST \ - -grafana_org_id=$GRAFANA_INTERNAL_TENANT_ID \ - -gh_sha=$GITHUB_SHA \ - -gh_event_path=$GITHUB_EVENT_PATH \ - -gh_event_name=$GITHUB_EVENT_NAME \ - -gh_run_id=$GITHUB_RUN_ID \ - -gh_repo=$GITHUB_REPO \ - -command=./tools/bin/go_core_tests \ - `ls -R ./artifacts/output.txt` - - name: Store logs artifacts - if: ${{ needs.filter.outputs.changes == 'true' && always() }} - uses: actions/upload-artifact@v4.4.3 - with: - name: flakey_test_runner_logs - path: | - ./output.txt - scan: name: SonarQube Scan needs: [core] diff --git a/GNUmakefile b/GNUmakefile index 4080f87b734..8a55e34d11b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -178,7 +178,7 @@ modgraph: .PHONY: test-short test-short: ## Run 'go test -short' and suppress uninteresting output - go test -short ./... | grep -v "no test files" | grep -v "\(cached\)" + go test -short ./... | grep -v "\[no test files\]" | grep -v "\(cached\)" help: @echo "" diff --git a/core/chains/evm/client/rpc_client_test.go b/core/chains/evm/client/rpc_client_test.go index 662c757ffb3..cbd0fa457a5 100644 --- a/core/chains/evm/client/rpc_client_test.go +++ b/core/chains/evm/client/rpc_client_test.go @@ -8,6 +8,7 @@ import ( "math/big" "net/url" "sync" + "sync/atomic" "testing" "time" @@ -401,7 +402,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) { lggr := logger.Test(t) type rpcServer struct { - Head *evmtypes.Head + Head atomic.Pointer[evmtypes.Head] URL *url.URL } createRPCServer := func() *rpcServer { @@ -409,7 +410,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) { server.URL = testutils.NewWSServer(t, chainId, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { assert.Equal(t, "eth_getBlockByNumber", method) if assert.True(t, params.IsArray()) && assert.Equal(t, "finalized", params.Array()[0].String()) { - head := server.Head + head := server.Head.Load() jsonHead, err := json.Marshal(head) if err != nil { panic(fmt.Errorf("failed to marshal head: %w", err)) @@ -427,7 +428,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) { rpc := client.NewRPCClient(lggr, server.URL, nil, "rpc", 1, chainId, commonclient.Primary, 0, 0, commonclient.QueryTimeout, commonclient.QueryTimeout, "") require.NoError(t, rpc.Dial(ctx)) defer rpc.Close() - server.Head = &evmtypes.Head{Number: 128} + server.Head.Store(&evmtypes.Head{Number: 128}) // updates chain info _, err := rpc.LatestFinalizedBlock(ctx) require.NoError(t, err) @@ -440,7 +441,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) { assert.Equal(t, int64(128), latest.FinalizedBlockNumber) // lower block number does not update highestUserObservations - server.Head = &evmtypes.Head{Number: 127} + server.Head.Store(&evmtypes.Head{Number: 127}) _, err = rpc.LatestFinalizedBlock(ctx) require.NoError(t, err) latest, highestUserObservations = rpc.GetInterceptedChainInfo() @@ -452,7 +453,7 @@ func TestRPCClient_LatestFinalizedBlock(t *testing.T) { assert.Equal(t, int64(127), latest.FinalizedBlockNumber) // health check flg prevents change in highestUserObservations - server.Head = &evmtypes.Head{Number: 256} + server.Head.Store(&evmtypes.Head{Number: 256}) _, err = rpc.LatestFinalizedBlock(commonclient.CtxAddHealthCheckFlag(ctx)) require.NoError(t, err) latest, highestUserObservations = rpc.GetInterceptedChainInfo() diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 4e7f9b05c8a..1f6ee6ede7a 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -32,6 +32,7 @@ import ( // NOTE: To avoid circular dependencies, this package MUST NOT import // anything from "github.com/smartcontractkit/chainlink/v2/core" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" ) const ( @@ -125,19 +126,7 @@ func WaitTimeout(t *testing.T) time.Duration { // Context returns a context with the test's deadline, if available. func Context(tb testing.TB) context.Context { - ctx := context.Background() - var cancel func() - switch t := tb.(type) { - case *testing.T: - if d, ok := t.Deadline(); ok { - ctx, cancel = context.WithDeadline(ctx, d) - } - } - if cancel == nil { - ctx, cancel = context.WithCancel(ctx) - } - tb.Cleanup(cancel) - return ctx + return tests.Context(tb) } // MustParseURL parses the URL or fails the test diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 0a1bb8acdd4..f3586f7309b 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" @@ -50,19 +51,7 @@ const ( // Context returns a context with the test's deadline, if available. func Context(tb testing.TB) context.Context { - ctx := context.Background() - var cancel func() - switch t := tb.(type) { - case *testing.T: - if d, ok := t.Deadline(); ok { - ctx, cancel = context.WithDeadline(ctx, d) - } - } - if cancel == nil { - ctx, cancel = context.WithCancel(ctx) - } - tb.Cleanup(cancel) - return ctx + return tests.Context(tb) } type DeployedEnv struct { diff --git a/integration-tests/deployment/memory/node.go b/integration-tests/deployment/memory/node.go index dc364f69993..d269d815a1f 100644 --- a/integration-tests/deployment/memory/node.go +++ b/integration-tests/deployment/memory/node.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/integration-tests/deployment" @@ -43,19 +44,7 @@ import ( ) func Context(tb testing.TB) context.Context { - ctx := context.Background() - var cancel func() - switch t := tb.(type) { - case *testing.T: - if d, ok := t.Deadline(); ok { - ctx, cancel = context.WithDeadline(ctx, d) - } - } - if cancel == nil { - ctx, cancel = context.WithCancel(ctx) - } - tb.Cleanup(cancel) - return ctx + return tests.Context(tb) } type Node struct { diff --git a/tools/bin/go_core_race_tests b/tools/bin/go_core_race_tests index d0fcb6cae41..552411a97be 100755 --- a/tools/bin/go_core_race_tests +++ b/tools/bin/go_core_race_tests @@ -1,22 +1,10 @@ #!/usr/bin/env bash set -ex OUTPUT_FILE=${OUTPUT_FILE:-"./output.txt"} -USE_TEE="${USE_TEE:-true}" TIMEOUT="${TIMEOUT:-30s}" COUNT="${COUNT:-10}" -# To allow reuse in CI from other repositories -TOOLS_PATH=${TOOLS_PATH:-"./tools"} - -GO_LDFLAGS=$(bash ${TOOLS_PATH}/bin/ldflags) -use_tee() { - if [ "$USE_TEE" = "true" ]; then - tee "$@" - else - cat > "$@" - fi -} -GORACE="log_path=$PWD/race" go test -json -race -ldflags "$GO_LDFLAGS" -shuffle on -timeout "$TIMEOUT" -count "$COUNT" $1 | use_tee "$OUTPUT_FILE" +GORACE="log_path=$PWD/race" go test -race -shuffle on -timeout "$TIMEOUT" -count "$COUNT" $1 | cat > "$OUTPUT_FILE" EXITCODE=${PIPESTATUS[0]} # Fail if any race logs are present. if ls race.* &>/dev/null diff --git a/tools/bin/go_core_tests b/tools/bin/go_core_tests index f7c1dfaf231..7580cc6ad56 100755 --- a/tools/bin/go_core_tests +++ b/tools/bin/go_core_tests @@ -4,22 +4,11 @@ set +e SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"` OUTPUT_FILE=${OUTPUT_FILE:-"./output.txt"} -USE_TEE="${USE_TEE:-true}" - -# To allow reuse in CI from other repositories -TOOLS_PATH=${TOOLS_PATH:-"./tools"} echo "Failed tests and panics: ---------------------" echo "" -GO_LDFLAGS=$(bash ${TOOLS_PATH}/bin/ldflags) -use_tee() { - if [ "$USE_TEE" = "true" ]; then - tee "$@" - else - cat > "$@" - fi -} -go test -json -ldflags "$GO_LDFLAGS" -tags integration $TEST_FLAGS -covermode=atomic -coverpkg=./... -coverprofile=coverage.txt $1 | use_tee $OUTPUT_FILE + +go test $TEST_FLAGS $1 | grep -v "\[no test files\]" | tee $OUTPUT_FILE EXITCODE=${PIPESTATUS[0]} # Assert no known sensitive strings present in test logger output