github.com/evdatsion/aphelion-dpos-bft@v0.32.1/abci/example/kvstore/kvstore_test.go (about)

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