You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

322 lines
8.2 KiB

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