Merge PR #6033: Add setup for cli_test
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package helpers
|
||||
|
||||
const (
|
||||
Denom = "stake"
|
||||
KeyFoo = "foo"
|
||||
KeyBar = "bar"
|
||||
FooDenom = "footoken"
|
||||
FeeDenom = "feetoken"
|
||||
Fee2Denom = "fee2token"
|
||||
KeyBaz = "baz"
|
||||
KeyVesting = "vesting"
|
||||
KeyFooBarBaz = "foobarbaz"
|
||||
)
|
||||
@@ -0,0 +1,49 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
)
|
||||
|
||||
func ExecuteWriteCheckErr(t *testing.T, cmdStr string, writes ...string) {
|
||||
require.True(t, ExecuteWrite(t, cmdStr, writes...))
|
||||
}
|
||||
|
||||
func ExecuteWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) {
|
||||
exitSuccess, _, _ = ExecuteWriteRetStdStreams(t, cmdStr, writes...)
|
||||
return
|
||||
}
|
||||
|
||||
func ExecuteWriteRetStdStreams(t *testing.T, cmdStr string, writes ...string) (bool, string, string) {
|
||||
proc := tests.GoExecuteT(t, cmdStr)
|
||||
|
||||
// Enables use of interactive commands
|
||||
for _, write := range writes {
|
||||
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Read both stdout and stderr from the process
|
||||
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:", string(stdout))
|
||||
}
|
||||
if len(stderr) > 0 {
|
||||
t.Log("Stderr:", string(stderr))
|
||||
}
|
||||
|
||||
// Wait for process to exit
|
||||
proc.Wait()
|
||||
|
||||
// Return succes, stdout, stderr
|
||||
return proc.ExitState.Success(), string(stdout), string(stderr)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/std"
|
||||
"github.com/stretchr/testify/require"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
)
|
||||
|
||||
var cdc = std.MakeCodec(simapp.ModuleBasics)
|
||||
|
||||
// Fixtures is used to setup the testing environment
|
||||
type Fixtures struct {
|
||||
BuildDir string
|
||||
RootDir string
|
||||
SimdBinary string
|
||||
SimcliBinary string
|
||||
ChainID string
|
||||
RPCAddr string
|
||||
Port string
|
||||
SimdHome string
|
||||
SimcliHome string
|
||||
P2PAddr string
|
||||
Cdc *codec.Codec
|
||||
T *testing.T
|
||||
}
|
||||
|
||||
// NewFixtures creates a new instance of Fixtures with many vars set
|
||||
func NewFixtures(t *testing.T) *Fixtures {
|
||||
tmpDir, err := ioutil.TempDir("", "sdk_integration_"+t.Name()+"_")
|
||||
require.NoError(t, err)
|
||||
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
|
||||
p2pAddr, _, err := server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
|
||||
buildDir := os.Getenv("BUILDDIR")
|
||||
require.NotNil(t, buildDir)
|
||||
|
||||
return &Fixtures{
|
||||
T: t,
|
||||
BuildDir: buildDir,
|
||||
RootDir: tmpDir,
|
||||
SimdBinary: filepath.Join(buildDir, "simd"),
|
||||
SimcliBinary: filepath.Join(buildDir, "simcli"),
|
||||
SimdHome: filepath.Join(tmpDir, ".simd"),
|
||||
SimcliHome: filepath.Join(tmpDir, ".simcli"),
|
||||
RPCAddr: servAddr,
|
||||
P2PAddr: p2pAddr,
|
||||
Cdc: cdc,
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
// GenesisFile returns the path of the genesis file
|
||||
func (f Fixtures) GenesisFile() string {
|
||||
return filepath.Join(f.SimdHome, "config", "genesis.json")
|
||||
}
|
||||
|
||||
// GenesisFile returns the application's genesis state
|
||||
func (f Fixtures) GenesisState() simapp.GenesisState {
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(f.GenesisFile())
|
||||
require.NoError(f.T, err)
|
||||
|
||||
var appState simapp.GenesisState
|
||||
require.NoError(f.T, f.Cdc.UnmarshalJSON(genDoc.AppState, &appState))
|
||||
return appState
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
)
|
||||
|
||||
var (
|
||||
totalCoins = sdk.NewCoins(
|
||||
sdk.NewCoin(Fee2Denom, sdk.TokensFromConsensusPower(2000000)),
|
||||
sdk.NewCoin(FeeDenom, sdk.TokensFromConsensusPower(2000000)),
|
||||
sdk.NewCoin(FooDenom, sdk.TokensFromConsensusPower(2000)),
|
||||
sdk.NewCoin(Denom, sdk.TokensFromConsensusPower(300).Add(sdk.NewInt(12))), // add coins from inflation
|
||||
)
|
||||
|
||||
startCoins = sdk.NewCoins(
|
||||
sdk.NewCoin(Fee2Denom, sdk.TokensFromConsensusPower(1000000)),
|
||||
sdk.NewCoin(FeeDenom, sdk.TokensFromConsensusPower(1000000)),
|
||||
sdk.NewCoin(FooDenom, sdk.TokensFromConsensusPower(1000)),
|
||||
sdk.NewCoin(Denom, sdk.TokensFromConsensusPower(150)),
|
||||
)
|
||||
|
||||
vestingCoins = sdk.NewCoins(
|
||||
sdk.NewCoin(FeeDenom, sdk.TokensFromConsensusPower(500000)),
|
||||
)
|
||||
)
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// simd
|
||||
|
||||
// UnsafeResetAll is simd unsafe-reset-all
|
||||
func (f *Fixtures) UnsafeResetAll(flags ...string) {
|
||||
cmd := fmt.Sprintf("%s --home=%s unsafe-reset-all", f.SimdBinary, f.SimdHome)
|
||||
ExecuteWrite(f.T, AddFlags(cmd, flags))
|
||||
err := os.RemoveAll(filepath.Join(f.SimdHome, "config", "gentx"))
|
||||
require.NoError(f.T, err)
|
||||
}
|
||||
|
||||
// SDInit is simd init
|
||||
// NOTE: SDInit sets the ChainID for the Fixtures instance
|
||||
func (f *Fixtures) SDInit(moniker string, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s init -o --home=%s %s", f.SimdBinary, f.SimdHome, moniker)
|
||||
_, stderr := tests.ExecuteT(f.T, AddFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
|
||||
var chainID string
|
||||
var initRes map[string]json.RawMessage
|
||||
|
||||
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||
require.NoError(f.T, err)
|
||||
|
||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||
require.NoError(f.T, err)
|
||||
|
||||
f.ChainID = chainID
|
||||
}
|
||||
|
||||
// AddGenesisAccount is simd add-genesis-account
|
||||
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s add-genesis-account %s %s --home=%s --keyring-backend=test", f.SimdBinary, address, coins, f.SimdHome)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags))
|
||||
}
|
||||
|
||||
// GenTx is simd gentx
|
||||
func (f *Fixtures) GenTx(name string, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s --keyring-backend=test", f.SimdBinary, name, f.SimdHome, f.SimcliHome)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags))
|
||||
}
|
||||
|
||||
// CollectGenTxs is simd collect-gentxs
|
||||
func (f *Fixtures) CollectGenTxs(flags ...string) {
|
||||
cmd := fmt.Sprintf("%s collect-gentxs --home=%s", f.SimdBinary, f.SimdHome)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags))
|
||||
}
|
||||
|
||||
// SDStart runs simd start with the appropriate flags and returns a process
|
||||
func (f *Fixtures) SDStart(flags ...string) *tests.Process {
|
||||
cmd := fmt.Sprintf("%s start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.SimdBinary, f.SimdHome, f.RPCAddr, f.P2PAddr)
|
||||
proc := tests.GoExecuteTWithStdout(f.T, AddFlags(cmd, flags))
|
||||
tests.WaitForTMStart(f.Port)
|
||||
tests.WaitForNextNBlocksTM(1, f.Port)
|
||||
return proc
|
||||
}
|
||||
|
||||
// SDTendermint returns the results of simd tendermint [query]
|
||||
func (f *Fixtures) SDTendermint(query string) string {
|
||||
cmd := fmt.Sprintf("%s tendermint %s --home=%s", f.SimdBinary, query, f.SimdHome)
|
||||
success, stdout, stderr := ExecuteWriteRetStdStreams(f.T, cmd)
|
||||
require.Empty(f.T, stderr)
|
||||
require.True(f.T, success)
|
||||
return strings.TrimSpace(stdout)
|
||||
}
|
||||
|
||||
// ValidateGenesis runs simd validate-genesis
|
||||
func (f *Fixtures) ValidateGenesis() {
|
||||
cmd := fmt.Sprintf("%s validate-genesis --home=%s", f.SimdBinary, f.SimdHome)
|
||||
ExecuteWriteCheckErr(f.T, cmd)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// simcli keys
|
||||
|
||||
// KeysDelete is simcli keys delete
|
||||
func (f *Fixtures) KeysDelete(name string, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s keys delete --keyring-backend=test --home=%s %s", f.SimcliBinary,
|
||||
f.SimcliHome, name)
|
||||
ExecuteWrite(f.T, AddFlags(cmd, append(append(flags, "-y"), "-f")))
|
||||
}
|
||||
|
||||
// KeysAdd is simcli keys add
|
||||
func (f *Fixtures) KeysAdd(name string, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s %s", f.SimcliBinary,
|
||||
f.SimcliHome, name)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags))
|
||||
}
|
||||
|
||||
// KeysAddRecover prepares simcli keys add --recover
|
||||
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) {
|
||||
cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s --recover %s",
|
||||
f.SimcliBinary, f.SimcliHome, name)
|
||||
return ExecuteWriteRetStdStreams(f.T, AddFlags(cmd, flags), mnemonic)
|
||||
}
|
||||
|
||||
// KeysAddRecoverHDPath prepares simcli keys add --recover --account --index
|
||||
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s keys add --keyring-backend=test --home=%s --recover %s --account %d"+
|
||||
" --index %d", f.SimcliBinary, f.SimcliHome, name, account, index)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags), mnemonic)
|
||||
}
|
||||
|
||||
// KeysShow is simcli keys show
|
||||
func (f *Fixtures) KeysShow(name string, flags ...string) keyring.KeyOutput {
|
||||
cmd := fmt.Sprintf("%s keys show --keyring-backend=test --home=%s %s", f.SimcliBinary,
|
||||
f.SimcliHome, name)
|
||||
out, _ := tests.ExecuteT(f.T, AddFlags(cmd, flags), "")
|
||||
var ko keyring.KeyOutput
|
||||
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
|
||||
require.NoError(f.T, err)
|
||||
return ko
|
||||
}
|
||||
|
||||
// KeyAddress returns the SDK account address from the key
|
||||
func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
|
||||
ko := f.KeysShow(name)
|
||||
accAddr, err := sdk.AccAddressFromBech32(ko.Address)
|
||||
require.NoError(f.T, err)
|
||||
return accAddr
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// simcli config
|
||||
|
||||
// CLIConfig is simcli config
|
||||
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
|
||||
cmd := fmt.Sprintf("%s config --home=%s %s %s", f.SimcliBinary, f.SimcliHome, key, value)
|
||||
ExecuteWriteCheckErr(f.T, AddFlags(cmd, flags))
|
||||
}
|
||||
|
||||
// TxBroadcast is gaiacli tx broadcast
|
||||
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
|
||||
cmd := fmt.Sprintf("%s tx broadcast %v %v", f.SimcliBinary, f.Flags(), fileName)
|
||||
return ExecuteWriteRetStdStreams(f.T, AddFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// TxEncode is gaiacli tx encode
|
||||
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
|
||||
cmd := fmt.Sprintf("%s tx encode %v %v", f.SimcliBinary, f.Flags(), fileName)
|
||||
return ExecuteWriteRetStdStreams(f.T, AddFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
//utils
|
||||
|
||||
func AddFlags(cmd string, flags []string) string {
|
||||
for _, f := range flags {
|
||||
cmd += " " + f
|
||||
}
|
||||
return strings.TrimSpace(cmd)
|
||||
}
|
||||
|
||||
func UnmarshalStdTx(t *testing.T, c *codec.Codec, s string) (stdTx auth.StdTx) {
|
||||
require.Nil(t, c.UnmarshalJSON([]byte(s), &stdTx))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// InitFixtures is called at the beginning of a test and initializes a chain
|
||||
// with 1 validator.
|
||||
func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||
f = NewFixtures(t)
|
||||
|
||||
// reset test state
|
||||
f.UnsafeResetAll()
|
||||
|
||||
f.CLIConfig("keyring-backend", "test")
|
||||
|
||||
// ensure keystore has foo and bar keys
|
||||
f.KeysDelete(KeyFoo)
|
||||
f.KeysDelete(KeyBar)
|
||||
f.KeysDelete(KeyBar)
|
||||
f.KeysDelete(KeyFooBarBaz)
|
||||
f.KeysAdd(KeyFoo)
|
||||
f.KeysAdd(KeyBar)
|
||||
f.KeysAdd(KeyBaz)
|
||||
f.KeysAdd(KeyVesting)
|
||||
f.KeysAdd(KeyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
|
||||
"--multisig=%s,%s,%s", KeyFoo, KeyBar, KeyBaz))
|
||||
|
||||
// ensure that CLI output is in JSON format
|
||||
f.CLIConfig("output", "json")
|
||||
|
||||
// NOTE: SDInit sets the ChainID
|
||||
f.SDInit(KeyFoo)
|
||||
|
||||
f.CLIConfig("chain-id", f.ChainID)
|
||||
f.CLIConfig("broadcast-mode", "block")
|
||||
f.CLIConfig("trust-node", "true")
|
||||
|
||||
// start an account with tokens
|
||||
f.AddGenesisAccount(f.KeyAddress(KeyFoo), startCoins)
|
||||
f.AddGenesisAccount(
|
||||
f.KeyAddress(KeyVesting), startCoins,
|
||||
fmt.Sprintf("--vesting-amount=%s", vestingCoins),
|
||||
fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()),
|
||||
fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
|
||||
)
|
||||
|
||||
f.GenTx(KeyFoo)
|
||||
f.CollectGenTxs()
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Cleanup is meant to be run at the end of a test to clean up an remaining test state
|
||||
func (f *Fixtures) Cleanup(dirs ...string) {
|
||||
clean := append(dirs, f.RootDir)
|
||||
for _, d := range clean {
|
||||
require.NoError(f.T, os.RemoveAll(d))
|
||||
}
|
||||
}
|
||||
|
||||
// Flags returns the flags necessary for making most CLI calls
|
||||
func (f *Fixtures) Flags() string {
|
||||
return fmt.Sprintf("--home=%s --node=%s", f.SimcliHome, f.RPCAddr)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package tests
|
||||
|
||||
// package tests runs integration tests which make use of CLI commands.
|
||||
@@ -0,0 +1,39 @@
|
||||
// +build cli_test
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/tests/cli/helpers"
|
||||
)
|
||||
|
||||
func TestCLIKeysAddMultisig(t *testing.T) {
|
||||
t.Parallel()
|
||||
f := helpers.InitFixtures(t)
|
||||
|
||||
// key names order does not matter
|
||||
f.KeysAdd("msig1", "--multisig-threshold=2",
|
||||
fmt.Sprintf("--multisig=%s,%s", helpers.KeyBar, helpers.KeyBaz))
|
||||
ke1Address1 := f.KeysShow("msig1").Address
|
||||
f.KeysDelete("msig1")
|
||||
|
||||
f.KeysAdd("msig2", "--multisig-threshold=2",
|
||||
fmt.Sprintf("--multisig=%s,%s", helpers.KeyBaz, helpers.KeyBar))
|
||||
require.Equal(t, ke1Address1, f.KeysShow("msig2").Address)
|
||||
f.KeysDelete("msig2")
|
||||
|
||||
f.KeysAdd("msig3", "--multisig-threshold=2",
|
||||
fmt.Sprintf("--multisig=%s,%s", helpers.KeyBar, helpers.KeyBaz),
|
||||
"--nosort")
|
||||
f.KeysAdd("msig4", "--multisig-threshold=2",
|
||||
fmt.Sprintf("--multisig=%s,%s", helpers.KeyBaz, helpers.KeyBar),
|
||||
"--nosort")
|
||||
require.NotEqual(t, f.KeysShow("msig3").Address, f.KeysShow("msig4").Address)
|
||||
|
||||
// Cleanup testing directories
|
||||
f.Cleanup()
|
||||
}
|
||||
Reference in New Issue
Block a user