system

package module
v0.0.0-...-38dffb8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 22, 2023 License: MIT Imports: 31 Imported by: 0

README

Testing

Test framework for system tests. Starts and interacts with a (multi node) blockchain in Go. Supports

  • CLI
  • Servers
  • Events
  • RPC

Uses:

  • testify
  • gjson
  • sjson Server and client side are executed on the host machine

Developer

Test strategy

System tests cover the full stack via cli and a running (multi node) network. They are more expensive (in terms of time/ cpu) to run compared to unit or integration tests. Therefore, we focus on the critical path and do not cover every condition.

Execute a single test
go test -tags system_test -count=1 -v ./testing --run TestSmokeTest  -verbose
  • Force a binary rebuild before running the test
go test -tags system_test -count=1 -v ./testing --run TestSmokeTest  -verbose -rebuild

Test cli parameters

  • -verbose verbose output
  • -rebuild - rebuild artifacts
  • -wait-time duration - time to wait for chain events (default 30s)
  • -nodes-count int - number of nodes in the cluster (default 4)

Port ranges

With n nodes:

  • 26657 - 26657+n - RPC
  • 1317 - 1317+n - API
  • 9090 - 9090+n - GRPC
  • 16656 - 16656+n - P2P

For example Node 3 listens on 26660 for RPC calls

Resources

Disclaimer

The initial code was contributed from the Tgrade project. The idea was inspired by the work of the e-money team on their system tests. Thank you!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetGenesisBalance

func GetGenesisBalance(rawGenesis []byte, addr string) sdk.Coins

GetGenesisBalance return the balance amount for an address from the given genesis json

func RequireTxFailure

func RequireTxFailure(t *testing.T, got string, containsMsgs ...string)

RequireTxFailure require the received response to contain any failure code and the passed msgsgs

func RequireTxSuccess

func RequireTxSuccess(t *testing.T, got string)

RequireTxSuccess require the received response to contain the success code

Types

type CleanupFn

type CleanupFn func()

type EventConsumer

type EventConsumer func(e ctypes.ResultEvent) (more bool)

func CaptureAllEventsConsumer

func CaptureAllEventsConsumer(t *testing.T, optMaxWaitTime ...time.Duration) (c EventConsumer, done func() []ctypes.ResultEvent)

CaptureAllEventsConsumer is an `EventConsumer` that captures all events until `done()` is called to stop or timeout happens. The consumer works async in the background and returns all the captured events when `done()` is called. This can be used to verify that certain events have happened. Example usage:

	c, done := CaptureAllEventsConsumer(t)
	query := `tm.event='Tx'`
	cleanupFn := l.Subscribe(query, c)
	t.Cleanup(cleanupFn)

 // do something in your test that create events

	assert.Len(t, done(), 1) // then verify your assumption

func CaptureSingleEventConsumer

func CaptureSingleEventConsumer() (EventConsumer, *ctypes.ResultEvent)

CaptureSingleEventConsumer consumes one event. No timeout

func TimeoutConsumer

func TimeoutConsumer(t *testing.T, maxWaitTime time.Duration, next EventConsumer) EventConsumer

TimeoutConsumer is an event consumer decorator with a max wait time. Panics when wait time exceeded without a result returned

type EventListener

type EventListener struct {
	// contains filtered or unexported fields
}

EventListener watches for events on the chain

func NewEventListener

func NewEventListener(t *testing.T, rpcAddr string) *EventListener

NewEventListener event listener

func (*EventListener) AwaitQuery

func (l *EventListener) AwaitQuery(query string, optMaxWaitTime ...time.Duration) *ctypes.ResultEvent

AwaitQuery blocks and waits for a single result or timeout. This can be used with `broadcast-mode=async`. For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events

func (*EventListener) Subscribe

func (l *EventListener) Subscribe(query string, cb EventConsumer) func()

Subscribe to receive events for a topic. Does not block. For query syntax See https://docs.cosmos.network/master/core/events.html#subscribing-to-events

type GenesisMutator

type GenesisMutator func([]byte) []byte

func SetConsensusMaxGas

func SetConsensusMaxGas(t *testing.T, max int) GenesisMutator

SetConsensusMaxGas max gas that can be consumed in a block

type Node

type Node struct {
	ID      string
	IP      string
	RPCPort int
	P2PPort int
}

func (Node) PeerAddr

func (n Node) PeerAddr() string

func (Node) RPCAddr

func (n Node) RPCAddr() string

type RPCClient

type RPCClient struct {
	// contains filtered or unexported fields
}

RPCClient is a test helper to interact with a node via the RPC endpoint.

func NewRPCClient

func NewRPCClient(t *testing.T, addr string) RPCClient

NewRPCClient constructor

func (RPCClient) Validators

func (r RPCClient) Validators() []*cmtypes.Validator

Validators returns list of validators

type RunErrorAssert

type RunErrorAssert func(t assert.TestingT, err error, msgAndArgs ...interface{}) (ok bool)

RunErrorAssert is custom type that is satisfies by testify matchers as well

var (
	// ErrOutOfGasMatcher requires error with "out of gas" message
	ErrOutOfGasMatcher RunErrorAssert = func(t assert.TestingT, err error, args ...interface{}) bool {
		const oogMsg = "out of gas"
		return expErrWithMsg(t, err, args, oogMsg)
	}
	// ErrTimeoutMatcher requires time out message
	ErrTimeoutMatcher RunErrorAssert = func(t assert.TestingT, err error, args ...interface{}) bool {
		const expMsg = "timed out waiting for tx to be included in a block"
		return expErrWithMsg(t, err, args, expMsg)
	}
	// ErrPostFailedMatcher requires post failed
	ErrPostFailedMatcher RunErrorAssert = func(t assert.TestingT, err error, args ...interface{}) bool {
		const expMsg = "post failed"
		return expErrWithMsg(t, err, args, expMsg)
	}
	// ErrInvalidQuery requires smart query request failed
	ErrInvalidQuery RunErrorAssert = func(t assert.TestingT, err error, args ...interface{}) bool {
		const expMsg = "query wasm contract failed"
		return expErrWithMsg(t, err, args, expMsg)
	}
)

type SystemUnderTest

type SystemUnderTest struct {
	ChainStarted bool
	// contains filtered or unexported fields
}

SystemUnderTest blockchain provisioning

func NewSystemUnderTest

func NewSystemUnderTest(execBinary string, verbose bool, nodesCount int, blockTime time.Duration) *SystemUnderTest

func (*SystemUnderTest) AddFullnode

func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumber int, nodePath string)) Node

AddFullnode starts a new fullnode that connects to the existing chain but is not a validator.

func (SystemUnderTest) AllNodes

func (s SystemUnderTest) AllNodes(t *testing.T) []Node

func (SystemUnderTest) AllPeers

func (s SystemUnderTest) AllPeers(t *testing.T) []string

func (*SystemUnderTest) AwaitNextBlock

func (s *SystemUnderTest) AwaitNextBlock(t *testing.T, timeout ...time.Duration) int64

AwaitNextBlock is a first class function that any caller can use to ensure a new block was minted. Returns the new height

func (*SystemUnderTest) AwaitNodeUp

func (s *SystemUnderTest) AwaitNodeUp(t *testing.T, rpcAddr string)

AwaitNodeUp ensures the node is running

func (SystemUnderTest) BuildNewBinary

func (s SystemUnderTest) BuildNewBinary()

BuildNewBinary builds and installs new executable binary

func (*SystemUnderTest) ForEachNodeExecAndWait

func (s *SystemUnderTest) ForEachNodeExecAndWait(t *testing.T, cmds ...[]string) [][]string

ForEachNodeExecAndWait runs the given app executable commands for all cluster nodes synchronously The commands output is returned for each node.

func (SystemUnderTest) IsDirty

func (s SystemUnderTest) IsDirty() bool

IsDirty true when non default genesis or other state modification were applied that might create incompatibility for tests

func (SystemUnderTest) Log

func (s SystemUnderTest) Log(msg string)

func (SystemUnderTest) Logf

func (s SystemUnderTest) Logf(msg string, args ...interface{})

func (*SystemUnderTest) MarkDirty

func (s *SystemUnderTest) MarkDirty()

MarkDirty whole chain will be reset when marked dirty

func (*SystemUnderTest) ModifyGenesisCLI

func (s *SystemUnderTest) ModifyGenesisCLI(t *testing.T, cmds ...[]string)

ModifyGenesisCLI executes the CLI commands to modify the genesis

func (*SystemUnderTest) ModifyGenesisJSON

func (s *SystemUnderTest) ModifyGenesisJSON(t *testing.T, mutators ...GenesisMutator)

ModifyGenesisJSON resets the chain and executes the callbacks to update the json representation The mutator callbacks after each other receive the genesis as raw bytes and return the updated genesis for the next. example:

return func(genesis []byte) []byte {
	val, _ := json.Marshal(sdk.NewDecCoins(fees...))
	state, _ := sjson.SetRawBytes(genesis, "app_state.globalfee.params.minimum_gas_prices", val)
	return state
}

func (*SystemUnderTest) NewEventListener

func (s *SystemUnderTest) NewEventListener(t *testing.T) *EventListener

NewEventListener constructor for Eventlistener with system rpc address

func (SystemUnderTest) PrintBuffer

func (s SystemUnderTest) PrintBuffer()

PrintBuffer prints the chain logs to the console

func (SystemUnderTest) RPCClient

func (s SystemUnderTest) RPCClient(t *testing.T) RPCClient

func (*SystemUnderTest) ReadGenesisJSON

func (s *SystemUnderTest) ReadGenesisJSON(t *testing.T) string

ReadGenesisJSON returns current genesis.json content as raw string

func (*SystemUnderTest) ResetChain

func (s *SystemUnderTest) ResetChain(t *testing.T)

ResetChain stops and clears all nodes state via 'unsafe-reset-all'

func (*SystemUnderTest) ResetDirtyChain

func (s *SystemUnderTest) ResetDirtyChain(t *testing.T)

ResetDirtyChain reset chain when non default setup or state (dirty)

func (*SystemUnderTest) SetupChain

func (s *SystemUnderTest) SetupChain()

func (*SystemUnderTest) StartChain

func (s *SystemUnderTest) StartChain(t *testing.T, xargs ...string)

func (*SystemUnderTest) StopChain

func (s *SystemUnderTest) StopChain()

StopChain stops the system under test and executes all registered cleanup callbacks

type WasmdCli

type WasmdCli struct {
	Debug bool
	// contains filtered or unexported fields
}

WasmdCli wraps the command line interface

func NewWasmdCLI

func NewWasmdCLI(t *testing.T, sut *SystemUnderTest, verbose bool) *WasmdCli

NewWasmdCLI constructor

func NewWasmdCLIx

func NewWasmdCLIx(
	t *testing.T,
	execBinary string,
	nodeAddress string,
	chainID string,
	awaiter awaitNextBlock,
	homeDir string,
	fees string,
	debug bool,
	assertErrorFn RunErrorAssert,
	expTXCommitted bool,
) *WasmdCli

NewWasmdCLIx extended constructor

func (WasmdCli) AddKey

func (c WasmdCli) AddKey(name string) string

AddKey add key to default keyring. Returns address

func (WasmdCli) CustomCommand

func (c WasmdCli) CustomCommand(args ...string) string

CustomCommand main entry for executing wasmd cli commands. When configured, method blocks until tx is committed.

func (WasmdCli) CustomQuery

func (c WasmdCli) CustomQuery(args ...string) string

CustomQuery main entrypoint for wasmd CLI queries

func (WasmdCli) FundAddress

func (c WasmdCli) FundAddress(destAddr, amount string) string

FundAddress sends the token amount to the destination address

func (WasmdCli) GetKeyAddr

func (c WasmdCli) GetKeyAddr(name string) string

GetKeyAddr returns address

func (WasmdCli) GetTendermintValidatorSet

func (c WasmdCli) GetTendermintValidatorSet() rpc.ResultValidatorsOutput

func (WasmdCli) IsInTendermintValset

func (c WasmdCli) IsInTendermintValset(valPubKey cryptotypes.PubKey) (rpc.ResultValidatorsOutput, bool)

IsInTendermintValset returns true when the given pub key is in the current active tendermint validator set

func (WasmdCli) Keys

func (c WasmdCli) Keys(args ...string) string

Keys wasmd keys CLI command

func (WasmdCli) QueryBalance

func (c WasmdCli) QueryBalance(addr, denom string) int64

QueryBalance returns balance amount for given denom. 0 when not found

func (WasmdCli) QueryBalances

func (c WasmdCli) QueryBalances(addr string) string

QueryBalances queries all balances for an account. Returns json response Example:`{"balances":[{"denom":"node0token","amount":"1000000000"},{"denom":"stake","amount":"400000003"}],"pagination":{}}`

func (WasmdCli) QuerySmart

func (c WasmdCli) QuerySmart(contractAddr, msg string, args ...string) string

QuerySmart run smart contract query

func (WasmdCli) QueryTotalSupply

func (c WasmdCli) QueryTotalSupply(denom string) int64

QueryTotalSupply returns total amount of tokens for a given denom. 0 when not found

func (WasmdCli) WasmExecute

func (c WasmdCli) WasmExecute(contractAddr, msg, from string, args ...string) string

WasmExecute send MsgExecute to a contract

func (WasmdCli) WasmInstantiate

func (c WasmdCli) WasmInstantiate(codeID int, initMsg string, args ...string) string

WasmInstantiate create a new contract instance. returns contract address

func (WasmdCli) WasmStore

func (c WasmdCli) WasmStore(file string, args ...string) int

WasmStore uploads a wasm contract to the chain. Returns code id

func (WasmdCli) WithAssertTXUncommitted

func (c WasmdCli) WithAssertTXUncommitted() WasmdCli

func (WasmdCli) WithNodeAddress

func (c WasmdCli) WithNodeAddress(nodeAddr string) WasmdCli

func (WasmdCli) WithRunErrorMatcher

func (c WasmdCli) WithRunErrorMatcher(f RunErrorAssert) WasmdCli

WithRunErrorMatcher assert function to ensure run command error value

func (WasmdCli) WithRunErrorsIgnored

func (c WasmdCli) WithRunErrorsIgnored() WasmdCli

WithRunErrorsIgnored does not fail on any error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL