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 }