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