From ff1204ae04a473f65acb4afceccffd536137ce5b Mon Sep 17 00:00:00 2001 From: Damjan Smickovski Date: Tue, 21 May 2024 09:03:07 +0200 Subject: [PATCH] Incorporated feedback --- docs/RunningE2eTests.md | 4 + .../src/commands/middlewares.ts | 6 +- integration-tests/common/common.go | 2 +- integration-tests/smoke/ocr2_test.go | 221 ++++++++++-------- 4 files changed, 130 insertions(+), 103 deletions(-) diff --git a/docs/RunningE2eTests.md b/docs/RunningE2eTests.md index 57ed0b42c..babdf6b94 100644 --- a/docs/RunningE2eTests.md +++ b/docs/RunningE2eTests.md @@ -11,11 +11,15 @@ The main test config logic resides in the `integration-tests/testconfig/` direct There are a few possibile combinations to run tests that we support. **Devnet** +Devnet requires previously deployed programs that are owned by the person running the tests. The program ID's are required for testnet, but ignored in localnet. - `Common.network` needs to be set to `devnet` which will instruct the tests to run against devnet - `ocr2_program_id`, `access_controller_program_id`, `store_program_id`, `link_token_address`, `vault_address` need to be set so the tests know what programs to use so we avoid deploying each time. - `rpc_url` and `ws_url` need to be set +**Localnet** +Setting localnet will instruct the tests to run in localnet, the program ID's are not taken from the TOML in this scenario, but rather defined in the `integration-tests/config/config.go`. + **K8s** Running in Kubernetes will require aws auth. diff --git a/gauntlet/packages/gauntlet-solana/src/commands/middlewares.ts b/gauntlet/packages/gauntlet-solana/src/commands/middlewares.ts index 4da5af9dd..87d5af4ac 100644 --- a/gauntlet/packages/gauntlet-solana/src/commands/middlewares.ts +++ b/gauntlet/packages/gauntlet-solana/src/commands/middlewares.ts @@ -18,8 +18,10 @@ export const withProvider: Middleware = (c: SolanaCommand, next: Next) => { `Invalid NODE_URL (${nodeURL}), please add an http:// or https:// prefix`, ) const wsUrl = process.env.WS_URL - assertions.assert(wsUrl && isValidURL(wsUrl), `Invalid WS_URL (${wsUrl}), please add an ws:// or wss:// prefix`) - c.provider = new AnchorProvider(new Connection(nodeURL, { wsEndpoint: wsUrl }), c.wallet, {}) + if (wsUrl) { + assertions.assert(isValidURL(wsUrl), `Invalid WS_URL (${wsUrl}), please add an ws:// or wss:// prefix`) + } + c.provider = new AnchorProvider(new Connection(nodeURL, wsUrl ? { wsEndpoint: wsUrl } : {}), c.wallet, {}) return next() } diff --git a/integration-tests/common/common.go b/integration-tests/common/common.go index 659ea7a1e..9985b1fe9 100644 --- a/integration-tests/common/common.go +++ b/integration-tests/common/common.go @@ -132,7 +132,7 @@ func New(testConfig *tc.TestConfig) *Common { // Getting the default localnet private key privateKey, err := solana.PrivateKeyFromBase58(solclient.DefaultPrivateKeysSolValidator[1]) if err != nil { - panic("Could not decode private devnet private key") + panic("Could not decode private localnet private key") } privateKeyString := fmt.Sprintf("[%s]", formatBuffer([]byte(privateKey))) publicKey := privateKey.PublicKey().String() diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 89d3ea506..88bb90091 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -2,6 +2,7 @@ package smoke import ( "fmt" + "maps" "testing" "time" @@ -14,114 +15,134 @@ import ( tc "github.com/smartcontractkit/chainlink-solana/integration-tests/testconfig" "github.com/smartcontractkit/chainlink-solana/integration-tests/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) func TestSolanaOCRV2Smoke(t *testing.T) { - config, err := tc.GetConfig("Smoke", tc.OCR2) - if err != nil { - t.Fatal(err) - } + 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("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } - state, err := common.NewOCRv2State(t, 1, "gauntlet", &config) - require.NoError(t, err, "Could not setup the ocrv2 state") - if state.Common.Env.WillUseRemoteRunner() { - // run the remote runner and exit - err := state.Common.Env.Run() - require.NoError(t, err) - return - } - state.DeployCluster(utils.ContractsDir) + test := test + t.Run(test.name, func(t *testing.T) { - sg, err := gauntlet.NewSolanaGauntlet(fmt.Sprintf("%s/gauntlet", utils.ProjectRoot)) - require.NoError(t, err) - state.Gauntlet = sg + state, err := common.NewOCRv2State(t, 1, "gauntlet-"+test.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) + }) + } - 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") + state.DeployCluster(utils.ContractsDir) + + sg, err := gauntlet.NewSolanaGauntlet(fmt.Sprintf("%s/gauntlet", utils.ProjectRoot)) + require.NoError(t, err) + state.Gauntlet = sg + + 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") + } + }) } - }) - } - 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, - } + state.SetupClients() + require.NoError(t, err) - err = sg.SetupNetwork(gauntletConfig) - require.NoError(t, err, "Error setting gauntlet network") - - 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) - } + 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") + + 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.Smoke.NumberOfRounds { + require.Less(t, stuck, 10, "Rounds have been stuck for more than 10 iterations") + log.Info().Str("Transmission", sg.OcrAddress).Msg("Inspecting transmissions") + transmissions, err := sg.FetchTransmissions(sg.OcrAddress) + require.NoError(t, 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.Answer).Msg("New answer found") + 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 + successFullRounds++ + time.Sleep(time.Second * 6) + stuck = 0 + } + }) - 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.Smoke.NumberOfRounds { - require.Less(t, stuck, 10, "Rounds have been stuck for more than 10 iterations") - log.Info().Str("Transmission", sg.OcrAddress).Msg("Inspecting transmissions") - transmissions, err := sg.FetchTransmissions(sg.OcrAddress) - require.NoError(t, 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.Answer).Msg("New answer found") - 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 - successFullRounds++ - time.Sleep(time.Second * 6) - stuck = 0 } }