github.com/number571/tendermint@v0.34.11-gost/abci/example/kvstore/kvstore_test.go (about)

     1  package kvstore
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"sort"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/number571/tendermint/libs/log"
    13  	"github.com/number571/tendermint/libs/service"
    14  
    15  	abcicli "github.com/number571/tendermint/abci/client"
    16  	"github.com/number571/tendermint/abci/example/code"
    17  	abciserver "github.com/number571/tendermint/abci/server"
    18  	"github.com/number571/tendermint/abci/types"
    19  	tmproto "github.com/number571/tendermint/proto/tendermint/types"
    20  )
    21  
    22  const (
    23  	testKey   = "abc"
    24  	testValue = "def"
    25  )
    26  
    27  var ctx = context.Background()
    28  
    29  func testKVStore(t *testing.T, app types.Application, tx []byte, key, value string) {
    30  	req := types.RequestDeliverTx{Tx: tx}
    31  	ar := app.DeliverTx(req)
    32  	require.False(t, ar.IsErr(), ar)
    33  	// repeating tx doesn't raise error
    34  	ar = app.DeliverTx(req)
    35  	require.False(t, ar.IsErr(), ar)
    36  	// commit
    37  	app.Commit()
    38  
    39  	info := app.Info(types.RequestInfo{})
    40  	require.NotZero(t, info.LastBlockHeight)
    41  
    42  	// make sure query is fine
    43  	resQuery := app.Query(types.RequestQuery{
    44  		Path: "/store",
    45  		Data: []byte(key),
    46  	})
    47  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
    48  	require.Equal(t, key, string(resQuery.Key))
    49  	require.Equal(t, value, string(resQuery.Value))
    50  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
    51  
    52  	// make sure proof is fine
    53  	resQuery = app.Query(types.RequestQuery{
    54  		Path:  "/store",
    55  		Data:  []byte(key),
    56  		Prove: true,
    57  	})
    58  	require.EqualValues(t, code.CodeTypeOK, resQuery.Code)
    59  	require.Equal(t, key, string(resQuery.Key))
    60  	require.Equal(t, value, string(resQuery.Value))
    61  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
    62  }
    63  
    64  func TestKVStoreKV(t *testing.T) {
    65  	kvstore := NewApplication()
    66  	key := testKey
    67  	value := key
    68  	tx := []byte(key)
    69  	testKVStore(t, kvstore, tx, key, value)
    70  
    71  	value = testValue
    72  	tx = []byte(key + "=" + value)
    73  	testKVStore(t, kvstore, tx, key, value)
    74  }
    75  
    76  func TestPersistentKVStoreKV(t *testing.T) {
    77  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	kvstore := NewPersistentKVStoreApplication(dir)
    82  	key := testKey
    83  	value := key
    84  	tx := []byte(key)
    85  	testKVStore(t, kvstore, tx, key, value)
    86  
    87  	value = testValue
    88  	tx = []byte(key + "=" + value)
    89  	testKVStore(t, kvstore, tx, key, value)
    90  }
    91  
    92  func TestPersistentKVStoreInfo(t *testing.T) {
    93  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
    94  	if err != nil {
    95  		t.Fatal(err)
    96  	}
    97  	kvstore := NewPersistentKVStoreApplication(dir)
    98  	InitKVStore(kvstore)
    99  	height := int64(0)
   100  
   101  	resInfo := kvstore.Info(types.RequestInfo{})
   102  	if resInfo.LastBlockHeight != height {
   103  		t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
   104  	}
   105  
   106  	// make and apply block
   107  	height = int64(1)
   108  	hash := []byte("foo")
   109  	header := tmproto.Header{
   110  		Height: height,
   111  	}
   112  	kvstore.BeginBlock(types.RequestBeginBlock{Hash: hash, Header: header})
   113  	kvstore.EndBlock(types.RequestEndBlock{Height: header.Height})
   114  	kvstore.Commit()
   115  
   116  	resInfo = kvstore.Info(types.RequestInfo{})
   117  	if resInfo.LastBlockHeight != height {
   118  		t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight)
   119  	}
   120  
   121  }
   122  
   123  // add a validator, remove a validator, update a validator
   124  func TestValUpdates(t *testing.T) {
   125  	dir, err := ioutil.TempDir("/tmp", "abci-kvstore-test") // TODO
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	kvstore := NewPersistentKVStoreApplication(dir)
   130  
   131  	// init with some validators
   132  	total := 10
   133  	nInit := 5
   134  	vals := RandVals(total)
   135  	// initialize with the first nInit
   136  	kvstore.InitChain(types.RequestInitChain{
   137  		Validators: vals[:nInit],
   138  	})
   139  
   140  	vals1, vals2 := vals[:nInit], kvstore.Validators()
   141  	valsEqual(t, vals1, vals2)
   142  
   143  	var v1, v2, v3 types.ValidatorUpdate
   144  
   145  	// add some validators
   146  	v1, v2 = vals[nInit], vals[nInit+1]
   147  	diff := []types.ValidatorUpdate{v1, v2}
   148  	tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power)
   149  	tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power)
   150  
   151  	makeApplyBlock(t, kvstore, 1, diff, tx1, tx2)
   152  
   153  	vals1, vals2 = vals[:nInit+2], kvstore.Validators()
   154  	valsEqual(t, vals1, vals2)
   155  
   156  	// remove some validators
   157  	v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit]
   158  	v1.Power = 0
   159  	v2.Power = 0
   160  	v3.Power = 0
   161  	diff = []types.ValidatorUpdate{v1, v2, v3}
   162  	tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
   163  	tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power)
   164  	tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power)
   165  
   166  	makeApplyBlock(t, kvstore, 2, diff, tx1, tx2, tx3)
   167  
   168  	vals1 = append(vals[:nInit-2], vals[nInit+1]) // nolint: gocritic
   169  	vals2 = kvstore.Validators()
   170  	valsEqual(t, vals1, vals2)
   171  
   172  	// update some validators
   173  	v1 = vals[0]
   174  	if v1.Power == 5 {
   175  		v1.Power = 6
   176  	} else {
   177  		v1.Power = 5
   178  	}
   179  	diff = []types.ValidatorUpdate{v1}
   180  	tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power)
   181  
   182  	makeApplyBlock(t, kvstore, 3, diff, tx1)
   183  
   184  	vals1 = append([]types.ValidatorUpdate{v1}, vals1[1:]...)
   185  	vals2 = kvstore.Validators()
   186  	valsEqual(t, vals1, vals2)
   187  
   188  }
   189  
   190  func makeApplyBlock(
   191  	t *testing.T,
   192  	kvstore types.Application,
   193  	heightInt int,
   194  	diff []types.ValidatorUpdate,
   195  	txs ...[]byte) {
   196  	// make and apply block
   197  	height := int64(heightInt)
   198  	hash := []byte("foo")
   199  	header := tmproto.Header{
   200  		Height: height,
   201  	}
   202  
   203  	kvstore.BeginBlock(types.RequestBeginBlock{Hash: hash, Header: header})
   204  	for _, tx := range txs {
   205  		if r := kvstore.DeliverTx(types.RequestDeliverTx{Tx: tx}); r.IsErr() {
   206  			t.Fatal(r)
   207  		}
   208  	}
   209  	resEndBlock := kvstore.EndBlock(types.RequestEndBlock{Height: header.Height})
   210  	kvstore.Commit()
   211  
   212  	valsEqual(t, diff, resEndBlock.ValidatorUpdates)
   213  
   214  }
   215  
   216  // order doesn't matter
   217  func valsEqual(t *testing.T, vals1, vals2 []types.ValidatorUpdate) {
   218  	if len(vals1) != len(vals2) {
   219  		t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1))
   220  	}
   221  	sort.Sort(types.ValidatorUpdates(vals1))
   222  	sort.Sort(types.ValidatorUpdates(vals2))
   223  	for i, v1 := range vals1 {
   224  		v2 := vals2[i]
   225  		if !v1.PubKey.Equal(v2.PubKey) ||
   226  			v1.Power != v2.Power {
   227  			t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power)
   228  		}
   229  	}
   230  }
   231  
   232  func makeSocketClientServer(app types.Application, name string) (abcicli.Client, service.Service, error) {
   233  	// Start the listener
   234  	socket := fmt.Sprintf("unix://%s.sock", name)
   235  	logger := log.TestingLogger()
   236  
   237  	server := abciserver.NewSocketServer(socket, app)
   238  	server.SetLogger(logger.With("module", "abci-server"))
   239  	if err := server.Start(); err != nil {
   240  		return nil, nil, err
   241  	}
   242  
   243  	// Connect to the socket
   244  	client := abcicli.NewSocketClient(socket, false)
   245  	client.SetLogger(logger.With("module", "abci-client"))
   246  	if err := client.Start(); err != nil {
   247  		if err = server.Stop(); err != nil {
   248  			return nil, nil, err
   249  		}
   250  		return nil, nil, err
   251  	}
   252  
   253  	return client, server, nil
   254  }
   255  
   256  func makeGRPCClientServer(app types.Application, name string) (abcicli.Client, service.Service, error) {
   257  	// Start the listener
   258  	socket := fmt.Sprintf("unix://%s.sock", name)
   259  	logger := log.TestingLogger()
   260  
   261  	gapp := types.NewGRPCApplication(app)
   262  	server := abciserver.NewGRPCServer(socket, gapp)
   263  	server.SetLogger(logger.With("module", "abci-server"))
   264  	if err := server.Start(); err != nil {
   265  		return nil, nil, err
   266  	}
   267  
   268  	client := abcicli.NewGRPCClient(socket, true)
   269  	client.SetLogger(logger.With("module", "abci-client"))
   270  	if err := client.Start(); err != nil {
   271  		if err := server.Stop(); err != nil {
   272  			return nil, nil, err
   273  		}
   274  		return nil, nil, err
   275  	}
   276  	return client, server, nil
   277  }
   278  
   279  func TestClientServer(t *testing.T) {
   280  	// set up socket app
   281  	kvstore := NewApplication()
   282  	client, server, err := makeSocketClientServer(kvstore, "kvstore-socket")
   283  	require.NoError(t, err)
   284  	t.Cleanup(func() {
   285  		if err := server.Stop(); err != nil {
   286  			t.Error(err)
   287  		}
   288  	})
   289  	t.Cleanup(func() {
   290  		if err := client.Stop(); err != nil {
   291  			t.Error(err)
   292  		}
   293  	})
   294  
   295  	runClientTests(t, client)
   296  
   297  	// set up grpc app
   298  	kvstore = NewApplication()
   299  	gclient, gserver, err := makeGRPCClientServer(kvstore, "kvstore-grpc")
   300  	require.NoError(t, err)
   301  
   302  	t.Cleanup(func() {
   303  		if err := gserver.Stop(); err != nil {
   304  			t.Error(err)
   305  		}
   306  	})
   307  	t.Cleanup(func() {
   308  		if err := gclient.Stop(); err != nil {
   309  			t.Error(err)
   310  		}
   311  	})
   312  
   313  	runClientTests(t, gclient)
   314  }
   315  
   316  func runClientTests(t *testing.T, client abcicli.Client) {
   317  	// run some tests....
   318  	key := testKey
   319  	value := key
   320  	tx := []byte(key)
   321  	testClient(t, client, tx, key, value)
   322  
   323  	value = testValue
   324  	tx = []byte(key + "=" + value)
   325  	testClient(t, client, tx, key, value)
   326  }
   327  
   328  func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) {
   329  	ar, err := app.DeliverTxSync(ctx, types.RequestDeliverTx{Tx: tx})
   330  	require.NoError(t, err)
   331  	require.False(t, ar.IsErr(), ar)
   332  	// repeating tx doesn't raise error
   333  	ar, err = app.DeliverTxSync(ctx, types.RequestDeliverTx{Tx: tx})
   334  	require.NoError(t, err)
   335  	require.False(t, ar.IsErr(), ar)
   336  	// commit
   337  	_, err = app.CommitSync(ctx)
   338  	require.NoError(t, err)
   339  
   340  	info, err := app.InfoSync(ctx, types.RequestInfo{})
   341  	require.NoError(t, err)
   342  	require.NotZero(t, info.LastBlockHeight)
   343  
   344  	// make sure query is fine
   345  	resQuery, err := app.QuerySync(ctx, types.RequestQuery{
   346  		Path: "/store",
   347  		Data: []byte(key),
   348  	})
   349  	require.Nil(t, err)
   350  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
   351  	require.Equal(t, key, string(resQuery.Key))
   352  	require.Equal(t, value, string(resQuery.Value))
   353  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
   354  
   355  	// make sure proof is fine
   356  	resQuery, err = app.QuerySync(ctx, types.RequestQuery{
   357  		Path:  "/store",
   358  		Data:  []byte(key),
   359  		Prove: true,
   360  	})
   361  	require.Nil(t, err)
   362  	require.Equal(t, code.CodeTypeOK, resQuery.Code)
   363  	require.Equal(t, key, string(resQuery.Key))
   364  	require.Equal(t, value, string(resQuery.Value))
   365  	require.EqualValues(t, info.LastBlockHeight, resQuery.Height)
   366  }