neotest: improve neotest API
Added several methods that are useful for testing.
This commit is contained in:
parent
5061a813c6
commit
dcb06163da
3 changed files with 81 additions and 0 deletions
|
@ -3,6 +3,7 @@ package neotest
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -62,6 +63,14 @@ func (e *Executor) NativeHash(t *testing.T, name string) util.Uint160 {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NativeID returns native contract ID by name.
|
||||||
|
func (e *Executor) NativeID(t *testing.T, name string) int32 {
|
||||||
|
h := e.NativeHash(t, name)
|
||||||
|
cs := e.Chain.GetContractState(h)
|
||||||
|
require.NotNil(t, cs)
|
||||||
|
return cs.ID
|
||||||
|
}
|
||||||
|
|
||||||
// NewUnsignedTx creates new unsigned transaction which invokes method of contract with hash.
|
// NewUnsignedTx creates new unsigned transaction which invokes method of contract with hash.
|
||||||
func (e *Executor) NewUnsignedTx(t *testing.T, hash util.Uint160, method string, args ...interface{}) *transaction.Transaction {
|
func (e *Executor) NewUnsignedTx(t *testing.T, hash util.Uint160, method string, args ...interface{}) *transaction.Transaction {
|
||||||
w := io.NewBufBinWriter()
|
w := io.NewBufBinWriter()
|
||||||
|
@ -202,6 +211,12 @@ func (e *Executor) CheckTxNotificationEvent(t *testing.T, h util.Uint256, index
|
||||||
require.Equal(t, expected, aer[0].Events[index])
|
require.Equal(t, expected, aer[0].Events[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckGASBalance ensures that provided account owns specified amount of GAS.
|
||||||
|
func (e *Executor) CheckGASBalance(t *testing.T, acc util.Uint160, expected *big.Int) {
|
||||||
|
actual := e.Chain.GetUtilityTokenBalance(acc)
|
||||||
|
require.Equal(t, expected, actual, fmt.Errorf("invalid GAS balance: expected %s, got %s", expected.String(), actual.String()))
|
||||||
|
}
|
||||||
|
|
||||||
// NewDeployTx returns new deployment tx for contract signed by committee.
|
// NewDeployTx returns new deployment tx for contract signed by committee.
|
||||||
func (e *Executor) NewDeployTx(t *testing.T, bc blockchainer.Blockchainer, c *Contract, data interface{}) *transaction.Transaction {
|
func (e *Executor) NewDeployTx(t *testing.T, bc blockchainer.Blockchainer, c *Contract, data interface{}) *transaction.Transaction {
|
||||||
rawManifest, err := json.Marshal(c.Manifest)
|
rawManifest, err := json.Marshal(c.Manifest)
|
||||||
|
@ -277,6 +292,13 @@ func (e *Executor) AddNewBlock(t *testing.T, txs ...*transaction.Transaction) *b
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateNewBlocks adds specified number of empty blocks to the chain.
|
||||||
|
func (e *Executor) GenerateNewBlocks(t *testing.T, count int) {
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
e.AddNewBlock(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SignBlock add validators signature to b.
|
// SignBlock add validators signature to b.
|
||||||
func (e *Executor) SignBlock(b *block.Block) *block.Block {
|
func (e *Executor) SignBlock(b *block.Block) *block.Block {
|
||||||
invoc := e.Validator.SignHashable(uint32(e.Chain.GetConfig().Magic), b)
|
invoc := e.Validator.SignHashable(uint32(e.Chain.GetConfig().Magic), b)
|
||||||
|
@ -316,3 +338,27 @@ func TestInvoke(bc blockchainer.Blockchainer, tx *transaction.Transaction) (*vm.
|
||||||
err = v.Run()
|
err = v.Run()
|
||||||
return v, err
|
return v, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTransaction returns transaction and its height by the specified hash.
|
||||||
|
func (e *Executor) GetTransaction(t *testing.T, h util.Uint256) (*transaction.Transaction, uint32) {
|
||||||
|
tx, height, err := e.Chain.GetTransaction(h)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return tx, height
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockByIndex returns block by the specified index.
|
||||||
|
func (e *Executor) GetBlockByIndex(t *testing.T, idx int) *block.Block {
|
||||||
|
h := e.Chain.GetHeaderHash(idx)
|
||||||
|
require.NotEmpty(t, h)
|
||||||
|
b, err := e.Chain.GetBlock(h)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTxExecResult returns application execution results for the specified transaction.
|
||||||
|
func (e *Executor) GetTxExecResult(t *testing.T, h util.Uint256) *state.AppExecResult {
|
||||||
|
aer, err := e.Chain.GetAppExecResults(h, trigger.Application)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(aer))
|
||||||
|
return &aer[0]
|
||||||
|
}
|
||||||
|
|
|
@ -108,14 +108,24 @@ func init() {
|
||||||
// NewSingle creates new blockchain instance with a single validator and
|
// NewSingle creates new blockchain instance with a single validator and
|
||||||
// setups cleanup functions.
|
// setups cleanup functions.
|
||||||
func NewSingle(t *testing.T) (*core.Blockchain, neotest.Signer) {
|
func NewSingle(t *testing.T) (*core.Blockchain, neotest.Signer) {
|
||||||
|
return NewSingleWithCustomConfig(t, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSingleWithCustomConfig creates new blockchain instance with custom protocol
|
||||||
|
// configuration and a single validator. It also setups cleanup functions.
|
||||||
|
func NewSingleWithCustomConfig(t *testing.T, f func(*config.ProtocolConfiguration)) (*core.Blockchain, neotest.Signer) {
|
||||||
protoCfg := config.ProtocolConfiguration{
|
protoCfg := config.ProtocolConfiguration{
|
||||||
Magic: netmode.UnitTestNet,
|
Magic: netmode.UnitTestNet,
|
||||||
|
MaxTraceableBlocks: 1000, // We don't need a lot of traceable blocks for tests.
|
||||||
SecondsPerBlock: 1,
|
SecondsPerBlock: 1,
|
||||||
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PrivateKey().PublicKey().Bytes())},
|
StandbyCommittee: []string{hex.EncodeToString(committeeAcc.PrivateKey().PublicKey().Bytes())},
|
||||||
ValidatorsCount: 1,
|
ValidatorsCount: 1,
|
||||||
VerifyBlocks: true,
|
VerifyBlocks: true,
|
||||||
VerifyTransactions: true,
|
VerifyTransactions: true,
|
||||||
}
|
}
|
||||||
|
if f != nil {
|
||||||
|
f(&protoCfg)
|
||||||
|
}
|
||||||
|
|
||||||
st := storage.NewMemoryStore()
|
st := storage.NewMemoryStore()
|
||||||
log := zaptest.NewLogger(t)
|
log := zaptest.NewLogger(t)
|
||||||
|
@ -129,6 +139,13 @@ func NewSingle(t *testing.T) (*core.Blockchain, neotest.Signer) {
|
||||||
// NewMulti creates new blockchain instance with 4 validators and 6 committee members.
|
// NewMulti creates new blockchain instance with 4 validators and 6 committee members.
|
||||||
// Second return value is for validator signer, third -- for committee.
|
// Second return value is for validator signer, third -- for committee.
|
||||||
func NewMulti(t *testing.T) (*core.Blockchain, neotest.Signer, neotest.Signer) {
|
func NewMulti(t *testing.T) (*core.Blockchain, neotest.Signer, neotest.Signer) {
|
||||||
|
return NewMultiWithCustomConfig(t, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMultiWithCustomConfig creates new blockchain instance with custom protocol
|
||||||
|
// configuration, 4 validators and 6 committee members. Second return value is
|
||||||
|
// for validator signer, third -- for committee.
|
||||||
|
func NewMultiWithCustomConfig(t *testing.T, f func(*config.ProtocolConfiguration)) (*core.Blockchain, neotest.Signer, neotest.Signer) {
|
||||||
protoCfg := config.ProtocolConfiguration{
|
protoCfg := config.ProtocolConfiguration{
|
||||||
Magic: netmode.UnitTestNet,
|
Magic: netmode.UnitTestNet,
|
||||||
SecondsPerBlock: 1,
|
SecondsPerBlock: 1,
|
||||||
|
@ -137,6 +154,9 @@ func NewMulti(t *testing.T) (*core.Blockchain, neotest.Signer, neotest.Signer) {
|
||||||
VerifyBlocks: true,
|
VerifyBlocks: true,
|
||||||
VerifyTransactions: true,
|
VerifyTransactions: true,
|
||||||
}
|
}
|
||||||
|
if f != nil {
|
||||||
|
f(&protoCfg)
|
||||||
|
}
|
||||||
|
|
||||||
st := storage.NewMemoryStore()
|
st := storage.NewMemoryStore()
|
||||||
log := zaptest.NewLogger(t)
|
log := zaptest.NewLogger(t)
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContractInvoker is a client for specific contract.
|
// ContractInvoker is a client for specific contract.
|
||||||
|
@ -65,6 +66,20 @@ func (c *ContractInvoker) Invoke(t *testing.T, result interface{}, method string
|
||||||
return tx.Hash()
|
return tx.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InvokeAndCheck invokes method with args, persists transaction and checks the result
|
||||||
|
// using provided function. Returns transaction hash.
|
||||||
|
func (c *ContractInvoker) InvokeAndCheck(t *testing.T, checkResult func(t *testing.T, stack []stackitem.Item), method string, args ...interface{}) util.Uint256 {
|
||||||
|
tx := c.PrepareInvoke(t, method, args...)
|
||||||
|
c.AddNewBlock(t, tx)
|
||||||
|
aer, err := c.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, vm.HaltState, aer[0].VMState, aer[0].FaultException)
|
||||||
|
if checkResult != nil {
|
||||||
|
checkResult(t, aer[0].Stack)
|
||||||
|
}
|
||||||
|
return tx.Hash()
|
||||||
|
}
|
||||||
|
|
||||||
// InvokeWithFeeFail is like InvokeFail but sets custom system fee for the transaction.
|
// InvokeWithFeeFail is like InvokeFail but sets custom system fee for the transaction.
|
||||||
func (c *ContractInvoker) InvokeWithFeeFail(t *testing.T, message string, sysFee int64, method string, args ...interface{}) util.Uint256 {
|
func (c *ContractInvoker) InvokeWithFeeFail(t *testing.T, message string, sysFee int64, method string, args ...interface{}) util.Uint256 {
|
||||||
tx := c.PrepareInvokeNoSign(t, method, args...)
|
tx := c.PrepareInvokeNoSign(t, method, args...)
|
||||||
|
|
Loading…
Reference in a new issue