Merge PR #1520: various fixes for test_cli

* various fixes for test_cli
* linting
This commit is contained in:
Ethan Buchman 2018-07-03 00:33:53 -04:00 committed by Christopher Goes
parent 85ba874d3b
commit d388036454
21 changed files with 195 additions and 145 deletions

View File

@ -83,7 +83,7 @@ jobs:
name: Test cli
command: |
export PATH="$GOBIN:$PATH"
make test_cli_retry
make test_cli
test_cover:
<<: *defaults

View File

@ -92,15 +92,9 @@ test: test_unit
test_cli:
@go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test`
test_cli_retry:
for i in 1 2 3; do make test_cli && break || sleep 2; done
test_unit:
@go test $(PACKAGES_NOCLITEST)
test_unit_retry:
for i in 1 2 3; do make test_unit && break || sleep 2; done
test_race:
@go test -race $(PACKAGES_NOCLITEST)

View File

@ -11,10 +11,10 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"

View File

@ -9,9 +9,9 @@ import (
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
cmn "github.com/tendermint/tendermint/libs/common"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"

View File

@ -13,9 +13,9 @@ import (
cryptoKeys "github.com/cosmos/cosmos-sdk/crypto/keys"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/common"
p2p "github.com/tendermint/tendermint/p2p"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/tendermint/tendermint/libs/common"
client "github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"

View File

@ -9,8 +9,8 @@ import (
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
cmn "github.com/tendermint/tendermint/libs/common"
tmserver "github.com/tendermint/tendermint/rpc/lib/server"
client "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"

View File

@ -19,14 +19,14 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
tmcfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
nm "github.com/tendermint/tendermint/node"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
tmrpc "github.com/tendermint/tendermint/rpc/lib/server"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/client"
keys "github.com/cosmos/cosmos-sdk/client/keys"
@ -169,7 +169,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.Address) (
//time.Sleep(time.Second)
//tests.WaitForHeight(2, port)
tests.WaitForStart(port)
tests.WaitForLCDStart(port)
tests.WaitForHeight(1, port)
// for use in defer

View File

@ -7,6 +7,9 @@ import (
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
@ -16,7 +19,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/stake"
"github.com/tendermint/tendermint/crypto"
)
func TestGaiaCLISend(t *testing.T) {
@ -34,9 +36,10 @@ func TestGaiaCLISend(t *testing.T) {
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer proc.Stop(false)
tests.WaitForStart(port)
tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
@ -90,9 +93,10 @@ func TestGaiaCLICreateValidator(t *testing.T) {
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer proc.Stop(false)
tests.WaitForStart(port)
tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
@ -130,19 +134,20 @@ func TestGaiaCLICreateValidator(t *testing.T) {
require.Equal(t, "2/1", validator.PoolShares.Amount.String())
// unbond a single share
unbondStr := fmt.Sprintf("gaiacli stake unbond %v", flags)
unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags)
unbondStr += fmt.Sprintf(" --name=%v", "bar")
unbondStr += fmt.Sprintf(" --address-validator=%v", barCech)
unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech)
unbondStr += fmt.Sprintf(" --shares=%v", "1")
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
t.Log(fmt.Sprintf("debug unbondStr: %v\n", unbondStr))
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
executeWrite(t, unbondStr, pass)
success := executeWrite(t, unbondStr, pass)
require.True(t, success)
tests.WaitForNextHeightTM(port)
/* // this won't be what we expect because we've only started unbonding, haven't completed
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
*/
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %v --output=json %v", barCech, flags))
require.Equal(t, "1/1", validator.PoolShares.Amount.String())
}
@ -162,9 +167,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
proc := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer proc.Stop(false)
tests.WaitForStart(port)
tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
@ -203,14 +209,27 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
//___________________________________________________________________________________
// executors
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
func executeWrite(t *testing.T, cmdStr string, writes ...string) bool {
proc := tests.GoExecuteT(t, cmdStr)
for _, write := range writes {
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
require.NoError(t, err)
}
stdout, stderr, err := proc.ReadAll()
if err != nil {
fmt.Println("Err on proc.ReadAll()", err, cmdStr)
}
// Log output.
if len(stdout) > 0 {
t.Log("Stdout:", cmn.Green(string(stdout)))
}
if len(stderr) > 0 {
t.Log("Stderr:", cmn.Red(string(stderr)))
}
proc.Wait()
return proc.ExitState.Success()
// bz := proc.StdoutBuffer.Bytes()
// fmt.Println("EXEC WRITE", string(bz))
}

View File

@ -6,10 +6,10 @@ import (
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"

View File

@ -4,10 +4,10 @@ import (
"encoding/json"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"

View File

@ -7,10 +7,10 @@ import (
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
"github.com/cosmos/cosmos-sdk/server"

View File

@ -5,9 +5,9 @@ import (
"path/filepath"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
)
// AppCreator lets us lazily initialize app, using home dir

View File

@ -18,12 +18,12 @@ import (
"github.com/tendermint/tendermint/crypto"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
tmtypes "github.com/tendermint/tendermint/types"
tmcli "github.com/tendermint/tendermint/libs/cli"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
tmtypes "github.com/tendermint/tendermint/types"
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"

View File

@ -7,9 +7,9 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
tmtypes "github.com/tendermint/tendermint/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
bam "github.com/cosmos/cosmos-sdk/baseapp"
gc "github.com/cosmos/cosmos-sdk/server/config"

View File

@ -8,10 +8,10 @@ import (
"github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/node"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
cmn "github.com/tendermint/tendermint/libs/common"
)
const (

View File

@ -7,8 +7,8 @@ import (
"golang.org/x/crypto/ripemd160"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/crypto/merkle"
dbm "github.com/tendermint/tendermint/libs/db"
sdk "github.com/cosmos/cosmos-sdk/types"
)

View File

@ -5,8 +5,8 @@ import (
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/crypto/merkle"
dbm "github.com/tendermint/tendermint/libs/db"
sdk "github.com/cosmos/cosmos-sdk/types"
)

View File

@ -1,6 +1,8 @@
package tests
import (
"fmt"
"io/ioutil"
"strings"
"testing"
@ -21,13 +23,15 @@ func ExecuteT(t *testing.T, cmd string) (out string) {
}
// Start process and wait.
proc, err := StartProcess("", name, args, nil, nil)
proc, err := StartProcess("", name, args)
require.NoError(t, err)
proc.Wait()
// Get the output.
outbz := proc.StdoutBuffer.Bytes()
errbz := proc.StderrBuffer.Bytes()
outbz, errbz, err := proc.ReadAll()
if err != nil {
fmt.Println("Err on proc.ReadAll()", err, args)
}
proc.Wait()
// Log output.
if len(outbz) > 0 {
@ -56,36 +60,38 @@ func GoExecuteT(t *testing.T, cmd string) (proc *Process) {
}
// Start process.
proc, err := StartProcess("", name, args, nil, nil)
proc, err := StartProcess("", name, args)
require.NoError(t, err)
// Run goroutines to log stdout.
go func() {
buf := make([]byte, 10240) // TODO Document the effects.
for {
n, err := proc.StdoutBuffer.Read(buf)
if err != nil {
return
}
if n > 0 {
t.Log("Stdout:", cmn.Green(string(buf[:n])))
}
}
}()
// Run goroutines to log stderr.
go func() {
buf := make([]byte, 10240) // TODO Document the effects.
for {
n, err := proc.StderrBuffer.Read(buf)
if err != nil {
return
}
if n > 0 {
t.Log("Stderr:", cmn.Red(string(buf[:n])))
}
}
}()
return proc
}
// Same as GoExecuteT but spawns a go routine to ReadAll off stdout.
func GoExecuteTWithStdout(t *testing.T, cmd string) (proc *Process) {
t.Log("Running", cmn.Cyan(cmd))
// Split cmd to name and args.
split := strings.Split(cmd, " ")
require.True(t, len(split) > 0, "no command provided")
name, args := split[0], []string(nil)
if len(split) > 1 {
args = split[1:]
}
// Start process.
proc, err := CreateProcess("", name, args)
require.NoError(t, err)
// Without this, the test halts ?!
go func() {
_, err := ioutil.ReadAll(proc.StdoutPipe)
if err != nil {
fmt.Println("-------------ERR-----------------------", err)
return
}
}()
err = proc.Cmd.Start()
require.NoError(t, err)
proc.Pid = proc.Cmd.Process.Pid
return proc
}

View File

@ -1,8 +1,8 @@
package tests
import (
"bytes"
"io"
"io/ioutil"
"os"
"os/exec"
"time"
@ -10,26 +10,37 @@ import (
// execution process
type Process struct {
ExecPath string
Args []string
Pid int
StartTime time.Time
EndTime time.Time
Cmd *exec.Cmd `json:"-"`
ExitState *os.ProcessState `json:"-"`
WaitCh chan struct{} `json:"-"`
StdinPipe io.WriteCloser `json:"-"`
StdoutBuffer *bytes.Buffer `json:"-"`
StderrBuffer *bytes.Buffer `json:"-"`
ExecPath string
Args []string
Pid int
StartTime time.Time
EndTime time.Time
Cmd *exec.Cmd `json:"-"`
ExitState *os.ProcessState `json:"-"`
StdinPipe io.WriteCloser `json:"-"`
StdoutPipe io.ReadCloser `json:"-"`
StderrPipe io.ReadCloser `json:"-"`
}
// dir: The working directory. If "", os.Getwd() is used.
// name: Command name
// args: Args to command. (should not include name)
// outFile, errFile: If not nil, will use, otherwise new Buffers will be
// allocated. Either way, Process.Cmd.StdoutPipe and Process.Cmd.StderrPipe will be nil
// respectively.
func StartProcess(dir string, name string, args []string, outFile, errFile io.WriteCloser) (*Process, error) {
func StartProcess(dir string, name string, args []string) (*Process, error) {
proc, err := CreateProcess(dir, name, args)
if err != nil {
return nil, err
}
// cmd start
if err := proc.Cmd.Start(); err != nil {
return nil, err
}
proc.Pid = proc.Cmd.Process.Pid
return proc, nil
}
// Same as StartProcess but doesn't start the process
func CreateProcess(dir string, name string, args []string) (*Process, error) {
var cmd = exec.Command(name, args...) // is not yet started.
// cmd dir
if dir == "" {
@ -46,52 +57,27 @@ func StartProcess(dir string, name string, args []string, outFile, errFile io.Wr
if err != nil {
return nil, err
}
// cmd stdout, stderr
var outBuffer, errBuffer *bytes.Buffer
if outFile != nil {
cmd.Stdout = outFile
} else {
outBuffer = bytes.NewBuffer(nil)
cmd.Stdout = outBuffer
}
if errFile != nil {
cmd.Stderr = errFile
} else {
errBuffer = bytes.NewBuffer(nil)
cmd.Stderr = errBuffer
}
// cmd start
if err := cmd.Start(); err != nil {
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
proc := &Process{
ExecPath: name,
Args: args,
Pid: cmd.Process.Pid,
StartTime: time.Now(),
Cmd: cmd,
ExitState: nil,
WaitCh: make(chan struct{}),
StdinPipe: stdin,
ExecPath: name,
Args: args,
StartTime: time.Now(),
Cmd: cmd,
ExitState: nil,
StdinPipe: stdin,
StdoutPipe: stdout,
StderrPipe: stderr,
}
if outBuffer != nil {
proc.StdoutBuffer = outBuffer
}
if errBuffer != nil {
proc.StderrBuffer = errBuffer
}
go func() {
err := proc.Cmd.Wait()
if err != nil {
// fmt.Printf("Process exit: %v\n", err)
if exitError, ok := err.(*exec.ExitError); ok {
proc.ExitState = exitError.ProcessState
}
}
proc.ExitState = proc.Cmd.ProcessState
proc.EndTime = time.Now() // TODO make this goroutine-safe
close(proc.WaitCh)
}()
return proc, nil
}
@ -106,5 +92,26 @@ func (proc *Process) Stop(kill bool) error {
// wait for the process
func (proc *Process) Wait() {
<-proc.WaitCh
err := proc.Cmd.Wait()
if err != nil {
// fmt.Printf("Process exit: %v\n", err)
if exitError, ok := err.(*exec.ExitError); ok {
proc.ExitState = exitError.ProcessState
}
}
proc.ExitState = proc.Cmd.ProcessState
proc.EndTime = time.Now() // TODO make this goroutine-safe
}
// ReadAll calls ioutil.ReadAll on the StdoutPipe and StderrPipe.
func (proc *Process) ReadAll() (stdout []byte, stderr []byte, err error) {
outbz, err := ioutil.ReadAll(proc.StdoutPipe)
if err != nil {
return nil, nil, err
}
errbz, err := ioutil.ReadAll(proc.StderrPipe)
if err != nil {
return nil, nil, err
}
return outbz, errbz, nil
}

View File

@ -21,13 +21,20 @@ func WaitForNextHeightTM(port string) {
// Wait for N tendermint blocks to pass using the Tendermint RPC
// on localhost
func WaitForNextNBlocksTM(n int64, port string) {
// get the latest block and wait for n more
url := fmt.Sprintf("http://localhost:%v", port)
cl := tmclient.NewHTTP(url, "/websocket")
resBlock, err := cl.Block(nil)
if err != nil {
panic(err)
var height int64
if err != nil || resBlock.Block == nil {
// wait for the first block to exist
WaitForHeightTM(1, port)
height = 1 + n
} else {
height = resBlock.Block.Height + n
}
waitForHeightTM(resBlock.Block.Height+n, url)
waitForHeightTM(height, url)
}
// Wait for the given height from the Tendermint RPC
@ -57,7 +64,6 @@ func waitForHeightTM(height int64, url string) {
if resBlock.Block != nil &&
resBlock.Block.Height >= height {
fmt.Println("HEIGHT", resBlock.Block.Height)
return
}
time.Sleep(time.Millisecond * 100)
@ -115,10 +121,23 @@ func waitForHeight(height int64, url string) {
}
}
// wait for tendermint to start
func WaitForStart(port string) {
var err error
// wait for tendermint to start by querying the LCD
func WaitForLCDStart(port string) {
url := fmt.Sprintf("http://localhost:%v/blocks/latest", port)
WaitForStart(url)
}
// wait for tendermint to start by querying tendermint
func WaitForTMStart(port string) {
url := fmt.Sprintf("http://localhost:%v/block", port)
WaitForStart(url)
}
// WaitForStart waits for the node to start by pinging the url
// every 100ms for 5s until it returns 200. If it takes longer than 5s,
// it panics.
func WaitForStart(url string) {
var err error
// ping the status endpoint a few times a second
// for a few seconds until we get a good response.
@ -131,6 +150,8 @@ func WaitForStart(port string) {
if err != nil || res == nil {
continue
}
// body, _ := ioutil.ReadAll(res.Body)
// fmt.Println("BODY", string(body))
err = res.Body.Close()
if err != nil {
panic(err)

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
@ -154,9 +155,10 @@ func GetCmdRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
Short: "redelegate illiquid tokens from one validator to another",
}
cmd.AddCommand(
GetCmdBeginRedelegate(storeName, cdc),
GetCmdCompleteRedelegate(cdc),
)
client.PostCommands(
GetCmdBeginRedelegate(storeName, cdc),
GetCmdCompleteRedelegate(cdc),
)...)
return cmd
}
@ -301,9 +303,10 @@ func GetCmdUnbond(storeName string, cdc *wire.Codec) *cobra.Command {
Short: "begin or complete unbonding shares from a validator",
}
cmd.AddCommand(
GetCmdBeginUnbonding(storeName, cdc),
GetCmdCompleteUnbonding(cdc),
)
client.PostCommands(
GetCmdBeginUnbonding(storeName, cdc),
GetCmdCompleteUnbonding(cdc),
)...)
return cmd
}