From fc870347428a96fbfda66f1e92cd2253d3dc6b24 Mon Sep 17 00:00:00 2001 From: harry <53987565+h5law@users.noreply.github.com> Date: Mon, 23 Oct 2023 19:22:05 +0100 Subject: [PATCH] [E2E] Add Regression Testing for Send E2E Feature Test (#84) --- e2e/tests/init_test.go | 103 ++++++++++++++++++++++++++++++++++------- e2e/tests/node.go | 2 +- e2e/tests/send.feature | 7 ++- go.mod | 4 +- 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/e2e/tests/init_test.go b/e2e/tests/init_test.go index 0ab3be752..fe831a507 100644 --- a/e2e/tests/init_test.go +++ b/e2e/tests/init_test.go @@ -5,26 +5,37 @@ package e2e import ( "fmt" "regexp" + "strconv" "strings" "testing" + "time" "github.com/regen-network/gocuke" "github.com/stretchr/testify/require" ) -var addrRe *regexp.Regexp +var ( + addrRe *regexp.Regexp + amountRe *regexp.Regexp + accNameToAddrMap = make(map[string]string) + keyRingFlag = "--keyring-backend=test" +) func init() { - addrRe = regexp.MustCompile(`address:\s+(pokt1\w+)`) + addrRe = regexp.MustCompile(`address: (\S+)\s+name: (\S+)`) + amountRe = regexp.MustCompile(`amount: "(.+?)"\s+denom: upokt`) } type suite struct { gocuke.TestingT - pocketd *pocketdBin + pocketd *pocketdBin + scenarioState map[string]any // temporary state for each scenario } func (s *suite) Before() { s.pocketd = new(pocketdBin) + s.scenarioState = make(map[string]any) + s.buildAddrMap() } // TestFeatures runs the e2e tests specified in any .features files in this directory @@ -56,17 +67,15 @@ func (s *suite) TheUserShouldBeAbleToSeeStandardOutputContaining(arg1 string) { } } -func (s *suite) TheUserSendsUpoktToAnotherAddress(amount int64) { - addrs := s.getAddresses() +func (s *suite) TheUserSendsUpoktFromAccountToAccount(amount int64, accName1, accName2 string) { args := []string{ "tx", "bank", "send", - addrs[0], - addrs[1], + accNameToAddrMap[accName1], + accNameToAddrMap[accName2], fmt.Sprintf("%dupokt", amount), - "--keyring-backend", - "test", + keyRingFlag, "-y", } res, err := s.pocketd.RunCommandOnHost("", args...) @@ -76,20 +85,78 @@ func (s *suite) TheUserSendsUpoktToAnotherAddress(amount int64) { s.pocketd.result = res } -func (s *suite) getAddresses() [2]string { - var strs [2]string +func (s *suite) TheAccountHasABalanceGreaterThanUpokt(accName string, amount int64) { + bal := s.getAccBalance(accName) + if int64(bal) < amount { + s.Fatalf("account %s does not have enough upokt: %d < %d", accName, bal, amount) + } + s.scenarioState[accName] = bal // save the balance for later +} + +func (s *suite) AnAccountExistsFor(accName string) { + bal := s.getAccBalance(accName) + s.scenarioState[accName] = bal // save the balance for later +} + +func (s *suite) TheAccountBalanceOfShouldBeUpoktThanBefore(accName string, amount int64, condition string) { + prev, ok := s.scenarioState[accName] + if !ok { + s.Fatalf("no previous balance found for %s", accName) + } + + bal := s.getAccBalance(accName) + switch condition { + case "more": + if bal <= prev.(int) { + s.Fatalf("account %s expected to have more upokt but: %d <= %d", accName, bal, prev) + } + case "less": + if bal >= prev.(int) { + s.Fatalf("account %s expected to have less upokt but: %d >= %d", accName, bal, prev) + } + default: + s.Fatalf("unknown condition %s", condition) + } +} + +func (s *suite) TheUserShouldWaitForSeconds(dur int64) { + time.Sleep(time.Duration(dur) * time.Second) +} + +func (s *suite) buildAddrMap() { + s.Helper() res, err := s.pocketd.RunCommand( - "keys", "list", "--keyring-backend", "test", + "keys", "list", keyRingFlag, ) if err != nil { s.Fatalf("error getting keys: %s", err) } matches := addrRe.FindAllStringSubmatch(res.Stdout, -1) - if len(matches) >= 2 { - strs[0] = matches[0][1] - strs[1] = matches[len(matches)-1][1] - } else { - s.Fatalf("could not find two addresses in output: %s", res.Stdout) + for _, match := range matches { + name := match[2] + address := match[1] + accNameToAddrMap[name] = address + } +} + +func (s *suite) getAccBalance(accName string) int { + s.Helper() + args := []string{ + "query", + "bank", + "balances", + accNameToAddrMap[accName], + } + res, err := s.pocketd.RunCommandOnHost("", args...) + if err != nil { + s.Fatalf("error getting balance: %s", err) + } + s.pocketd.result = res + match := amountRe.FindStringSubmatch(res.Stdout) + if len(match) < 2 { + s.Fatalf("no balance found for %s", accName) } - return strs + found, err := strconv.Atoi(match[1]) + require.NoError(s, err) + return found } diff --git a/e2e/tests/node.go b/e2e/tests/node.go index 4a025cae5..ba0e3b46b 100644 --- a/e2e/tests/node.go +++ b/e2e/tests/node.go @@ -24,7 +24,7 @@ func init() { defaultRPCURL = fmt.Sprintf("tcp://%s:%d", defaultRPCHost, defaultRPCPort) } if defaultHome == "" { - defaultHome = "./localnet/pocketd" + defaultHome = "../../localnet/pocketd" } } diff --git a/e2e/tests/send.feature b/e2e/tests/send.feature index 1e2bdf2f8..dc5fc4504 100644 --- a/e2e/tests/send.feature +++ b/e2e/tests/send.feature @@ -2,7 +2,12 @@ Feature: Tx Namespace Scenario: User can send uPOKT Given the user has the pocketd binary installed - When the user sends 10000 uPOKT to another address + And the account "app1" has a balance greater than "1000" uPOKT + And an account exists for "app2" + When the user sends "1000" uPOKT from account "app1" to account "app2" Then the user should be able to see standard output containing "txhash:" And the user should be able to see standard output containing "code: 0" And the pocketd binary should exit without error + And the user should wait for "5" seconds + And the account balance of "app1" should be "1000" uPOKT "less" than before + And the account balance of "app2" should be "1000" uPOKT "more" than before diff --git a/go.mod b/go.mod index 9c881afe5..3534e7fda 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( cosmossdk.io/math v1.0.1 github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 + github.com/cosmos/cosmos-proto v1.0.0-beta.2 github.com/cosmos/cosmos-sdk v0.47.3 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.1.0 @@ -22,6 +23,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 google.golang.org/grpc v1.56.1 gopkg.in/yaml.v2 v2.4.0 ) @@ -66,7 +68,6 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.0 // indirect @@ -265,7 +266,6 @@ require ( gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect