diff --git a/.github/workflows/framework-dockercompose-tests.yml b/.github/workflows/framework-dockercompose-tests.yml new file mode 100644 index 000000000..a9dbec656 --- /dev/null +++ b/.github/workflows/framework-dockercompose-tests.yml @@ -0,0 +1,84 @@ +name: Framework Docker Compose Tests +on: + push: + +jobs: + test: + defaults: + run: + working-directory: framework/examples/myproject + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + strategy: + fail-fast: false + matrix: + test: + - name: TestChipIngressSmoke + config: smoke_chip.toml + count: 1 + timeout: 3m + name: ${{ matrix.test.name }} + steps: + - name: Checkout repo + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + + - name: Configure AWS credentials using OIDC + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_CTF_READ_ACCESS_ROLE_ARN }} + aws-region: us-west-2 + + - name: Login to Amazon ECR + id: login-ecr-private + uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 + with: + registries: ${{ format('{0},{1}', secrets.AWS_ACCOUNT_ID_SDLC, secrets.AWS_ACCOUNT_ID_PROD) }} + env: + AWS_REGION: us-west-2 + + - name: Check for changes in Docker Components + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: changes + with: + filters: | + src: + - 'framework/components/dockercompose/**' + - '.github/workflows/framework-components-tests.yml' + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.24.0' + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: go-modules-${{ hashFiles('framework/examples/myproject/go.sum') }}-${{ runner.os }}-framework-golden-examples + restore-keys: | + go-modules-${{ runner.os }}-framework-golden-examples + go-modules-${{ runner.os }} + + - name: Install dependencies + run: go mod download + + - name: Run System Tests + if: steps.changes.outputs.src == 'true' + env: + CTF_CONFIGS: ${{ matrix.test.config }} + CHIP_INGRESS_IMAGE: ${{ secrets.AWS_ACCOUNT_ID_PROD }}.dkr.ecr.us-west-2.amazonaws.com/atlas-chip-ingress:qa-latest + CTF_LOG_LEVEL: debug + run: | + go test -timeout ${{ matrix.test.timeout }} -v -count ${{ matrix.test.count }} -run ${{ matrix.test.name }} + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: container-logs-${{ matrix.test.name }} + path: framework/examples/myproject/logs + retention-days: 1 diff --git a/framework/components/dockercompose/.changeset/v0.1.12.md b/framework/components/dockercompose/.changeset/v0.1.12.md new file mode 100644 index 000000000..3a326f754 --- /dev/null +++ b/framework/components/dockercompose/.changeset/v0.1.12.md @@ -0,0 +1,3 @@ +- Revert topological sorting of proto dependencies for the local-cre +- Revert support for exclude files to proto registration config +- Add retry on proto registration \ No newline at end of file diff --git a/framework/components/dockercompose/chip_ingress_set/chip_ingress.go b/framework/components/dockercompose/chip_ingress_set/chip_ingress.go index 29d2ba3c2..e54dcfcbb 100644 --- a/framework/components/dockercompose/chip_ingress_set/chip_ingress.go +++ b/framework/components/dockercompose/chip_ingress_set/chip_ingress.go @@ -128,6 +128,7 @@ func New(in *Input) (*Output, error) { wait.NewHostPortStrategy(DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT).WithPollInterval(100*time.Millisecond), wait.NewHostPortStrategy(DEFAULT_RED_PANDA_KAFKA_PORT).WithPollInterval(100*time.Millisecond), wait.ForHTTP("/v1/status/ready").WithPort("9644"), // admin API port + wait.ForHTTP("/status/ready").WithPort(DEFAULT_RED_PANDA_SCHEMA_REGISTRY_PORT).WithPollInterval(100*time.Millisecond), ).WithDeadline(2*time.Minute), ).WaitForService(DEFAULT_RED_PANDA_CONSOLE_SERVICE_NAME, wait.ForAll( diff --git a/framework/components/dockercompose/chip_ingress_set/protos.go b/framework/components/dockercompose/chip_ingress_set/protos.go index d7b367b6c..3723138b7 100644 --- a/framework/components/dockercompose/chip_ingress_set/protos.go +++ b/framework/components/dockercompose/chip_ingress_set/protos.go @@ -11,7 +11,9 @@ import ( "path/filepath" "regexp" "strings" + "time" + "github.com/avast/retry-go/v4" "github.com/google/go-github/v72/github" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-testing-framework/framework" @@ -510,20 +512,33 @@ func registerSingleProto( } url := fmt.Sprintf("%s/subjects/%s/versions", registryURL, subject) + maxAttempts := uint(10) - resp, respErr := http.Post(url, "application/vnd.schemaregistry.v1+json", bytes.NewReader(payload)) - if respErr != nil { - return 0, errors.Wrap(respErr, "failed to post to schema registry") - } - defer resp.Body.Close() + var resp *http.Response + retry.Do(func() error { + var respErr error + resp, respErr = http.Post(url, "application/vnd.schemaregistry.v1+json", bytes.NewReader(payload)) + if respErr != nil { + return errors.Wrap(respErr, "failed to post to schema registry") + } - if resp.StatusCode >= 300 { - data, dataErr := io.ReadAll(resp.Body) - if dataErr != nil { - return 0, errors.Wrap(dataErr, "failed to read response body") + if resp.StatusCode >= 300 { + data, dataErr := io.ReadAll(resp.Body) + if dataErr != nil { + return errors.Wrap(dataErr, "failed to read response body") + } + return fmt.Errorf("schema registry error (%d): %s", resp.StatusCode, data) } - return 0, fmt.Errorf("schema registry error (%d): %s", resp.StatusCode, data) - } + + return nil + }, retry.Attempts(maxAttempts), retry.Delay(100*time.Millisecond), retry.DelayType(retry.BackOffDelay), retry.OnRetry(func(n uint, err error) { + framework.L.Debug().Str("attempt/max", fmt.Sprintf("%d/%d", n, maxAttempts)).Msgf("Retrying to register schema %s: %v", subject, err) + }), retry.RetryIf(func(err error) bool { + // we don't want to retry all errors, because some of them are are expected (e.g. missing dependencies) + // and will be handled by higher-level code + return strings.Contains(err.Error(), "connection reset by peer") + })) + defer resp.Body.Close() var result struct { ID int `json:"id"` diff --git a/framework/components/dockercompose/go.mod b/framework/components/dockercompose/go.mod index 95c1cdc68..0f727901c 100644 --- a/framework/components/dockercompose/go.mod +++ b/framework/components/dockercompose/go.mod @@ -5,6 +5,7 @@ go 1.24.2 replace github.com/smartcontractkit/chainlink-testing-framework/framework => ../../../framework require ( + github.com/avast/retry-go/v4 v4.6.1 github.com/confluentinc/confluent-kafka-go v1.9.2 github.com/docker/docker v28.0.4+incompatible github.com/google/go-github/v72 v72.0.0 diff --git a/framework/components/dockercompose/go.sum b/framework/components/dockercompose/go.sum index fdb418525..6b714d92d 100644 --- a/framework/components/dockercompose/go.sum +++ b/framework/components/dockercompose/go.sum @@ -40,6 +40,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= +github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= github.com/aws/aws-sdk-go-v2/config v1.27.39 h1:FCylu78eTGzW1ynHcongXK9YHtoXD5AiiUqq3YfJYjU= diff --git a/framework/examples/myproject/smoke_chip_ingress_test.go b/framework/examples/myproject/smoke_chip_ingress_test.go index cd6288599..c71883f94 100644 --- a/framework/examples/myproject/smoke_chip_ingress_test.go +++ b/framework/examples/myproject/smoke_chip_ingress_test.go @@ -2,7 +2,6 @@ package examples import ( "context" - "os" "testing" "time" @@ -17,8 +16,6 @@ type ChipConfig struct { // use config file: smoke_chip.toml func TestChipIngressSmoke(t *testing.T) { - t.Skip("skipping smoke test until we have a way to fetch Chip Ingress image") - os.Setenv("CTF_CONFIGS", "smoke_chip.toml") in, err := framework.Load[ChipConfig](t) require.NoError(t, err, "failed to load config")