package mock_test import ( "context" "errors" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/example/kvstore" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/bytes" "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/client/mock" "github.com/tendermint/tendermint/rpc/coretypes" "github.com/tendermint/tendermint/types" ) func TestABCIMock(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() key, value := []byte("foo"), []byte("bar") height := int64(10) goodTx := types.Tx{0x01, 0xff} badTx := types.Tx{0x12, 0x21} m := mock.ABCIMock{ Info: mock.Call{Error: errors.New("foobar")}, Query: mock.Call{Response: abci.ResponseQuery{ Key: key, Value: value, Height: height, }}, // Broadcast commit depends on call BroadcastCommit: mock.Call{ Args: goodTx, Response: &coretypes.ResultBroadcastTxCommit{ CheckTx: abci.ResponseCheckTx{Data: bytes.HexBytes("stand")}, TxResult: abci.ExecTxResult{Data: bytes.HexBytes("deliver")}, }, Error: errors.New("bad tx"), }, Broadcast: mock.Call{Error: errors.New("must commit")}, } // now, let's try to make some calls _, err := m.ABCIInfo(ctx) require.Error(t, err) assert.Equal(t, "foobar", err.Error()) // query always returns the response _query, err := m.ABCIQueryWithOptions(ctx, "/", nil, client.ABCIQueryOptions{Prove: false}) query := _query.Response require.NoError(t, err) require.NotNil(t, query) assert.EqualValues(t, key, query.Key) assert.EqualValues(t, value, query.Value) assert.Equal(t, height, query.Height) // non-commit calls always return errors _, err = m.BroadcastTxSync(ctx, goodTx) require.Error(t, err) assert.Equal(t, "must commit", err.Error()) _, err = m.BroadcastTxAsync(ctx, goodTx) require.Error(t, err) assert.Equal(t, "must commit", err.Error()) // commit depends on the input _, err = m.BroadcastTxCommit(ctx, badTx) require.Error(t, err) assert.Equal(t, "bad tx", err.Error()) bres, err := m.BroadcastTxCommit(ctx, goodTx) require.NoError(t, err, "%+v", err) assert.EqualValues(t, 0, bres.CheckTx.Code) assert.EqualValues(t, "stand", bres.CheckTx.Data) assert.EqualValues(t, "deliver", bres.TxResult.Data) } func TestABCIRecorder(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() // This mock returns errors on everything but Query m := mock.ABCIMock{ Info: mock.Call{Response: abci.ResponseInfo{ Data: "data", Version: "v0.9.9", }}, Query: mock.Call{Error: errors.New("query")}, Broadcast: mock.Call{Error: errors.New("broadcast")}, BroadcastCommit: mock.Call{Error: errors.New("broadcast_commit")}, } r := mock.NewABCIRecorder(m) require.Equal(t, 0, len(r.Calls)) _, err := r.ABCIInfo(ctx) assert.NoError(t, err, "expected no err on info") _, err = r.ABCIQueryWithOptions( ctx, "path", bytes.HexBytes("data"), client.ABCIQueryOptions{Prove: false}, ) assert.Error(t, err, "expected error on query") require.Equal(t, 2, len(r.Calls)) info := r.Calls[0] assert.Equal(t, "abci_info", info.Name) assert.Nil(t, info.Error) assert.Nil(t, info.Args) require.NotNil(t, info.Response) ir, ok := info.Response.(*coretypes.ResultABCIInfo) require.True(t, ok) assert.Equal(t, "data", ir.Response.Data) assert.Equal(t, "v0.9.9", ir.Response.Version) query := r.Calls[1] assert.Equal(t, "abci_query", query.Name) assert.Nil(t, query.Response) require.NotNil(t, query.Error) assert.Equal(t, "query", query.Error.Error()) require.NotNil(t, query.Args) qa, ok := query.Args.(mock.QueryArgs) require.True(t, ok) assert.Equal(t, "path", qa.Path) assert.EqualValues(t, "data", qa.Data) assert.False(t, qa.Prove) // now add some broadcasts (should all err) txs := []types.Tx{{1}, {2}, {3}} _, err = r.BroadcastTxCommit(ctx, txs[0]) assert.Error(t, err, "expected err on broadcast") _, err = r.BroadcastTxSync(ctx, txs[1]) assert.Error(t, err, "expected err on broadcast") _, err = r.BroadcastTxAsync(ctx, txs[2]) assert.Error(t, err, "expected err on broadcast") require.Equal(t, 5, len(r.Calls)) bc := r.Calls[2] assert.Equal(t, "broadcast_tx_commit", bc.Name) assert.Nil(t, bc.Response) require.NotNil(t, bc.Error) assert.EqualValues(t, bc.Args, txs[0]) bs := r.Calls[3] assert.Equal(t, "broadcast_tx_sync", bs.Name) assert.Nil(t, bs.Response) require.NotNil(t, bs.Error) assert.EqualValues(t, bs.Args, txs[1]) ba := r.Calls[4] assert.Equal(t, "broadcast_tx_async", ba.Name) assert.Nil(t, ba.Response) require.NotNil(t, ba.Error) assert.EqualValues(t, ba.Args, txs[2]) } func TestABCIApp(t *testing.T) { app := kvstore.NewApplication() m := mock.ABCIApp{app} ctx, cancel := context.WithCancel(context.Background()) defer cancel() // get some info info, err := m.ABCIInfo(ctx) require.NoError(t, err) assert.Equal(t, `{"size":0}`, info.Response.GetData()) // add a key key, value := "foo", "bar" tx := fmt.Sprintf("%s=%s", key, value) res, err := m.BroadcastTxCommit(ctx, types.Tx(tx)) require.NoError(t, err) assert.True(t, res.CheckTx.IsOK()) require.NotNil(t, res.TxResult) assert.True(t, res.TxResult.IsOK()) // commit // TODO: This may not be necessary in the future if res.Height == -1 { m.App.Commit() } // check the key _qres, err := m.ABCIQueryWithOptions( ctx, "/key", bytes.HexBytes(key), client.ABCIQueryOptions{Prove: true}, ) qres := _qres.Response require.NoError(t, err) assert.EqualValues(t, value, qres.Value) // XXX Check proof }