github.com/okex/exchain@v1.8.0/libs/tendermint/abci/example/kvstore/kvstore_test.go (about)

     1  package kvstore
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"sort"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	abcicli "github.com/okex/exchain/libs/tendermint/abci/client"
    12  	"github.com/okex/exchain/libs/tendermint/abci/example/code"
    13  	"github.com/okex/exchain/libs/tendermint/abci/types"
    14  )
    15  
    16  const (
    17  	testKey   = "abc"
    18  	testValue = "def"
    19  )
    20  
    21  func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) {
    22  	req := types.RequestDeliverTx{Tx: tx}
    23  	ar := app.DeliverTx(req)
    24  	require.False(t, ar.IsErr(), ar)
    25  	// repeating tx doesn't raise error
    26  	ar = app.DeliverTx(req)
    27  	require.False(t, ar.IsErr(), ar)
    28  	// commit
    29  	app.Commit(types.RequestCommit{})
    30  
    31  	info := app.Info(types.RequestInfo{})
    32  	require.NotZero(t, info.LastBlockHeight)
    33  
    34  	// make sure query is fine
    35  	resQuery := app.Query(types.RequestQuery{
    36  		Path: "/store",
    37  		Data: []byte(key),
    38  	})
    39  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
    40  	require.Equal(t, key, string(resQuery.Key))
    41  	require.Equal(t, value, string(resQuery.Value))
    42  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
    43  
    44  	// make sure proof is fine
    45  	resQuery = app.Query(types.RequestQuery{
    46  		Path:  "/store",
    47  		Data:  []byte(key),
    48  		Prove: true,
    49  	})
    50  	require.EqualValues(t, code.CodeTypeOK, resQuery.Code)
    51  	require.Equal(t, key, string(resQuery.Key))
    52  	require.Equal(t, value, string(resQuery.Value))
    53  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
    54  }
    55  
    56  func TestKVStoreKV(t *testing.T) {
    57  	kvstore := NewApplication()
    58  	key := testKey
    59  	value := key
    60  	tx := []byte(key)
    61  	testKVStore(t, kvstore, tx, key, value)
    62  
    63  	value = testValue
    64  	tx = []byte(key + "=" + value)
    65  	testKVStore(t, kvstore, tx, key, value)
    66  }
    67  
    68  func TestPersistentKVStoreKV(t *testing.T) {
    69  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	kvstore := NewPersistentKVStoreApplication(dir)
    74  
    75  	key := testKey
    76  	value := key
    77  	tx := []byte(key)
    78  	testKVStore(t, kvstore, tx, key, value)
    79  
    80  	value = testValue
    81  	tx = []byte(key + "=" + value)
    82  	testKVStore(t, kvstore, tx, key, value)
    83  }
    84  
    85  func TestPersistentKVStoreInfo(t *testing.T) {
    86  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	kvstore := NewPersistentKVStoreApplication(dir)
    91  
    92  	InitKVStore(kvstore)
    93  	height := int64(0)
    94  
    95  	resInfo := kvstore.Info(types.RequestInfo{})
    96  	if resInfo.LastBlockHeight != height {
    97  		t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
    98  	}
    99  
   100  	// make and apply block
   101  	height = int64(1)
   102  	hash := []byte("foo")
   103  	header := types.Header{
   104  		Height: height,
   105  	}
   106  	kvstore.BeginBlock(types.RequestBeginBlock{Hash: hash, Header: header})
   107  	kvstore.EndBlock(types.RequestEndBlock{Height: header.Height})
   108  	kvstore.Commit(types.RequestCommit{})
   109  
   110  	resInfo = kvstore.Info(types.RequestInfo{})
   111  	if resInfo.LastBlockHeight != height {
   112  		t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
   113  	}
   114  
   115  }
   116  
   117  // add a validator, remove a validator, update a validator
   118  func TestValUpdates(t *testing.T) {
   119  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
   120  	if err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	kvstore := NewPersistentKVStoreApplication(dir)
   124  	// init with some validators
   125  	total := 10
   126  	nInit := 5
   127  	vals := RandVals(total)
   128  	// iniitalize with the first nInit
   129  	kvstore.InitChain(types.RequestInitChain{
   130  		Validators: vals[:nInit],
   131  	})
   132  
   133  	vals1, vals2 := vals[:nInit], kvstore.Validators()
   134  	valsEqual(t, vals1, vals2)
   135  
   136  	var v1, v2, v3 types.ValidatorUpdate
   137  
   138  	// add some validators
   139  	v1, v2 = vals[nInit], vals[nInit+1]
   140  	diff := []types.ValidatorUpdate{v1, v2}
   141  	tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
   142  	tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
   143  
   144  	makeApplyBlock(t, kvstore, 1, diff, tx1, tx2)
   145  
   146  	vals1, vals2 = vals[:nInit+2], kvstore.Validators()
   147  	valsEqual(t, vals1, vals2)
   148  
   149  	// remove some validators
   150  	v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
   151  	v1.Power = 0
   152  	v2.Power = 0
   153  	v3.Power = 0
   154  	diff = []types.ValidatorUpdate{v1, v2, v3}
   155  	tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
   156  	tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
   157  	tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
   158  
   159  	makeApplyBlock(t, kvstore, 2, diff, tx1, tx2, tx3)
   160  
   161  	vals1 = append(vals[:nInit-2], vals[nInit+1]) // nolint: gocritic
   162  	vals2 = kvstore.Validators()
   163  	valsEqual(t, vals1, vals2)
   164  
   165  	// update some validators
   166  	v1 = vals[0]
   167  	if v1.Power == 5 {
   168  		v1.Power = 6
   169  	} else {
   170  		v1.Power = 5
   171  	}
   172  	diff = []types.ValidatorUpdate{v1}
   173  	tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
   174  
   175  	makeApplyBlock(t, kvstore, 3, diff, tx1)
   176  
   177  	vals1 = append([]types.ValidatorUpdate{v1}, vals1[1:]...)
   178  	vals2 = kvstore.Validators()
   179  	valsEqual(t, vals1, vals2)
   180  
   181  }
   182  
   183  func makeApplyBlock(
   184  	t *testing.T,
   185  	kvstore types.Application,
   186  	heightInt int,
   187  	diff []types.ValidatorUpdate,
   188  	txs ...[]byte) {
   189  	// make and apply block
   190  	height := int64(heightInt)
   191  	hash := []byte("foo")
   192  	header := types.Header{
   193  		Height: height,
   194  	}
   195  
   196  	kvstore.BeginBlock(types.RequestBeginBlock{Hash: hash, Header: header})
   197  	for _, tx := range txs {
   198  		if r := kvstore.DeliverTx(types.RequestDeliverTx{Tx: tx}); r.IsErr() {
   199  			t.Fatal(r)
   200  		}
   201  	}
   202  	resEndBlock := kvstore.EndBlock(types.RequestEndBlock{Height: header.Height})
   203  	kvstore.Commit(types.RequestCommit{})
   204  
   205  	valsEqual(t, diff, resEndBlock.ValidatorUpdates)
   206  
   207  }
   208  
   209  // order doesn't matter
   210  func valsEqual(t *testing.T, vals1, vals2 []types.ValidatorUpdate) {
   211  	if len(vals1) != len(vals2) {
   212  		t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
   213  	}
   214  	sort.Sort(types.ValidatorUpdates(vals1))
   215  	sort.Sort(types.ValidatorUpdates(vals2))
   216  	for i, v1 := range vals1 {
   217  		v2 := vals2[i]
   218  		if !bytes.Equal(v1.PubKey.Data, v2.PubKey.Data) ||
   219  			v1.Power != v2.Power {
   220  			t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
   221  		}
   222  	}
   223  }
   224  
   225  func runClientTests(t *testing.T, client abcicli.Client) {
   226  	// run some tests....
   227  	key := testKey
   228  	value := key
   229  	tx := []byte(key)
   230  	testClient(t, client, tx, key, value)
   231  
   232  	value = testValue
   233  	tx = []byte(key + "=" + value)
   234  	testClient(t, client, tx, key, value)
   235  }
   236  
   237  func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
   238  	ar, err := app.DeliverTxSync(types.RequestDeliverTx{Tx: tx})
   239  	require.NoError(t, err)
   240  	require.False(t, ar.IsErr(), ar)
   241  	// repeating tx doesn't raise error
   242  	ar, err = app.DeliverTxSync(types.RequestDeliverTx{Tx: tx})
   243  	require.NoError(t, err)
   244  	require.False(t, ar.IsErr(), ar)
   245  	// commit
   246  	_, err = app.CommitSync(types.RequestCommit{})
   247  	require.NoError(t, err)
   248  
   249  	info, err := app.InfoSync(types.RequestInfo{})
   250  	require.NoError(t, err)
   251  	require.NotZero(t, info.LastBlockHeight)
   252  
   253  	// make sure query is fine
   254  	resQuery, err := app.QuerySync(types.RequestQuery{
   255  		Path: "/store",
   256  		Data: []byte(key),
   257  	})
   258  	require.Nil(t, err)
   259  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
   260  	require.Equal(t, key, string(resQuery.Key))
   261  	require.Equal(t, value, string(resQuery.Value))
   262  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
   263  
   264  	// make sure proof is fine
   265  	resQuery, err = app.QuerySync(types.RequestQuery{
   266  		Path:  "/store",
   267  		Data:  []byte(key),
   268  		Prove: true,
   269  	})
   270  	require.Nil(t, err)
   271  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
   272  	require.Equal(t, key, string(resQuery.Key))
   273  	require.Equal(t, value, string(resQuery.Value))
   274  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
   275  }