tendermint/example/kvstore/kvstore_test.go

311 lines
7.9 KiB
Go
Raw Normal View History

2018-02-19 12:34:51 -08:00
package kvstore
2016-11-21 20:42:42 -08:00
import (
"bytes"
"io/ioutil"
"sort"
"testing"
"github.com/stretchr/testify/require"
2017-11-30 12:37:31 -08:00
cmn "github.com/tendermint/tmlibs/common"
2017-04-27 13:37:18 -07:00
"github.com/tendermint/tmlibs/log"
2017-11-30 12:37:31 -08:00
abcicli "github.com/tendermint/abci/client"
"github.com/tendermint/abci/example/code"
abciserver "github.com/tendermint/abci/server"
"github.com/tendermint/abci/types"
2016-11-21 20:42:42 -08:00
)
2018-02-19 12:34:51 -08:00
func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) {
ar := app.DeliverTx(tx)
require.False(t, ar.IsErr(), ar)
// repeating tx doesn't raise error
ar = app.DeliverTx(tx)
require.False(t, ar.IsErr(), ar)
2016-11-21 20:42:42 -08:00
// make sure query is fine
resQuery := app.Query(types.RequestQuery{
Path: "/store",
Data: []byte(key),
})
2017-11-30 12:37:31 -08:00
require.Equal(t, code.CodeTypeOK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value))
// make sure proof is fine
resQuery = app.Query(types.RequestQuery{
Path: "/store",
Data: []byte(key),
Prove: true,
})
2017-11-30 12:37:31 -08:00
require.EqualValues(t, code.CodeTypeOK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value))
2016-11-21 20:42:42 -08:00
}
2018-02-19 12:34:51 -08:00
func TestKVStoreKV(t *testing.T) {
kvstore := NewKVStoreApplication()
2016-11-21 20:42:42 -08:00
key := "abc"
value := key
tx := []byte(key)
2018-02-19 12:34:51 -08:00
testKVStore(t, kvstore, tx, key, value)
2016-11-21 20:42:42 -08:00
value = "def"
tx = []byte(key + "=" + value)
2018-02-19 12:34:51 -08:00
testKVStore(t, kvstore, tx, key, value)
2016-11-21 20:42:42 -08:00
}
2018-02-19 12:34:51 -08:00
func TestPersistentKVStoreKV(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
2016-11-21 20:42:42 -08:00
if err != nil {
t.Fatal(err)
}
2018-02-19 12:34:51 -08:00
kvstore := NewPersistentKVStoreApplication(dir)
2016-11-21 20:42:42 -08:00
key := "abc"
value := key
tx := []byte(key)
2018-02-19 12:34:51 -08:00
testKVStore(t, kvstore, tx, key, value)
2016-11-21 20:42:42 -08:00
value = "def"
tx = []byte(key + "=" + value)
2018-02-19 12:34:51 -08:00
testKVStore(t, kvstore, tx, key, value)
2016-11-21 20:42:42 -08:00
}
2018-02-19 12:34:51 -08:00
func TestPersistentKVStoreInfo(t *testing.T) {
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
2016-11-21 20:42:42 -08:00
if err != nil {
t.Fatal(err)
}
2018-02-19 12:34:51 -08:00
kvstore := NewPersistentKVStoreApplication(dir)
InitKVStore(kvstore)
2017-11-30 21:41:07 -08:00
height := int64(0)
2016-11-21 20:42:42 -08:00
2018-02-19 12:34:51 -08:00
resInfo := kvstore.Info(types.RequestInfo{})
2016-12-26 17:44:36 -08:00
if resInfo.LastBlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
2016-11-21 20:42:42 -08:00
}
// make and apply block
2017-11-30 21:41:07 -08:00
height = int64(1)
2016-11-21 20:42:42 -08:00
hash := []byte("foo")
header := types.Header{
2017-11-30 21:41:07 -08:00
Height: int64(height),
2016-11-21 20:42:42 -08:00
}
2018-02-19 12:34:51 -08:00
kvstore.BeginBlock(types.RequestBeginBlock{hash, header, nil, nil})
kvstore.EndBlock(types.RequestEndBlock{header.Height})
kvstore.Commit()
2016-11-21 20:42:42 -08:00
2018-02-19 12:34:51 -08:00
resInfo = kvstore.Info(types.RequestInfo{})
2016-12-26 17:44:36 -08:00
if resInfo.LastBlockHeight != height {
t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
2016-11-21 20:42:42 -08:00
}
}
// add a validator, remove a validator, update a validator
func TestValUpdates(t *testing.T) {
2018-02-19 12:34:51 -08:00
dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
2016-11-21 20:42:42 -08:00
if err != nil {
t.Fatal(err)
}
2018-02-19 12:34:51 -08:00
kvstore := NewPersistentKVStoreApplication(dir)
2016-11-21 20:42:42 -08:00
// init with some validators
total := 10
nInit := 5
vals := RandVals(total)
2016-11-21 20:42:42 -08:00
// iniitalize with the first nInit
2018-02-19 12:34:51 -08:00
kvstore.InitChain(types.RequestInitChain{
2018-02-16 16:49:33 -08:00
Validators: vals[:nInit],
})
2016-11-21 20:42:42 -08:00
2018-02-19 12:34:51 -08:00
vals1, vals2 := vals[:nInit], kvstore.Validators()
2016-11-21 20:42:42 -08:00
valsEqual(t, vals1, vals2)
var v1, v2, v3 types.Validator
2016-11-21 20:42:42 -08:00
// add some validators
v1, v2 = vals[nInit], vals[nInit+1]
diff := []types.Validator{v1, v2}
2016-11-21 20:42:42 -08:00
tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
2018-02-19 12:34:51 -08:00
makeApplyBlock(t, kvstore, 1, diff, tx1, tx2)
2016-11-21 20:42:42 -08:00
2018-02-19 12:34:51 -08:00
vals1, vals2 = vals[:nInit+2], kvstore.Validators()
2016-11-21 20:42:42 -08:00
valsEqual(t, vals1, vals2)
// remove some validators
v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
v1.Power = 0
v2.Power = 0
v3.Power = 0
diff = []types.Validator{v1, v2, v3}
2016-11-21 20:42:42 -08:00
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
2018-02-19 12:34:51 -08:00
makeApplyBlock(t, kvstore, 2, diff, tx1, tx2, tx3)
2016-11-21 20:42:42 -08:00
vals1 = append(vals[:nInit-2], vals[nInit+1])
2018-02-19 12:34:51 -08:00
vals2 = kvstore.Validators()
2016-11-21 20:42:42 -08:00
valsEqual(t, vals1, vals2)
// update some validators
v1 = vals[0]
if v1.Power == 5 {
v1.Power = 6
} else {
v1.Power = 5
}
diff = []types.Validator{v1}
2016-11-21 20:42:42 -08:00
tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
2018-02-19 12:34:51 -08:00
makeApplyBlock(t, kvstore, 3, diff, tx1)
2016-11-21 20:42:42 -08:00
vals1 = append([]types.Validator{v1}, vals1[1:]...)
2018-02-19 12:34:51 -08:00
vals2 = kvstore.Validators()
2016-11-21 20:42:42 -08:00
valsEqual(t, vals1, vals2)
}
2018-02-19 12:34:51 -08:00
func makeApplyBlock(t *testing.T, kvstore types.Application, heightInt int, diff []types.Validator, txs ...[]byte) {
2016-11-21 20:42:42 -08:00
// make and apply block
2017-11-30 21:41:07 -08:00
height := int64(heightInt)
2016-11-21 20:42:42 -08:00
hash := []byte("foo")
header := types.Header{
2016-11-21 20:42:42 -08:00
Height: height,
}
2018-02-19 12:34:51 -08:00
kvstore.BeginBlock(types.RequestBeginBlock{hash, header, nil, nil})
2016-11-21 20:42:42 -08:00
for _, tx := range txs {
2018-02-19 12:34:51 -08:00
if r := kvstore.DeliverTx(tx); r.IsErr() {
2016-11-21 20:42:42 -08:00
t.Fatal(r)
}
}
2018-02-19 12:34:51 -08:00
resEndBlock := kvstore.EndBlock(types.RequestEndBlock{header.Height})
kvstore.Commit()
2016-11-21 20:42:42 -08:00
valsEqual(t, diff, resEndBlock.ValidatorUpdates)
2016-11-21 20:42:42 -08:00
}
// order doesn't matter
func valsEqual(t *testing.T, vals1, vals2 []types.Validator) {
2016-11-21 20:42:42 -08:00
if len(vals1) != len(vals2) {
t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
}
sort.Sort(types.Validators(vals1))
sort.Sort(types.Validators(vals2))
for i, v1 := range vals1 {
v2 := vals2[i]
2018-05-23 19:20:35 -07:00
if !bytes.Equal(v1.PubKey.Data, v2.PubKey.Data) ||
2016-11-21 20:42:42 -08:00
v1.Power != v2.Power {
t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
}
}
}
2017-01-27 22:27:32 -08:00
func makeSocketClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) {
// Start the listener
2017-01-27 22:27:32 -08:00
socket := cmn.Fmt("unix://%s.sock", name)
2017-05-04 11:43:54 -07:00
logger := log.TestingLogger()
2017-04-27 13:37:18 -07:00
2017-11-08 14:29:15 -08:00
server := abciserver.NewSocketServer(socket, app)
server.SetLogger(logger.With("module", "abci-server"))
2018-01-05 19:19:37 -08:00
if err := server.Start(); err != nil {
return nil, nil, err
}
// Connect to the socket
client := abcicli.NewSocketClient(socket, false)
client.SetLogger(logger.With("module", "abci-client"))
2018-01-05 19:19:37 -08:00
if err := client.Start(); err != nil {
server.Stop()
return nil, nil, err
}
return client, server, nil
}
2017-01-27 22:27:32 -08:00
func makeGRPCClientServer(app types.Application, name string) (abcicli.Client, cmn.Service, error) {
// Start the listener
2017-01-27 22:27:32 -08:00
socket := cmn.Fmt("unix://%s.sock", name)
2017-05-04 11:43:54 -07:00
logger := log.TestingLogger()
gapp := types.NewGRPCApplication(app)
2017-11-08 14:29:15 -08:00
server := abciserver.NewGRPCServer(socket, gapp)
server.SetLogger(logger.With("module", "abci-server"))
2018-01-05 19:19:37 -08:00
if err := server.Start(); err != nil {
return nil, nil, err
}
client := abcicli.NewGRPCClient(socket, true)
client.SetLogger(logger.With("module", "abci-client"))
2018-01-05 19:19:37 -08:00
if err := client.Start(); err != nil {
server.Stop()
return nil, nil, err
}
return client, server, nil
}
func TestClientServer(t *testing.T) {
// set up socket app
2018-02-19 12:34:51 -08:00
kvstore := NewKVStoreApplication()
client, server, err := makeSocketClientServer(kvstore, "kvstore-socket")
require.Nil(t, err)
defer server.Stop()
defer client.Stop()
runClientTests(t, client)
// set up grpc app
2018-02-19 12:34:51 -08:00
kvstore = NewKVStoreApplication()
gclient, gserver, err := makeGRPCClientServer(kvstore, "kvstore-grpc")
require.Nil(t, err)
defer gserver.Stop()
defer gclient.Stop()
runClientTests(t, gclient)
}
func runClientTests(t *testing.T, client abcicli.Client) {
// run some tests....
key := "abc"
value := key
tx := []byte(key)
testClient(t, client, tx, key, value)
value = "def"
tx = []byte(key + "=" + value)
testClient(t, client, tx, key, value)
}
func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
ar, err := app.DeliverTxSync(tx)
require.NoError(t, err)
require.False(t, ar.IsErr(), ar)
// repeating tx doesn't raise error
ar, err = app.DeliverTxSync(tx)
require.NoError(t, err)
require.False(t, ar.IsErr(), ar)
// make sure query is fine
resQuery, err := app.QuerySync(types.RequestQuery{
Path: "/store",
Data: []byte(key),
})
require.Nil(t, err)
2017-11-30 12:37:31 -08:00
require.Equal(t, code.CodeTypeOK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value))
// make sure proof is fine
resQuery, err = app.QuerySync(types.RequestQuery{
Path: "/store",
Data: []byte(key),
Prove: true,
})
require.Nil(t, err)
2017-11-30 12:37:31 -08:00
require.Equal(t, code.CodeTypeOK, resQuery.Code)
require.Equal(t, value, string(resQuery.Value))
}