From 0bb4e93da7afc86e10a6cfeeccecbf63fb5690fa Mon Sep 17 00:00:00 2001 From: Adam Hamrick Date: Wed, 20 Oct 2021 08:54:29 -0400 Subject: [PATCH] Integration CI on this repo (#112) Adds smoke tests to the framework repo's CI --- .github/workflows/lint.yaml | 2 +- .github/workflows/test.yaml | 179 ++++++++++++++++-- README.md | 31 +-- actions/actions.go | 7 +- client/blockchain.go | 4 +- client/client_suite_test.go | 2 +- client/ethereum.go | 22 +-- config/config_suite_test.go | 2 +- environment/environment_test.go | 1 - environment/k8s_environment.go | 5 +- environment/k8s_environment_helm_test.go | 4 +- environment/k8s_environment_test.go | 18 +- environment/k8s_helm_resource.go | 11 +- .../contracts_flux_validate_flag_test.go | 8 +- suite/contracts/contracts_keeper_test.go | 7 + suite/contracts/contracts_test.go | 3 + suite/contracts/contracts_vrf_test.go | 4 + suite/refill/eth_refill_test.go | 26 ++- tools/integration_test.sh | 16 ++ 19 files changed, 287 insertions(+), 65 deletions(-) create mode 100755 tools/integration_test.sh diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 2164347d0..f69b345bb 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,4 +1,4 @@ -name: golangci-lint +name: Linting on: push: tags: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e2ac18e5e..768a51b02 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -1,4 +1,4 @@ -name: test +name: Tests on: push: tags: @@ -8,7 +8,7 @@ on: - main pull_request: jobs: - test: + unit: strategy: matrix: go-version: [1.16.x] @@ -24,26 +24,175 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - name: Install Go + - name: Checkout the Repo + uses: actions/checkout@v2 + - name: Setup Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - - name: Checkout code - uses: actions/checkout@v2 - - name: Test - run: go test ./client ./config ./environment -v -covermode=count -coverprofile=coverage.out - - name: Convert coverage to lcov - uses: jandelgado/gcov2lcov-action@v1.0.5 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-duration-seconds: 3600 + - name: Set Kubernetes Context + uses: azure/k8s-set-context@v1 + with: + method: kubeconfig + kubeconfig: ${{ secrets.KUBECONFIG }} + - name: Cache Vendor Packages + uses: actions/cache@v2 + id: cache-packages + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Download Go Vendor Packages + if: steps.cache-packages.outputs.cache-hit != 'true' + run: go mod download + - name: Install Ginkgo CLI + run: go install github.com/onsi/ginkgo/ginkgo + - name: Run Tests + run: | + export PATH=$PATH:$(go env GOPATH)/bin + ginkgo -r --randomizeAllSpecs --randomizeSuites -keepGoing -covermode=count -coverprofile=unit-test-coverage.out -nodes=10 ./client ./config ./environment + - name: Code Coverage + uses: codecov/codecov-action@v2 + with: + files: ./unit-test-coverage.out + name: codecov-umbrella + - name: Publish Unit Test Results + uses: mikepenz/action-junit-report@v2 if: always() - - name: Report code coverage - uses: romeovs/lcov-reporter-action@v0.2.21 + with: + report_paths: '**/logs/tests-*.xml' + github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Publish Artifacts + if: failure() + uses: actions/upload-artifact@v1 + with: + name: test-logs + path: ./logs + + smoke: + runs-on: ubuntu-latest + needs: unit + env: + CGO_ENABLED: 0 + steps: + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Setup go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-duration-seconds: 3600 + - name: Set Kubernetes Context + uses: azure/k8s-set-context@v1 + with: + method: kubeconfig + kubeconfig: ${{ secrets.KUBECONFIG }} + - name: Cache Vendor Packages + uses: actions/cache@v2 + id: cache-packages + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Download Go Vendor Packages + if: steps.cache-packages.outputs.cache-hit != 'true' + run: go mod download + - name: Install Ginkgo CLI + run: go install github.com/onsi/ginkgo/ginkgo + - name: Run Tests + run: | + export PATH=$PATH:$(go env GOPATH)/bin + ./tools/integration_test.sh 0 + - name: Publish Test Results + uses: mikepenz/action-junit-report@v2 if: always() with: - github-token: ${{ secrets.GITHUB_TOKEN }} - lcov-file: ./coverage.lcov - - name: Publish Unit Test Results + report_paths: '**/logs/tests-*.xml' + github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Publish Artifacts + if: failure() + uses: actions/upload-artifact@v1 + with: + name: test-logs + path: ./logs + + performance: + # Only run performance tests on significant PRs / merges to main + if: startsWith(github.ref, 'v') || contains(github.ref, 'main') || contains(github.ref, 'develop') + needs: unit + runs-on: ubuntu-latest + env: + CGO_ENABLED: 0 + NETWORK: ethereum_geth_performance + steps: + - name: Checkout the repo + uses: actions/checkout@v2 + - name: Setup Go + uses: actions/setup-go@v1 + with: + go-version: 1.16 + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-duration-seconds: 3600 + - name: Set Kubernetes Context + uses: azure/k8s-set-context@v1 + with: + method: kubeconfig + kubeconfig: ${{ secrets.KUBECONFIG }} + - name: Cache Vendor Packages + uses: actions/cache@v2 + id: cache-packages + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: Download Go Vendor Packages + if: steps.cache-packages.outputs.cache-hit != 'true' + run: go mod download + - name: Install Ginkgo CLI + run: go install github.com/onsi/ginkgo/ginkgo + - name: Run Tests + run: | + export PATH=$PATH:$(go env GOPATH)/bin + ./tools/integration_test.sh 1 + - name: Publish Test Results uses: mikepenz/action-junit-report@v2 if: always() with: - report_paths: '**/junit.xml' + report_paths: '**/logs/tests-*.xml' github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Publish Artifacts + if: failure() + uses: actions/upload-artifact@v1 + with: + name: test-logs + path: ./logs \ No newline at end of file diff --git a/README.md b/README.md index f921230f8..5c99e9751 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,10 @@ This framework is still very much a work in progress, and will have frequent cha breaking. ### Setup + Install CLI -``` + +```sh make install_cli ``` @@ -24,20 +26,23 @@ A simple example on deploying and interaction with a simple contract using this ```go var _ = Describe("Basic Contract Interactions", func() { - var suiteSetup *actions.DefaultSuiteSetup - var defaultWallet client.BlockchainWallet + var ( + suiteSetup actions.SuiteSetup + networkInfo actions.NetworkInfo + defaultWallet client.BlockchainWallet + ) BeforeEach(func() { By("Deploying the environment", func() { - confFileLocation, err := filepath.Abs("../") // Get the absolute path of the test suite's root directory - Expect(err).ShouldNot(HaveOccurred()) - suiteSetup, err = actions.DefaultLocalSetup( + var err error + suiteSetup, err = actions.SingleNetworkSetup( environment.NewChainlinkCluster(0), - client.NewNetworkFromConfig, - confFileLocation, // Directory where config.yml is placed + client.DefaultNetworkFromConfig, + tools.ProjectRoot, ) Expect(err).ShouldNot(HaveOccurred()) - defaultWallet = suiteSetup.Wallets.Default() + networkInfo = suiteSetup.DefaultNetwork() + defaultWallet = networkInfo.Wallets.Default() }) }) @@ -110,13 +115,17 @@ NETWORK="ethereum_geth_performance" make test_performance ``` ### Build contracts + Example of generating go bindings for Ethereum contracts -``` + +```sh ifcli build_contracts -c config.yml ``` ### Create environment + Example of creating environment with one Chainlink node and Geth dev network -``` + +```sh ifcli create_env -n ethereum_geth -t chainlink -c 1 ``` diff --git a/actions/actions.go b/actions/actions.go index 701a9912f..6a3eefd16 100644 --- a/actions/actions.go +++ b/actions/actions.go @@ -2,12 +2,13 @@ package actions import ( "encoding/json" + "math/big" + "strings" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" "github.com/smartcontractkit/integrations-framework/client" - "math/big" - "strings" ) // FundChainlinkNodes will fund all of the Chainlink nodes with a given amount of ETH in wei diff --git a/client/blockchain.go b/client/blockchain.go index 8d431e056..546facd4f 100644 --- a/client/blockchain.go +++ b/client/blockchain.go @@ -223,10 +223,10 @@ func (e *EthereumNetwork) Wallets() (BlockchainWallets, error) { // FluxMonitorSubmissionGasUsed Flux Monitor one submission gasUsed value func (e *EthereumNetwork) FluxMonitorSubmissionGasUsed() (*big.Int, error) { - if e.networkConfig.Name == "Ethereum Geth dev" { + if strings.HasPrefix(e.networkConfig.Name, "ethereum-geth") { return big.NewInt(400000), nil } - return nil, errors.New("unknown gas used estimation") + return nil, fmt.Errorf("gas used estimation unavailable for the network name '%s'", e.networkConfig.Name) } // BlockchainWallets is an interface that when implemented is a representation of a slice of wallets for diff --git a/client/client_suite_test.go b/client/client_suite_test.go index 88f6e2c39..6994b0e03 100644 --- a/client/client_suite_test.go +++ b/client/client_suite_test.go @@ -14,6 +14,6 @@ import ( func TestClient(t *testing.T) { RegisterFailHandler(Fail) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) - junitReporter := reporters.NewJUnitReporter("junit.xml") + junitReporter := reporters.NewJUnitReporter("../logs/tests-client.xml") RunSpecsWithDefaultAndCustomReporters(t, "Client Suite", []Reporter{junitReporter}) } diff --git a/client/ethereum.go b/client/ethereum.go index 0b51b8f31..edef39f03 100644 --- a/client/ethereum.go +++ b/client/ethereum.go @@ -326,18 +326,18 @@ func (e *EthereumClient) Get() interface{} { // CalculateTxGas calculates tx gas cost accordingly gas used plus buffer, converts it to big.Float for funding func (e *EthereumClient) CalculateTxGas(gasUsed *big.Int) (*big.Float, error) { - gp, err := e.Client.SuggestGasPrice(context.Background()) + gasPrice, err := e.Client.SuggestGasPrice(context.Background()) // Wei if err != nil { return nil, err } - gpWei := gp.Mul(gp, OneGWei) - log.Debug().Int64("Gas price", gp.Int64()).Msg("Suggested gas price") - buf := big.NewInt(int64(e.Network.Config().GasEstimationBuffer)) - gasUsedWithBuf := gasUsed.Add(gasUsed, buf) - cost := big.NewInt(1).Mul(gpWei, gasUsedWithBuf) - log.Debug().Int64("TX Gas cost", cost.Int64()).Msg("Estimated tx gas cost with buffer") - bf := new(big.Float).SetInt(cost) - return big.NewFloat(1).Quo(bf, OneEth), nil + buffer := big.NewInt(0).SetUint64(e.Network.Config().GasEstimationBuffer) + gasUsedWithBuffer := gasUsed.Add(gasUsed, buffer) + cost := big.NewFloat(0).SetInt(big.NewInt(1).Mul(gasPrice, gasUsedWithBuffer)) + costInEth := big.NewFloat(0).Quo(cost, OneEth) + costInEthFloat, _ := costInEth.Float64() + + log.Debug().Float64("ETH", costInEthFloat).Msg("Estimated tx gas cost with buffer") + return costInEth, nil } // GasStats gets gas stats instance @@ -366,7 +366,7 @@ func (e *EthereumClient) Fund( Str("Token", "ETH"). Str("From", fromWallet.Address()). Str("To", toAddress). - Str("Amount", eth.String()). + Str("Amount", ethAmount.String()). Msg("Funding Address") _, err := e.SendTransaction(fromWallet, ethAddress, eth, nil) if err != nil { @@ -381,7 +381,7 @@ func (e *EthereumClient) Fund( Str("Token", "LINK"). Str("From", fromWallet.Address()). Str("To", toAddress). - Str("Amount", link.String()). + Str("Amount", linkAmount.String()). Msg("Funding Address") linkAddress := common.HexToAddress(e.Network.Config().LinkTokenAddress) linkInstance, err := ethContracts.NewLinkToken(linkAddress, e.Client) diff --git a/config/config_suite_test.go b/config/config_suite_test.go index 128c1f044..309434831 100644 --- a/config/config_suite_test.go +++ b/config/config_suite_test.go @@ -14,6 +14,6 @@ import ( func TestConfig(t *testing.T) { RegisterFailHandler(Fail) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) - junitReporter := reporters.NewJUnitReporter("junit.xml") + junitReporter := reporters.NewJUnitReporter("../logs/tests-config.xml") RunSpecsWithDefaultAndCustomReporters(t, "Config Suite", []Reporter{junitReporter}) } diff --git a/environment/environment_test.go b/environment/environment_test.go index 8737da6af..3556ce4e7 100644 --- a/environment/environment_test.go +++ b/environment/environment_test.go @@ -54,7 +54,6 @@ var _ = Describe("Environment unit tests @unit", func() { It("should fetch secret private keys", func() { Skip("Not ready to be run in github") - conf, err := config.NewConfig(fmt.Sprintf(secretKeysConfig, tools.ProjectRoot)) Expect(err).ShouldNot(HaveOccurred()) diff --git a/environment/k8s_environment.go b/environment/k8s_environment.go index 1603639cc..d3ff45688 100644 --- a/environment/k8s_environment.go +++ b/environment/k8s_environment.go @@ -405,7 +405,7 @@ func (env *K8sEnvironment) deploySpecs(startIndex int, errChan chan<- error) { } func (env *K8sEnvironment) createNamespace(namespace string) (*coreV1.Namespace, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) defer cancel() createdNamespace, err := env.k8sClient.CoreV1().Namespaces().Create( @@ -417,9 +417,6 @@ func (env *K8sEnvironment) createNamespace(namespace string) (*coreV1.Namespace, }, metaV1.CreateOptions{}, ) - if err == nil { - log.Info().Str("Namespace", createdNamespace.Name).Msg("Created namespace") - } return createdNamespace, err } diff --git a/environment/k8s_environment_helm_test.go b/environment/k8s_environment_helm_test.go index 764a54c17..7e165c300 100644 --- a/environment/k8s_environment_helm_test.go +++ b/environment/k8s_environment_helm_test.go @@ -15,14 +15,15 @@ var _ = Describe("Environment with Helm @helm_deploy", func() { Describe("Chart deployments", func() { var env Environment + BeforeEach(func() { var err error conf, err = config.NewConfig(tools.ProjectRoot) Expect(err).ShouldNot(HaveOccurred()) }) + It("Deploy Geth reorg chart", func() { Skip("Not ready to be run in github") - conf.Networks = []string{"ethereum_geth_reorg"} networkConfig, err := client.DefaultNetworkFromConfig(conf) Expect(err).ShouldNot(HaveOccurred()) @@ -35,6 +36,7 @@ var _ = Describe("Environment with Helm @helm_deploy", func() { Expect(err).ShouldNot(HaveOccurred()) Expect(sd.RemoteURL).Should(ContainSubstring(strconv.Itoa(int(networkConfig.RemotePort())))) }) + AfterEach(func() { By("Tearing down the environment", func() { env.TearDown() diff --git a/environment/k8s_environment_test.go b/environment/k8s_environment_test.go index 085743d55..b622a3fe5 100644 --- a/environment/k8s_environment_test.go +++ b/environment/k8s_environment_test.go @@ -12,7 +12,10 @@ import ( ) var _ = Describe("Environment functionality @unit", func() { - var conf *config.Config + var ( + conf *config.Config + env Environment + ) BeforeEach(func() { var err error @@ -20,17 +23,18 @@ var _ = Describe("Environment functionality @unit", func() { Expect(err).ShouldNot(HaveOccurred()) }) - DescribeTable("basic environment", func( + DescribeTable("single network environments", func( initFunc client.BlockchainNetworkInit, envInitFunc K8sEnvSpecInit, nodeCount int, ) { - Skip("Not ready to be run in github") // Setup + Skip("Not ready to be run in github") + networkConfig, err := initFunc(conf) Expect(err).ShouldNot(HaveOccurred()) - env, err := NewK8sEnvironment(conf, networkConfig) + env, err = NewK8sEnvironment(conf, networkConfig) Expect(err).ShouldNot(HaveOccurred()) err = env.DeploySpecs(envInitFunc) Expect(err).ShouldNot(HaveOccurred()) @@ -51,4 +55,10 @@ var _ = Describe("Environment functionality @unit", func() { Entry("3 node cluster", client.DefaultNetworkFromConfig, NewChainlinkCluster(3), 3), Entry("mixed version cluster", client.DefaultNetworkFromConfig, NewMixedVersionChainlinkCluster(3, 2), 3), ) + + AfterEach(func() { + By("Tearing down the environment", func() { + env.TearDown() + }) + }) }) diff --git a/environment/k8s_helm_resource.go b/environment/k8s_helm_resource.go index ee9694050..7d6c5c21d 100644 --- a/environment/k8s_helm_resource.go +++ b/environment/k8s_helm_resource.go @@ -176,8 +176,17 @@ func (k *HelmChart) Deploy(_ map[string]interface{}) error { } k.actionConfig = &action.Configuration{} + // TODO: So, this is annoying, and not really all that important, I SHOULD be able to just use our K8sConfig function + // and pass that in as our config, but K8s has like 10 different config types, all of which don't talk to each other, + // and this wants an interface, instead of the rest config that we use everywhere else. Creating such an interface is + // also a huge hassle and... well anyway, if you've got some time to burn to make this more sensical, I hope you like + // digging into K8s code with sparse to no docs. + kubeConfigPath := filepath.Join(homeDir, DefaultK8sConfigPath) + if len(os.Getenv("KUBECONFIG")) > 0 { + kubeConfigPath = os.Getenv("KUBECONFIG") + } if err := k.actionConfig.Init( - kube.GetConfig(filepath.Join(homeDir, DefaultK8sConfigPath), "", k.env.namespace.Name), + kube.GetConfig(kubeConfigPath, "", k.env.namespace.Name), k.env.namespace.Name, os.Getenv("HELM_DRIVER"), func(format string, v ...interface{}) { diff --git a/suite/contracts/contracts_flux_validate_flag_test.go b/suite/contracts/contracts_flux_validate_flag_test.go index 266b4a018..139ff68a2 100644 --- a/suite/contracts/contracts_flux_validate_flag_test.go +++ b/suite/contracts/contracts_flux_validate_flag_test.go @@ -34,8 +34,8 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() fluxRoundConfirmer *contracts.FluxAggregatorRoundConfirmer flagSet bool err error + fluxRoundTimeout = time.Second * 30 ) - fluxRoundTimeout := time.Second * 30 BeforeEach(func() { By("Deploying the environment", func() { @@ -53,6 +53,7 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() networkInfo.Client.ParallelTransactions(true) }) + By("Deploying access controller, flags, deviation validator", func() { rac, err = networkInfo.Deployer.DeployReadAccessController(networkInfo.Wallets.Default()) Expect(err).ShouldNot(HaveOccurred()) @@ -61,6 +62,7 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() dfv, err = networkInfo.Deployer.DeployDeviationFlaggingValidator(networkInfo.Wallets.Default(), flags.Address(), big.NewInt(0)) Expect(err).ShouldNot(HaveOccurred()) }) + By("Deploying and funding contract", func() { fmOpts := contracts.FluxAggregatorOptions{ PaymentAmount: big.NewInt(1), @@ -80,10 +82,12 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("Setting access to flags contract", func() { err = rac.AddAccess(networkInfo.Wallets.Default(), dfv.Address()) Expect(err).ShouldNot(HaveOccurred()) }) + By("Funding Chainlink nodes", func() { nodeAddresses, err = actions.ChainlinkNodeAddresses(nodes) Expect(err).ShouldNot(HaveOccurred()) @@ -96,6 +100,7 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() ) Expect(err).ShouldNot(HaveOccurred()) }) + By("Setting oracle options", func() { err = fluxInstance.SetOracles(networkInfo.Wallets.Default(), contracts.FluxAggregatorSetOraclesOptions{ @@ -113,6 +118,7 @@ var _ = Describe("Flux monitor external validator suite @validator-flux", func() Expect(err).ShouldNot(HaveOccurred()) log.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") }) + By("Creating flux jobs", func() { for _, n := range nodes { fluxSpec := &client.FluxMonitorJobSpec{ diff --git a/suite/contracts/contracts_keeper_test.go b/suite/contracts/contracts_keeper_test.go index a4d631a15..7f231e2b6 100644 --- a/suite/contracts/contracts_keeper_test.go +++ b/suite/contracts/contracts_keeper_test.go @@ -27,6 +27,7 @@ var _ = Describe("Keeper suite @keeper", func() { checkGasLimit = uint32(2500000) err error ) + BeforeEach(func() { By("Deploying the environment", func() { suiteSetup, err = actions.SingleNetworkSetup( @@ -44,6 +45,7 @@ var _ = Describe("Keeper suite @keeper", func() { networkInfo.Client.ParallelTransactions(true) }) + By("Funding Chainlink nodes", func() { ethAmount, err := networkInfo.Deployer.CalculateETHForTXs(networkInfo.Wallets.Default(), networkInfo.Network.Config(), 10) Expect(err).ShouldNot(HaveOccurred()) @@ -56,6 +58,7 @@ var _ = Describe("Keeper suite @keeper", func() { ) Expect(err).ShouldNot(HaveOccurred()) }) + By("Deploying Keeper contracts", func() { ef, err := networkInfo.Deployer.DeployMockETHLINKFeed(networkInfo.Wallets.Default(), big.NewInt(2e18)) Expect(err).ShouldNot(HaveOccurred()) @@ -86,6 +89,7 @@ var _ = Describe("Keeper suite @keeper", func() { err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("Registering upkeep target", func() { registrar, err := networkInfo.Deployer.DeployUpkeepRegistrationRequests( networkInfo.Wallets.Default(), @@ -120,6 +124,7 @@ var _ = Describe("Keeper suite @keeper", func() { err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("Adding Keepers and a job", func() { keys, err := nodes[0].ReadETHKeys() Expect(err).ShouldNot(HaveOccurred()) @@ -146,6 +151,7 @@ var _ = Describe("Keeper suite @keeper", func() { Expect(err).ShouldNot(HaveOccurred()) }) }) + Describe("with Keeper job", func() { It("performs upkeep of a target contract", func() { Eventually(func(g Gomega) { @@ -156,6 +162,7 @@ var _ = Describe("Keeper suite @keeper", func() { }, "2m", "1s").Should(Succeed()) }) }) + AfterEach(func() { By("Printing gas stats", func() { networkInfo.Client.GasStats().PrintStats() diff --git a/suite/contracts/contracts_test.go b/suite/contracts/contracts_test.go index 98e45a137..5c9725f7d 100644 --- a/suite/contracts/contracts_test.go +++ b/suite/contracts/contracts_test.go @@ -63,6 +63,7 @@ var _ = Describe("Basic Contract Interactions @contract", func() { _, err := networkInfo.Deployer.DeployOffChainAggregator(defaultWallet, ocrOptions) Expect(err).ShouldNot(HaveOccurred()) }) + By("deploying keeper contracts", func() { ef, err := networkInfo.Deployer.DeployMockETHLINKFeed(networkInfo.Wallets.Default(), big.NewInt(2e18)) Expect(err).ShouldNot(HaveOccurred()) @@ -87,6 +88,7 @@ var _ = Describe("Basic Contract Interactions @contract", func() { err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("deploying vrf contract", func() { bhs, err := networkInfo.Deployer.DeployBlockhashStore(networkInfo.Wallets.Default()) Expect(err).ShouldNot(HaveOccurred()) @@ -99,6 +101,7 @@ var _ = Describe("Basic Contract Interactions @contract", func() { err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("deploying direct request contract", func() { _, err := networkInfo.Deployer.DeployOracle(networkInfo.Wallets.Default(), networkInfo.Link.Address()) Expect(err).ShouldNot(HaveOccurred()) diff --git a/suite/contracts/contracts_vrf_test.go b/suite/contracts/contracts_vrf_test.go index 7deebd5cc..5e51e2a39 100644 --- a/suite/contracts/contracts_vrf_test.go +++ b/suite/contracts/contracts_vrf_test.go @@ -41,12 +41,14 @@ var _ = Describe("VRF suite @vrf", func() { networkInfo.Client.ParallelTransactions(true) }) + By("Funding Chainlink nodes", func() { ethAmount, err := networkInfo.Deployer.CalculateETHForTXs(networkInfo.Wallets.Default(), networkInfo.Network.Config(), 1) Expect(err).ShouldNot(HaveOccurred()) err = actions.FundChainlinkNodes(nodes, networkInfo.Client, networkInfo.Wallets.Default(), ethAmount, nil) Expect(err).ShouldNot(HaveOccurred()) }) + By("Deploying VRF contracts", func() { bhs, err := networkInfo.Deployer.DeployBlockhashStore(networkInfo.Wallets.Default()) Expect(err).ShouldNot(HaveOccurred()) @@ -61,6 +63,7 @@ var _ = Describe("VRF suite @vrf", func() { err = networkInfo.Client.WaitForEvents() Expect(err).ShouldNot(HaveOccurred()) }) + By("Creating jobs and registering proving keys", func() { for _, n := range nodes { nodeKeys, err := n.ReadVRFKeys() @@ -115,6 +118,7 @@ var _ = Describe("VRF suite @vrf", func() { }, "2m", "1s").Should(Succeed()) }) }) + AfterEach(func() { By("Printing gas stats", func() { networkInfo.Client.GasStats().PrintStats() diff --git a/suite/refill/eth_refill_test.go b/suite/refill/eth_refill_test.go index 80c3438bc..ee0052769 100644 --- a/suite/refill/eth_refill_test.go +++ b/suite/refill/eth_refill_test.go @@ -20,15 +20,15 @@ import ( var _ = Describe("FluxAggregator ETH Refill @refill", func() { var ( - suiteSetup actions.SuiteSetup - networkInfo actions.NetworkInfo - adapter environment.ExternalAdapter - nodes []client.Chainlink - nodeAddresses []common.Address - err error - fluxInstance contracts.FluxAggregator + suiteSetup actions.SuiteSetup + networkInfo actions.NetworkInfo + adapter environment.ExternalAdapter + nodes []client.Chainlink + nodeAddresses []common.Address + err error + fluxInstance contracts.FluxAggregator + fluxRoundTimeout = 35 * time.Second ) - fluxRoundTimeout := 30 * time.Second BeforeEach(func() { By("Deploying the environment", func() { @@ -138,6 +138,16 @@ var _ = Describe("FluxAggregator ETH Refill @refill", func() { fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout) networkInfo.Client.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) err = networkInfo.Client.WaitForEvents() + if err == nil { // Not all has been drained, try another round + err = adapter.SetVariable(7) + Expect(err).ShouldNot(HaveOccurred()) + + fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(3), fluxRoundTimeout) + networkInfo.Client.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) + err = networkInfo.Client.WaitForEvents() + } + Expect(err).ShouldNot(BeNil(), "Flux rounds are still happening after draining the nodes of ETH, "+ + "was expecting an error. Nodes likely haven't been fully drained of their ETH") Expect(err.Error()).Should(ContainSubstring("timeout waiting for flux round to confirm")) }) }) diff --git a/tools/integration_test.sh b/tools/integration_test.sh new file mode 100755 index 000000000..269ed10be --- /dev/null +++ b/tools/integration_test.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Inputs: +# performance: 0 or 1 +# Indicates whether this is a performance test run or not. +# - 0: No performance tests +# - 1: Performance tests +performance=$1 + +if [[ $performance == 0 ]]; then + echo "Running smoke tests" + ginkgo -r -keepGoing --trace --randomizeAllSpecs --randomizeSuites --progress -nodes=10 -skipPackage=./suite/performance,./suite/chaos ./suite/... +else + echo "Running performance and chaos tests" + ginkgo -r -keepGoing --trace --randomizeAllSpecs --randomizeSuites --progress ./suite/performance ./suite/chaos +fi \ No newline at end of file