From d30c7db49abe5f6851301b91898fcc09dc2c5b4a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 31 Aug 2020 12:42:42 +0300 Subject: [PATCH] cli: add tests for NEP5 transfer --- cli/executor_test.go | 26 +++++++++++++++++++++++ cli/nep5_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++ cli/options/options.go | 4 ++++ 3 files changed, 78 insertions(+) diff --git a/cli/executor_test.go b/cli/executor_test.go index ce35b0143..142cfce3d 100644 --- a/cli/executor_test.go +++ b/cli/executor_test.go @@ -1,22 +1,28 @@ package main import ( + "bufio" "bytes" "errors" "io" + "io/ioutil" "testing" + "time" "github.com/nspcc-dev/neo-go/cli/input" "github.com/nspcc-dev/neo-go/pkg/config" "github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/storage" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/network" "github.com/nspcc-dev/neo-go/pkg/rpc/server" + "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" "github.com/urfave/cli" "go.uber.org/zap" "go.uber.org/zap/zaptest" + "golang.org/x/crypto/ssh/terminal" ) const ( @@ -42,6 +48,8 @@ type executor struct { Out *bytes.Buffer // Err contains command errors. Err *bytes.Buffer + // In contains command input. + In *bytes.Buffer } func newTestChain(t *testing.T) (*core.Blockchain, *server.Server, *network.Server) { @@ -72,9 +80,13 @@ func newExecutor(t *testing.T, needChain bool) *executor { CLI: newApp(), Out: bytes.NewBuffer(nil), Err: bytes.NewBuffer(nil), + In: bytes.NewBuffer(nil), } e.CLI.Writer = e.Out e.CLI.ErrWriter = e.Err + rw := bufio.NewReadWriter(bufio.NewReader(e.In), bufio.NewWriter(ioutil.Discard)) + require.Nil(t, input.Terminal) // check that tests clean up properly + input.Terminal = terminal.NewTerminal(rw, "") if needChain { e.Chain, e.RPC, e.NetSrv = newTestChain(t) } @@ -94,6 +106,20 @@ func (e *executor) Close(t *testing.T) { } } +// GetTransaction returns tx with hash h after it has persisted. +// If it is in mempool, we can just wait for the next block, otherwise +// it must be already in chain. 1 second is time per block in a unittest chain. +func (e *executor) GetTransaction(t *testing.T, h util.Uint256) *transaction.Transaction { + var tx *transaction.Transaction + require.Eventually(t, func() bool { + var height uint32 + var err error + tx, height, err = e.Chain.GetTransaction(h) + return err == nil && height != 0 + }, time.Second*2, time.Millisecond*100, "too long time waiting for block") + return tx +} + func (e *executor) checkNextLine(t *testing.T, expected string) { line, err := e.Out.ReadString('\n') require.NoError(t, err) diff --git a/cli/nep5_test.go b/cli/nep5_test.go index 81fcdd8de..f9a639cde 100644 --- a/cli/nep5_test.go +++ b/cli/nep5_test.go @@ -1,10 +1,16 @@ package main import ( + "math/big" "strconv" + "strings" "testing" + "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm" + "github.com/nspcc-dev/neo-go/pkg/wallet" + "github.com/stretchr/testify/require" ) func TestNEP5Balance(t *testing.T) { @@ -44,3 +50,45 @@ func TestNEP5Balance(t *testing.T) { }) return } + +func TestNEP5Transfer(t *testing.T) { + w, err := wallet.NewWalletFromFile("testdata/testwallet.json") + require.NoError(t, err) + defer w.Close() + + e := newExecutor(t, true) + defer e.Close(t) + args := []string{ + "neo-go", "wallet", "nep5", "transfer", + "--unittest", + "--rpc-endpoint", "http://" + e.RPC.Addr, + "--wallet", validatorWallet, + "--from", validatorAddr, + "--to", w.Accounts[0].Address, + "--token", "neo", + "--amount", "1", + } + + t.Run("InvalidPassword", func(t *testing.T) { + e.In.WriteString("onetwothree\r") + e.RunWithError(t, args...) + e.In.Reset() + }) + + e.In.WriteString("one\r") + e.Run(t, args...) + line, err := e.Out.ReadString('\n') + require.NoError(t, err) + h, err := util.Uint256DecodeStringLE(strings.TrimSpace(line)) + require.NoError(t, err, "can't decode tx hash: %s", line) + + tx := e.GetTransaction(t, h) + aer, err := e.Chain.GetAppExecResult(tx.Hash()) + require.NoError(t, err) + require.Equal(t, vm.HaltState, aer.VMState) + + sh, err := address.StringToUint160(w.Accounts[0].Address) + require.NoError(t, err) + b, _ := e.Chain.GetGoverningTokenBalance(sh) + require.Equal(t, big.NewInt(1), b) +} diff --git a/cli/options/options.go b/cli/options/options.go index 19420db0f..19f4c7e4e 100644 --- a/cli/options/options.go +++ b/cli/options/options.go @@ -37,6 +37,7 @@ var RPC = []cli.Flag{ cli.BoolFlag{Name: "privnet, p"}, cli.BoolFlag{Name: "mainnet, m"}, cli.BoolFlag{Name: "testnet, t"}, + cli.BoolFlag{Name: "unittest", Hidden: true}, } var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'") @@ -51,6 +52,9 @@ func GetNetwork(ctx *cli.Context) netmode.Magic { if ctx.Bool("mainnet") { net = netmode.MainNet } + if ctx.Bool("unittest") { + net = netmode.UnitTestNet + } return net }