diff --git a/.github/workflows/framework-golden-tests.yml b/.github/workflows/framework-golden-tests.yml index 32070633e..ce1f114fd 100644 --- a/.github/workflows/framework-golden-tests.yml +++ b/.github/workflows/framework-golden-tests.yml @@ -1,9 +1,6 @@ name: Framework Golden Tests Examples on: push: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }}-framework-golden-examples - cancel-in-progress: true jobs: test: @@ -18,6 +15,7 @@ jobs: id-token: write contents: read strategy: + fail-fast: false matrix: test: - name: TestSmoke @@ -32,6 +30,10 @@ jobs: config: chaos.toml count: 1 timeout: 10m + - name: TestReload + config: reload.toml + count: 1 + timeout: 10m steps: - name: Checkout repo uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 @@ -62,9 +64,10 @@ jobs: path: | ~/.cache/go-build ~/go/pkg/mod - key: go-modules-${{ hashFiles('**/go.sum') }}-${{ runner.os }}-framework-golden-examples + key: go-modules-${{ hashFiles('framework/examples/myproject/go.sum') }}-${{ runner.os }}-framework-golden-examples restore-keys: | - go-modules-${{ hashFiles('**/go.sum') }}-${{ runner.os }}-framework-golden-examples + go-modules-${{ runner.os }}-framework-golden-examples + go-modules-${{ runner.os }} - name: Install dependencies run: go mod download - name: Run Docker Component Tests diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index e4f1931fd..430f6b351 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -14,8 +14,10 @@ - [CLI](./framework/cli.md) - [Configuration](./framework/configuration.md) - [Test Configuration](./framework/test_configuration_overrides.md) - - [Caching](framework/components/caching.md) + - [Components Persistence](framework/components/state.md) + - [Components Caching](framework/components/caching.md) - [Secrets]() + - [Docker](framework/docker.md) - [Observability Stack](framework/observability/observability_stack.md) - [Metrics](framework/observability/metrics.md) - [Logs](framework/observability/logs.md) diff --git a/book/src/ci/ci.md b/book/src/ci/ci.md index 98c2a2333..b78499159 100644 --- a/book/src/ci/ci.md +++ b/book/src/ci/ci.md @@ -2,8 +2,6 @@ Here we describe our good practices for structuring different types of tests in Continuous Integration (GitHub Actions). -The simplest flow can look like: - Set up secrets in your GitHub repository ``` gh secret set CTF_SIMULATED_KEY_1 --body "..." @@ -11,22 +9,58 @@ gh secret set CTF_SIMULATED_KEY_1 --body "..." Add a workflow ```yaml -name: Run E2E tests - +name: Framework Golden Tests Examples on: push: jobs: test: - runs-on: ubuntu-latest + defaults: + run: + working-directory: framework/examples/myproject env: - CTF_CONFIGS: smoke.toml - CTF_LOG_LEVEL: info - CTF_LOKI_STREAM: "false" - PRIVATE_KEY: ${{ secrets.CTF_SIMULATED_KEY_1 }} + LOKI_TENANT_ID: promtail + LOKI_URL: http://localhost:3030/loki/api/v1/push + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + strategy: + fail-fast: false + matrix: + test: + - name: TestSmoke + config: smoke.toml + count: 1 + timeout: 10m + - name: TestLoad + config: load.toml + count: 1 + timeout: 10m + - name: TestChaos + config: chaos.toml + count: 1 + timeout: 10m steps: - - name: Check out code - uses: actions/checkout@v3 + - 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.PUBLIC_AWS_ECR_ROLE }} + aws-region: us-east-1 + - name: Authenticate to ECR Public + id: login-ecr-public + uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 + with: + registry-type: public + - name: Check for changes in Framework + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: changes + with: + filters: | + src: + - 'framework/**' - name: Set up Go uses: actions/setup-go@v4 with: @@ -37,14 +71,18 @@ jobs: path: | ~/.cache/go-build ~/go/pkg/mod - key: go-modules-${{ hashFiles('**/go.sum') }}-${{ runner.os }} + key: go-modules-${{ hashFiles('framework/examples/myproject/go.sum') }}-${{ runner.os }}-framework-golden-examples restore-keys: | - go-modules-${{ hashFiles('**/go.sum') }}-${{ runner.os }} + go-modules-${{ runner.os }}-framework-golden-examples + go-modules-${{ runner.os }} - name: Install dependencies run: go mod download - - name: Run tests - working-directory: e2e/capabilities - run: go test -v -run TestDON + - name: Run Docker Component Tests + if: steps.changes.outputs.src == 'true' + env: + CTF_CONFIGS: ${{ matrix.test.config }} + run: | + go test -timeout ${{ matrix.test.timeout }} -v -count ${{ matrix.test.count }} -run ${{ matrix.test.name }} ``` If you need to structure a lot of different end-to-end tests follow [this](https://github.com/smartcontractkit/.github/tree/main/.github/workflows) guide. \ No newline at end of file diff --git a/book/src/framework/components/caching.md b/book/src/framework/components/caching.md index 4700a68fc..c6900be1f 100644 --- a/book/src/framework/components/caching.md +++ b/book/src/framework/components/caching.md @@ -1,6 +1,6 @@ ## Component caching -We use component caching to accelerate test development and enforce idempotent test actions. +We use component caching to accelerate test development and enforce idempotent test actions development. Each component is isolated by means of inputs and outputs. diff --git a/book/src/framework/components/chainlink/nodeset.md b/book/src/framework/components/chainlink/nodeset.md index 2696b1ac0..19d523747 100644 --- a/book/src/framework/components/chainlink/nodeset.md +++ b/book/src/framework/components/chainlink/nodeset.md @@ -48,6 +48,11 @@ Then configure NodeSet # defines how we override configs, either we apply first node fields to all of them # or we define each node custom configuration (used in compatibility testing) override_mode = "all" + # HTTP API port range start, each new node get port incremented (host machine) + http_port_range_start = 10000 + # P2P API port range start, each new node get port incremented (host machine) + p2p_port_range_start = 12000 + [[nodeset.node_specs]] # Optional URL for fake data provider URL @@ -59,6 +64,8 @@ Then configure NodeSet image = "postgres:15.6" # Pulls the image every time if set to 'true', used like that in CI. Can be set to 'false' to speed up local runs pull_image = true + # PostgreSQL volume name + volume_name = "" [nodeset.node_specs.node] # A list of paths to capability binaries diff --git a/book/src/framework/components/databases/pg.md b/book/src/framework/components/databases/pg.md new file mode 100644 index 000000000..9892a29dc --- /dev/null +++ b/book/src/framework/components/databases/pg.md @@ -0,0 +1 @@ +# PostgreSQL \ No newline at end of file diff --git a/book/src/framework/components/state.md b/book/src/framework/components/state.md new file mode 100644 index 000000000..1a42412f8 --- /dev/null +++ b/book/src/framework/components/state.md @@ -0,0 +1,37 @@ +# Components Persistence + +We use static port ranges and volumes for all components to simplify Docker port management for developers. + +This approach allows us to apply chaos testing to any container, ensuring it reconnects and retains the data needed for your tests. + +When deploying a component, you can explicitly configure port ranges if the default ports don’t meet your needs. + +Defaults are: +- [NodeSet](../components/chainlink/nodeset.md) (Node HTTP API): `10000..100XX` +- [NodeSet](../components/chainlink/nodeset.md) (Node P2P API): `12000..120XX` +``` +[nodeset] + # HTTP API port range start, each new node get port incremented (host machine) + http_port_range_start = 10000 + # P2P API port range start, each new node get port incremented (host machine) + p2p_port_range_start = 12000 +``` +- [PostgreSQL](../components/chainlink/nodeset.md): `13000` (we do not allow to have multiple databases for now, for simplicity) +``` + [nodeset.node_specs.db] + # PostgreSQL volume name + volume_name = "a" + # PostgreSQL port (host machine) + port = 13000 +``` + +When you run `ctf d rm` database volume will be **removed**. + +
+ +One node set is enough for any kind of testing, if you need more nodes consider extending your existing node set: +``` +[nodeset] + nodes = 10 +``` +
diff --git a/book/src/framework/docker.md b/book/src/framework/docker.md new file mode 100644 index 000000000..c102010cb --- /dev/null +++ b/book/src/framework/docker.md @@ -0,0 +1,7 @@ +# Docker + +We are not removing volumes and images when you are working locally to allow you to debug, however, to clean up some space use: +``` +docker volume prune -f +docker system prune -f +``` diff --git a/book/src/framework/first_test.md b/book/src/framework/first_test.md index d651ac172..f30c3155b 100644 --- a/book/src/framework/first_test.md +++ b/book/src/framework/first_test.md @@ -55,6 +55,6 @@ Summary: - We defined configuration for `BlockchainNetwork` - We've used one CTF component in test and checked if it's working -You can learn more about [component design](./components/overview.md) or proceed with another example of [connecting Chainlink node](./connecting_chainlink_node.md) +Now let's connect the [Chainlink](./connecting_chainlink_node.md) node! Learn more about [anvil](./components/blockchains/anvil.md) component. \ No newline at end of file diff --git a/book/src/framework/nodeset_environment.md b/book/src/framework/nodeset_environment.md index ce0588d57..d6eca5c21 100644 --- a/book/src/framework/nodeset_environment.md +++ b/book/src/framework/nodeset_environment.md @@ -72,13 +72,9 @@ Run it CTF_CONFIGS=smoke.toml go test -v -run TestNodeSet ``` -You'll see something like, use any URL to access CL node +Check the logs to access the UI ```bash -6:14PM INF Chainlink node url URL=http://127.0.0.1:34041 -6:14PM INF Chainlink node url URL=http://127.0.0.1:34045 -6:14PM INF Chainlink node url URL=http://127.0.0.1:34044 -6:14PM INF Chainlink node url URL=http://127.0.0.1:34042 -6:14PM INF Chainlink node url URL=http://127.0.0.1:34043 +12:41AM INF UI=["http://127.0.0.1:10000","http://127.0.0.1:10001", ...] ``` Use credentials to authorize: diff --git a/framework/.changeset/v0.1.11.md b/framework/.changeset/v0.1.11.md new file mode 100644 index 000000000..714889248 --- /dev/null +++ b/framework/.changeset/v0.1.11.md @@ -0,0 +1,3 @@ +- Static port ranges for easy chaos testing +- SharedDBNodeSet config update method +- Example of rebooting nodes to apply configuration \ No newline at end of file diff --git a/framework/chaos/chaos.go b/framework/chaos/chaos.go index b18637b04..56ec1b7a7 100644 --- a/framework/chaos/chaos.go +++ b/framework/chaos/chaos.go @@ -9,9 +9,13 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/testcontainers/testcontainers-go" "strings" + "time" ) -func ExecPumba(command string) (func(), error) { +// ExecPumba executes Pumba (https://github.com/alexei-led/pumba) command +// since handling various docker race conditions is hard and there is no easy API for that +// for now you can provide time to wait until chaos is applied +func ExecPumba(command string, wait time.Duration) (func(), error) { ctx := context.Background() cmd := strings.Split(command, " ") pumbaReq := testcontainers.ContainerRequest{ @@ -38,7 +42,9 @@ func ExecPumba(command string) (func(), error) { if err != nil { return nil, fmt.Errorf("failed to start pumba chaos container: %w", err) } - framework.L.Info().Msg("Pumba chaos started") + framework.L.Info().Str("Cmd", command).Msg("Pumba chaos has started") + time.Sleep(wait) + framework.L.Info().Msg("Pumba chaos has finished") return func() { _ = pumbaContainer.Terminate(ctx) }, nil diff --git a/framework/cmd/blockscout.go b/framework/cmd/blockscout.go index ef77f2749..20385bc34 100644 --- a/framework/cmd/blockscout.go +++ b/framework/cmd/blockscout.go @@ -18,7 +18,6 @@ func blockscoutUp() error { if err != nil { return err } - framework.L.Info().Msg("Done") fmt.Println() framework.L.Info().Msgf("Blockscout is up at: %s", "http://localhost") return nil @@ -40,6 +39,5 @@ func blockscoutDown() error { rm -rf redis-data && \ rm -rf stats-db-data `, filepath.Join("blockscout", "services"))) - framework.L.Info().Msg("Done") return nil } diff --git a/framework/cmd/docker.go b/framework/cmd/docker.go index 181ea8c88..bf503f6e8 100644 --- a/framework/cmd/docker.go +++ b/framework/cmd/docker.go @@ -14,7 +14,8 @@ func cleanDockerResources() error { // Bash command for removing Docker containers and networks with "framework=ctf" label cmd := exec.Command("bash", "-c", ` docker ps -aq --filter "label=framework=ctf" | xargs -r docker rm -f && \ - docker network ls --filter "label=framework=ctf" -q | xargs -r docker network rm + docker network ls --filter "label=framework=ctf" -q | xargs -r docker network rm && \ + docker volume rm postgresql_data `) framework.L.Debug().Msg("Running command") if framework.L.GetLevel() == zerolog.DebugLevel { @@ -24,7 +25,6 @@ func cleanDockerResources() error { if err != nil { return fmt.Errorf("error running clean command: %s", string(output)) } - framework.L.Info().Msgf("Done") return nil } diff --git a/framework/cmd/interactive.go b/framework/cmd/interactive.go index ff907cec7..61ae06a8b 100644 --- a/framework/cmd/interactive.go +++ b/framework/cmd/interactive.go @@ -131,14 +131,14 @@ Docker Desktop (https://www.docker.com/products/docker-desktop/) Options( huh.NewOption("Anvil", "anvil"), ). - Value(&f.Network), // stores the selected network + Value(&f.Network), huh.NewSelect[int](). Title("How many nodes do you need?"). Options( huh.NewOption("5", 5), ). - Value(&f.Nodes), // stores the selected number of nodes + Value(&f.Nodes), huh.NewSelect[string](). Title("Choose Chainlink node version"). @@ -147,11 +147,11 @@ Docker Desktop (https://www.docker.com/products/docker-desktop/) Value(&f.CLVersion), huh.NewConfirm(). Title("Do you need to spin up an observability stack?"). - Value(&f.Observability), // stores the observability option + Value(&f.Observability), huh.NewConfirm(). Title("Do you need to spin up a Blockscout stack?"). - Value(&f.Blockscout), // stores the Blockscout option + Value(&f.Blockscout), ), ) @@ -167,13 +167,12 @@ Docker Desktop (https://www.docker.com/products/docker-desktop/) signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) go func() { <-sigs - fmt.Println("\nReceived Ctrl+C, starting custom cleanup...") err := cleanup(f) if err != nil { panic(err) } os.Exit(0) }() - framework.L.Info().Msg("Press Ctrl+C to remove the stack..") + framework.L.Info().Msg("Services are up! Press Ctrl+C to remove them..") select {} } diff --git a/framework/cmd/observability.go b/framework/cmd/observability.go index 039851b76..7a42dc666 100644 --- a/framework/cmd/observability.go +++ b/framework/cmd/observability.go @@ -17,11 +17,8 @@ func observabilityUp() error { if err != nil { return err } - framework.L.Info().Msg("Done") fmt.Println() framework.L.Info().Msgf("Loki: %s", LocalLogsURL) - framework.L.Info().Msgf("All logs: %s", "{job=\"ctf\"}") - framework.L.Info().Msgf("By log level: %s", "{job=\"ctf\", container=~\"node.*\"} |= \"WARN|INFO|DEBUG\"") framework.L.Info().Msgf("Pyroscope: %s", LocalPyroScopeURL) return nil } @@ -35,6 +32,5 @@ func observabilityDown() error { if err != nil { return err } - framework.L.Info().Msg("Done") return nil } diff --git a/framework/components/clnode/clnode.go b/framework/components/clnode/clnode.go index 9131828a4..cdd69f759 100644 --- a/framework/components/clnode/clnode.go +++ b/framework/components/clnode/clnode.go @@ -263,24 +263,6 @@ func newNode(in *Input, pgOut *postgres.Output) (*NodeOut, error) { if err != nil { return nil, err } - //var ( - // mp nat.Port - // mpP2P nat.Port - //) - //if in.Node.HTTPPort != 0 && in.Node.P2PPort != 0 { - // mp = nat.Port(fmt.Sprintf("%d/tcp", in.Node.HTTPPort)) - // mpP2P = nat.Port(fmt.Sprintf("%d/udp", in.Node.P2PPort)) - //} - //else { - // mp, err = c.MappedPort(ctx, nat.Port(httpPort)) - // if err != nil { - // return nil, err - // } - // mpP2P, err = c.MappedPort(ctx, nat.Port(p2pPort)) - // if err != nil { - // return nil, err - // } - //} mp := nat.Port(fmt.Sprintf("%d/tcp", in.Node.HTTPPort)) mpP2P := nat.Port(fmt.Sprintf("%d/udp", in.Node.P2PPort)) diff --git a/framework/components/clnode/clnode_test.go b/framework/components/clnode/clnode_test.go index 3c35ac688..d2fac58e4 100644 --- a/framework/components/clnode/clnode_test.go +++ b/framework/components/clnode/clnode_test.go @@ -33,7 +33,9 @@ func TestDockerNodeWithSharedDB(t *testing.T) { input: &clnode.Input{ DataProviderURL: "http://example.com", DbInput: &postgres.Input{ - Image: "postgres:15.6", + Image: "postgres:15.6", + Port: 16000, + VolumeName: "a", }, Node: &clnode.NodeInput{ Image: "public.ecr.aws/chainlink/chainlink:v2.17.0", @@ -67,7 +69,9 @@ func TestDockerNodeWithDB(t *testing.T) { input: &clnode.Input{ DataProviderURL: "http://example.com", DbInput: &postgres.Input{ - Image: "postgres:15.6", + Image: "postgres:15.6", + Port: 15000, + VolumeName: "b", }, Node: &clnode.NodeInput{ Image: "public.ecr.aws/chainlink/chainlink:v2.17.0", diff --git a/framework/components/postgres/postgres.go b/framework/components/postgres/postgres.go index 33670d8dc..9b5fb957e 100644 --- a/framework/components/postgres/postgres.go +++ b/framework/components/postgres/postgres.go @@ -3,6 +3,7 @@ package postgres import ( "context" "fmt" + "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/testcontainers/testcontainers-go" @@ -13,17 +14,21 @@ import ( ) const ( - User = "chainlink" - Password = "thispasswordislongenough" - Port = "5432" - Database = "chainlink" - Databases = 5 + User = "chainlink" + Password = "thispasswordislongenough" + Port = "5432" + ExposedStaticPort = 13000 + Database = "chainlink" + DBVolumeName = "postgresql_data" ) type Input struct { - Image string `toml:"image" validate:"required"` - PullImage bool `toml:"pull_image"` - Out *Output `toml:"out"` + Image string `toml:"image" validate:"required"` + Port int `toml:"port"` + VolumeName string `toml:"volume_name"` + Databases int `toml:"databases"` + PullImage bool `toml:"pull_image"` + Out *Output `toml:"out"` } type Output struct { @@ -35,11 +40,10 @@ func NewPostgreSQL(in *Input) (*Output, error) { ctx := context.Background() bindPort := fmt.Sprintf("%s/tcp", Port) - containerName := framework.DefaultTCName("postgresql") var sqlCommands []string - for i := 0; i <= Databases; i++ { + for i := 0; i <= in.Databases; i++ { sqlCommands = append(sqlCommands, fmt.Sprintf("CREATE DATABASE db_%d;", i)) } sqlCommands = append(sqlCommands, "ALTER USER chainlink WITH SUPERUSER;") @@ -80,13 +84,39 @@ func NewPostgreSQL(in *Input) (*Output, error) { FileMode: 0644, }, }, + Mounts: testcontainers.ContainerMounts{ + { + Source: testcontainers.GenericVolumeMountSource{ + Name: fmt.Sprintf("%s%s", DBVolumeName, in.VolumeName), + }, + Target: "/var/lib/postgresql/data", + }, + }, WaitingFor: tcwait.ForExec([]string{"psql", "-h", "127.0.0.1", "-U", User, "-p", Port, "-c", "select", "1", "-d", Database}). - WithStartupTimeout(20 * time.Second), + WithStartupTimeout(20 * time.Second). + WithPollInterval(1 * time.Second), + } + var portToExpose int + if in.Port != 0 { + portToExpose = in.Port + } else { + portToExpose = ExposedStaticPort + } + req.HostConfigModifier = func(h *container.HostConfig) { + h.PortBindings = nat.PortMap{ + nat.Port(bindPort): []nat.PortBinding{ + { + HostIP: "0.0.0.0", + HostPort: fmt.Sprintf("%d/tcp", portToExpose), + }, + }, + } } c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, + Reuse: true, }) if err != nil { return nil, err @@ -95,10 +125,6 @@ func NewPostgreSQL(in *Input) (*Output, error) { if err != nil { return nil, err } - mp, err := c.MappedPort(ctx, nat.Port(bindPort)) - if err != nil { - return nil, err - } return &Output{ DockerInternalURL: fmt.Sprintf( "postgresql://%s:%s@%s:%s/%s?sslmode=disable", @@ -109,11 +135,11 @@ func NewPostgreSQL(in *Input) (*Output, error) { Database, ), Url: fmt.Sprintf( - "postgresql://%s:%s@%s:%s/%s?sslmode=disable", + "postgresql://%s:%s@%s:%d/%s?sslmode=disable", User, Password, host, - mp.Port(), + portToExpose, Database, ), }, nil diff --git a/framework/components/simple_node_set/node_set.go b/framework/components/simple_node_set/node_set.go index c51b36f0c..1a9d4837b 100644 --- a/framework/components/simple_node_set/node_set.go +++ b/framework/components/simple_node_set/node_set.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/clnode" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/postgres" "golang.org/x/sync/errgroup" + "slices" "strings" "sync" ) @@ -16,20 +17,24 @@ const ( DefaultP2PStaticRangeStart = 12000 ) +// Input is a node set configuration input type Input struct { Nodes int `toml:"nodes" validate:"required"` HTTPPortRangeStart int `toml:"http_port_range_start"` P2PPortRangeStart int `toml:"p2p_port_range_start"` OverrideMode string `toml:"override_mode" validate:"required,oneof=all each"` - NodeSpecs []*clnode.Input `toml:"node_specs"` + NodeSpecs []*clnode.Input `toml:"node_specs" validate:"required"` Out *Output `toml:"out"` } +// Output is a node set configuration output, used for caching or external components type Output struct { UseCache bool `toml:"use_cache"` CLNodes []*clnode.Output `toml:"cl_nodes"` } +// NewSharedDBNodeSet create a new node set with a shared database instance +// all the nodes have their own isolated database func NewSharedDBNodeSet(in *Input, bcOut *blockchain.Output, fakeUrl string) (*Output, error) { if in.Out != nil && in.Out.UseCache { return in.Out, nil @@ -39,6 +44,7 @@ func NewSharedDBNodeSet(in *Input, bcOut *blockchain.Output, fakeUrl string) (*O err error ) defer func() { + printURLs(out) in.Out = out }() if len(in.NodeSpecs) != in.Nodes && in.OverrideMode == "each" { @@ -56,23 +62,34 @@ func NewSharedDBNodeSet(in *Input, bcOut *blockchain.Output, fakeUrl string) (*O return nil, err } } - printOut(out) return out, nil } -func printOut(out *Output) { - for i, n := range out.CLNodes { - framework.L.Info().Str(fmt.Sprintf("Node-%d", i), n.Node.HostURL).Msg("Chainlink node url") +func printURLs(out *Output) { + if out == nil { + return } + httpURLs, p2pURLs, pgURLs := make([]string, 0), make([]string, 0), make([]string, 0) + for _, n := range out.CLNodes { + httpURLs = append(httpURLs, n.Node.HostURL) + p2pURLs = append(p2pURLs, n.Node.HostP2PURL) + pgURLs = append(pgURLs, n.PostgreSQL.Url) + } + framework.L.Info().Any("UI", httpURLs).Send() + framework.L.Debug().Any("P2P", p2pURLs).Send() + framework.L.Debug().Any("DB", pgURLs).Send() } func sharedDBSetup(in *Input, bcOut *blockchain.Output, fakeUrl string, overrideEach bool) (*Output, error) { + in.NodeSpecs[0].DbInput.Databases = in.Nodes dbOut, err := postgres.NewPostgreSQL(in.NodeSpecs[0].DbInput) if err != nil { return nil, err } nodeOuts := make([]*clnode.Output, 0) + // to make it easier for chaos testing we use static ports + // there is no need to check them in advance since testcontainers-go returns a nice error var ( httpPortRangeStart = DefaultHTTPPortStaticRangeStart p2pPortRangeStart = DefaultP2PStaticRangeStart @@ -125,9 +142,10 @@ func sharedDBSetup(in *Input, bcOut *blockchain.Output, fakeUrl string, override }, } + dbURLHost := strings.Replace(dbOut.Url, "/chainlink?sslmode=disable", fmt.Sprintf("/db_%d?sslmode=disable", i), -1) dbURL := strings.Replace(dbOut.DockerInternalURL, "/chainlink?sslmode=disable", fmt.Sprintf("/db_%d?sslmode=disable", i), -1) dbSpec := &postgres.Output{ - Url: dbOut.Url, + Url: dbURLHost, DockerInternalURL: dbURL, } @@ -144,8 +162,21 @@ func sharedDBSetup(in *Input, bcOut *blockchain.Output, fakeUrl string, override if err := eg.Wait(); err != nil { return nil, err } + sortNodeOutsByHostPort(nodeOuts) return &Output{ UseCache: true, CLNodes: nodeOuts, }, nil } + +func sortNodeOutsByHostPort(nodes []*clnode.Output) { + slices.SortFunc[[]*clnode.Output, *clnode.Output](nodes, func(a, b *clnode.Output) int { + aa := strings.Split(a.Node.HostURL, ":") + bb := strings.Split(b.Node.HostURL, ":") + if aa[len(aa)-1] < bb[len(bb)-1] { + return -1 + } else { + return 1 + } + }) +} diff --git a/framework/components/simple_node_set/nodeset_test.go b/framework/components/simple_node_set/nodeset_test.go index f0aa9860b..98d604568 100644 --- a/framework/components/simple_node_set/nodeset_test.go +++ b/framework/components/simple_node_set/nodeset_test.go @@ -87,6 +87,7 @@ func TestDockerNodeSetSharedDB(t *testing.T) { DataProviderURL: "http://example.com", DbInput: &postgres.Input{ Image: "postgres:15.6", + Port: 14000, }, Node: &clnode.NodeInput{ Image: "public.ecr.aws/chainlink/chainlink:v2.17.0", diff --git a/framework/components/simple_node_set/reload.go b/framework/components/simple_node_set/reload.go new file mode 100644 index 000000000..9180defa5 --- /dev/null +++ b/framework/components/simple_node_set/reload.go @@ -0,0 +1,8 @@ +package simple_node_set + +// UpdateNodeConfigs updates nodes configuration TOML files +// this API is discouraged, however, you can use it if nodes require restart or configuration updates, temporarily! +func UpdateNodeConfigs(in *Input, cfg string) { + in.NodeSpecs[0].Node.UserConfigOverrides = in.NodeSpecs[0].Node.UserConfigOverrides + cfg + in.Out = nil +} diff --git a/framework/examples/.gitignore b/framework/examples/.gitignore index 8184ab7cb..ea2f8193b 100644 --- a/framework/examples/.gitignore +++ b/framework/examples/.gitignore @@ -33,3 +33,5 @@ promtail-config.yml **/blockscout **/blockscout/* **/*cache.toml +**/postgresql_data +**/postgresql_data/* diff --git a/framework/examples/myproject/.envrc b/framework/examples/myproject/.envrc index 2bc67310e..3e3bc940a 100644 --- a/framework/examples/myproject/.envrc +++ b/framework/examples/myproject/.envrc @@ -3,4 +3,5 @@ export PRIVATE_KEY="..." # load test export LOKI_TENANT_ID=promtail export LOKI_URL=http://localhost:3030/loki/api/v1/push -export RESTY_DEBUG=true \ No newline at end of file +#export RESTY_DEBUG=true +export CTF_LOG_LEVEL=debug \ No newline at end of file diff --git a/framework/examples/myproject/chaos_test.go b/framework/examples/myproject/chaos_test.go index 6a3baee42..4c2df3149 100644 --- a/framework/examples/myproject/chaos_test.go +++ b/framework/examples/myproject/chaos_test.go @@ -9,6 +9,7 @@ import ( ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" "github.com/stretchr/testify/require" "testing" + "time" ) type CfgChaos struct { @@ -35,7 +36,7 @@ func TestChaos(t *testing.T) { // example commands for Pumba: // stop --duration=1s --restart re2:node0 # stop one container for 1s and restart // netem --tc-image=gaiadocker/iproute2 --duration=1m delay --time=300 re2:node.* # slow network - _, err = chaos.ExecPumba("stop --duration=1s --restart re2:node0") + _, err = chaos.ExecPumba("stop --duration=1s --restart re2:node0", 1*time.Second) require.NoError(t, err) _, _, err = c[0].ReadBridges() require.NoError(t, err) diff --git a/framework/examples/myproject/go.mod b/framework/examples/myproject/go.mod index f458d7773..6a2d21569 100644 --- a/framework/examples/myproject/go.mod +++ b/framework/examples/myproject/go.mod @@ -9,7 +9,7 @@ replace ( ) require ( - github.com/smartcontractkit/chainlink-testing-framework/framework v0.1.9 + github.com/smartcontractkit/chainlink-testing-framework/framework v0.1.10 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 github.com/stretchr/testify v1.9.0 ) @@ -28,6 +28,7 @@ require ( github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/aws-sdk-go-v2 v1.31.0 // indirect github.com/aws/aws-sdk-go-v2/config v1.27.39 // indirect @@ -43,6 +44,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.3 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 // indirect github.com/aws/smithy-go v1.21.0 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect @@ -50,9 +52,18 @@ require ( github.com/bytedance/sonic/loader v0.2.0 // indirect github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect + github.com/catppuccin/go v0.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/bubbles v0.20.0 // indirect + github.com/charmbracelet/bubbletea v1.1.1 // indirect + github.com/charmbracelet/huh v0.6.0 // indirect + github.com/charmbracelet/huh/spinner v0.0.0-20241028115900-20a4d21717a8 // indirect + github.com/charmbracelet/lipgloss v0.13.0 // indirect + github.com/charmbracelet/x/ansi v0.2.3 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect + github.com/charmbracelet/x/term v0.2.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/coder/websocket v1.8.12 // indirect @@ -62,6 +73,7 @@ require ( github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dennwc/varint v1.0.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -72,6 +84,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/ethereum/go-ethereum v1.14.11 // indirect github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect github.com/fatih/color v1.16.0 // indirect @@ -143,14 +156,18 @@ require ( github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/miekg/dns v1.1.56 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect @@ -161,6 +178,9 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/oklog/ulid v1.3.1 // indirect @@ -170,6 +190,7 @@ require ( github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -183,7 +204,9 @@ require ( github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/zerolog v1.33.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sercand/kuberesolver/v5 v5.1.1 // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect @@ -203,7 +226,9 @@ require ( github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/ugorji/go/codec v1.2.12 // indirect + github.com/urfave/cli/v2 v2.27.5 // indirect github.com/x448/float16 v0.8.4 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.etcd.io/etcd/api/v3 v3.5.7 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.7 // indirect diff --git a/framework/examples/myproject/go.sum b/framework/examples/myproject/go.sum index 70537bae5..a39037ab9 100644 --- a/framework/examples/myproject/go.sum +++ b/framework/examples/myproject/go.sum @@ -105,6 +105,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.45.25 h1:c4fLlh5sLdK2DCRTY1z0hyuJZU4ygxX8m1FswL6/nF4= github.com/aws/aws-sdk-go v1.45.25/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= @@ -136,6 +138,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.31.3 h1:VzudTFrDCIDakXtemR7l6Qzt2+JY github.com/aws/aws-sdk-go-v2/service/sts v1.31.3/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -154,6 +158,8 @@ github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdS github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -162,6 +168,22 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= +github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= +github.com/charmbracelet/bubbletea v1.1.1 h1:KJ2/DnmpfqFtDNVTvYZ6zpPFL9iRCRr0qqKOCvppbPY= +github.com/charmbracelet/bubbletea v1.1.1/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= +github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8= +github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU= +github.com/charmbracelet/huh/spinner v0.0.0-20241028115900-20a4d21717a8 h1:g+Bz64hsMLTf3lAgUqI6Rj1YEAlm/HN39IuhyneCokc= +github.com/charmbracelet/huh/spinner v0.0.0-20241028115900-20a4d21717a8/go.mod h1:Cxhgl8N0sX9A+EQxedzzGZAalaF8fUVL+JP/pSOW8cI= +github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= +github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= +github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= +github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= +github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -189,6 +211,8 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -226,6 +250,8 @@ github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnv github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= @@ -572,6 +598,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= @@ -599,6 +627,10 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -611,6 +643,8 @@ github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFW github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -639,6 +673,12 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= +github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -674,6 +714,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= @@ -728,6 +770,9 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 h1:6ksZ7t1hNOzGPPs8DK7SvXQf6UfWzi+W5Z7PCBl8gx4= github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510/go.mod h1:UC0TwJiF90m2T3iYPQBKnGu8gv3s55dF/EgpTq8gyvo= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -736,6 +781,9 @@ github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20 h1:a9hSJdJcd16e0HoMsnFvaHvxB3pxSD+SC7+CISp7xY0= @@ -811,6 +859,9 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli v1.22.12 h1:igJgVw1JdKH+trcLWLeLwZjU9fEfPesQ+9/e4MQ44S8= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -822,6 +873,8 @@ github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3k github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1051,6 +1104,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/framework/examples/myproject/reload.toml b/framework/examples/myproject/reload.toml new file mode 100644 index 000000000..acbac497d --- /dev/null +++ b/framework/examples/myproject/reload.toml @@ -0,0 +1,23 @@ + +[blockchain_a] + chain_id = "31337" + image = "f4hrenh9it/foundry:latest" + port = "8545" + type = "anvil" + +[data_provider] + port = 9111 + +[nodeset] + nodes = 5 + override_mode = "all" + + [[nodeset.node_specs]] + + [nodeset.node_specs.db] + image = "postgres:15.6" + pull_image = true + + [nodeset.node_specs.node] + image = "public.ecr.aws/chainlink/chainlink:v2.17.0" + pull_image = false diff --git a/framework/examples/myproject/reload_test.go b/framework/examples/myproject/reload_test.go new file mode 100644 index 000000000..9e9732b5c --- /dev/null +++ b/framework/examples/myproject/reload_test.go @@ -0,0 +1,74 @@ +package examples + +import ( + "fmt" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/smartcontractkit/chainlink-testing-framework/framework/chaos" + "github.com/smartcontractkit/chainlink-testing-framework/framework/clclient" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" + ns "github.com/smartcontractkit/chainlink-testing-framework/framework/components/simple_node_set" + "github.com/stretchr/testify/require" + "testing" + "time" +) + +type CfgReload struct { + BlockchainA *blockchain.Input `toml:"blockchain_a" validate:"required"` + MockerDataProvider *fake.Input `toml:"data_provider" validate:"required"` + NodeSet *ns.Input `toml:"nodeset" validate:"required"` +} + +func TestReload(t *testing.T) { + in, err := framework.Load[CfgReload](t) + require.NoError(t, err) + + bc, err := blockchain.NewBlockchainNetwork(in.BlockchainA) + require.NoError(t, err) + dp, err := fake.NewFakeDataProvider(in.MockerDataProvider) + require.NoError(t, err) + + // deploy first time + out, err := ns.NewSharedDBNodeSet(in.NodeSet, bc, dp.BaseURLDocker) + require.NoError(t, err) + + c, err := clclient.NewCLDefaultClients(out.CLNodes, framework.L) + require.NoError(t, err) + _, _, err = c[0].CreateJobRaw(` + type = "cron" + schemaVersion = 1 + schedule = "CRON_TZ=UTC */10 * * * * *" # every 10 secs + observationSource = """ + // data source 2 + fetch [type=http method=GET url="https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD"]; + parse [type=jsonparse path="RAW,ETH,USD,PRICE"]; + multiply [type="multiply" input="$(parse)" times=100] + encode_tx [type="ethabiencode" + abi="submit(uint256 value)" + data="{ \\"value\\": $(multiply) }"] + submit_tx [type="ethtx" to="0x859AAa51961284C94d970B47E82b8771942F1980" data="$(encode_tx)"] + + fetch -> parse -> multiply -> encode_tx -> submit_tx + """`) + require.NoError(t, err) + + // deploy second time + _, err = chaos.ExecPumba("rm --volumes=false re2:node.*|postgresql.*", 5*time.Second) + require.NoError(t, err) + ns.UpdateNodeConfigs(in.NodeSet, ` +[Log] +level = 'info' +`) + out, err = ns.NewSharedDBNodeSet(in.NodeSet, bc, dp.BaseURLDocker) + require.NoError(t, err) + jobs, _, err := c[0].ReadJobs() + require.NoError(t, err) + fmt.Println(jobs) + + t.Run("test something", func(t *testing.T) { + for _, n := range out.CLNodes { + require.NotEmpty(t, n.Node.HostURL) + require.NotEmpty(t, n.Node.HostP2PURL) + } + }) +}