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 }