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.

186 lines
5.5 KiB

7 years ago
  1. package kv
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "testing"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. abci "github.com/tendermint/abci/types"
  10. "github.com/tendermint/tendermint/state/txindex"
  11. "github.com/tendermint/tendermint/types"
  12. db "github.com/tendermint/tmlibs/db"
  13. "github.com/tendermint/tmlibs/pubsub/query"
  14. )
  15. func TestTxIndex(t *testing.T) {
  16. indexer := NewTxIndex(db.NewMemDB())
  17. tx := types.Tx("HELLO WORLD")
  18. txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []*abci.KVPair{}}}
  19. hash := tx.Hash()
  20. batch := txindex.NewBatch(1)
  21. if err := batch.Add(txResult); err != nil {
  22. t.Error(err)
  23. }
  24. err := indexer.AddBatch(batch)
  25. require.NoError(t, err)
  26. loadedTxResult, err := indexer.Get(hash)
  27. require.NoError(t, err)
  28. assert.Equal(t, txResult, loadedTxResult)
  29. tx2 := types.Tx("BYE BYE WORLD")
  30. txResult2 := &types.TxResult{1, 0, tx2, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []*abci.KVPair{}}}
  31. hash2 := tx2.Hash()
  32. err = indexer.Index(txResult2)
  33. require.NoError(t, err)
  34. loadedTxResult2, err := indexer.Get(hash2)
  35. require.NoError(t, err)
  36. assert.Equal(t, txResult2, loadedTxResult2)
  37. }
  38. func TestTxSearch(t *testing.T) {
  39. allowedTags := []string{"account.number", "account.owner", "account.date"}
  40. indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
  41. txResult := txResultWithTags([]*abci.KVPair{
  42. {Key: "account.number", ValueType: abci.KVPair_INT, ValueInt: 1},
  43. {Key: "account.owner", ValueType: abci.KVPair_STRING, ValueString: "Ivan"},
  44. {Key: "not_allowed", ValueType: abci.KVPair_STRING, ValueString: "Vlad"},
  45. })
  46. hash := txResult.Tx.Hash()
  47. err := indexer.Index(txResult)
  48. require.NoError(t, err)
  49. testCases := []struct {
  50. q string
  51. resultsLength int
  52. }{
  53. // search by hash
  54. {fmt.Sprintf("tx.hash = '%X'", hash), 1},
  55. // search by exact match (one tag)
  56. {"account.number = 1", 1},
  57. // search by exact match (two tags)
  58. {"account.number = 1 AND account.owner = 'Ivan'", 1},
  59. // search by exact match (two tags)
  60. {"account.number = 1 AND account.owner = 'Vlad'", 0},
  61. // search by range
  62. {"account.number >= 1 AND account.number <= 5", 1},
  63. // search by range (lower bound)
  64. {"account.number >= 1", 1},
  65. // search by range (upper bound)
  66. {"account.number <= 5", 1},
  67. // search using not allowed tag
  68. {"not_allowed = 'boom'", 0},
  69. // search for not existing tx result
  70. {"account.number >= 2 AND account.number <= 5", 0},
  71. // search using not existing tag
  72. {"account.date >= TIME 2013-05-03T14:45:00Z", 0},
  73. // search using CONTAINS
  74. {"account.owner CONTAINS 'an'", 1},
  75. // search using CONTAINS
  76. {"account.owner CONTAINS 'Vlad'", 0},
  77. }
  78. for _, tc := range testCases {
  79. t.Run(tc.q, func(t *testing.T) {
  80. results, err := indexer.Search(query.MustParse(tc.q))
  81. assert.NoError(t, err)
  82. assert.Len(t, results, tc.resultsLength)
  83. if tc.resultsLength > 0 {
  84. assert.Equal(t, []*types.TxResult{txResult}, results)
  85. }
  86. })
  87. }
  88. }
  89. func TestTxSearchOneTxWithMultipleSameTagsButDifferentValues(t *testing.T) {
  90. allowedTags := []string{"account.number"}
  91. indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
  92. txResult := txResultWithTags([]*abci.KVPair{
  93. {Key: "account.number", ValueType: abci.KVPair_INT, ValueInt: 1},
  94. {Key: "account.number", ValueType: abci.KVPair_INT, ValueInt: 2},
  95. })
  96. err := indexer.Index(txResult)
  97. require.NoError(t, err)
  98. results, err := indexer.Search(query.MustParse("account.number >= 1"))
  99. assert.NoError(t, err)
  100. assert.Len(t, results, 1)
  101. assert.Equal(t, []*types.TxResult{txResult}, results)
  102. }
  103. func TestIndexAllTags(t *testing.T) {
  104. indexer := NewTxIndex(db.NewMemDB(), IndexAllTags())
  105. txResult := txResultWithTags([]*abci.KVPair{
  106. abci.KVPairString("account.owner", "Ivan"),
  107. abci.KVPairInt("account.number", 1),
  108. })
  109. err := indexer.Index(txResult)
  110. require.NoError(t, err)
  111. results, err := indexer.Search(query.MustParse("account.number >= 1"))
  112. assert.NoError(t, err)
  113. assert.Len(t, results, 1)
  114. assert.Equal(t, []*types.TxResult{txResult}, results)
  115. results, err = indexer.Search(query.MustParse("account.owner = 'Ivan'"))
  116. assert.NoError(t, err)
  117. assert.Len(t, results, 1)
  118. assert.Equal(t, []*types.TxResult{txResult}, results)
  119. }
  120. func txResultWithTags(tags []*abci.KVPair) *types.TxResult {
  121. tx := types.Tx("HELLO WORLD")
  122. return &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: tags}}
  123. }
  124. func benchmarkTxIndex(txsCount int, b *testing.B) {
  125. tx := types.Tx("HELLO WORLD")
  126. txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: []*abci.KVPair{}}}
  127. dir, err := ioutil.TempDir("", "tx_index_db")
  128. if err != nil {
  129. b.Fatal(err)
  130. }
  131. defer os.RemoveAll(dir) // nolint: errcheck
  132. store := db.NewDB("tx_index", "leveldb", dir)
  133. indexer := NewTxIndex(store)
  134. batch := txindex.NewBatch(txsCount)
  135. for i := 0; i < txsCount; i++ {
  136. if err := batch.Add(txResult); err != nil {
  137. b.Fatal(err)
  138. }
  139. txResult.Index += 1
  140. }
  141. b.ResetTimer()
  142. for n := 0; n < b.N; n++ {
  143. err = indexer.AddBatch(batch)
  144. }
  145. if err != nil {
  146. b.Fatal(err)
  147. }
  148. }
  149. func BenchmarkTxIndex1(b *testing.B) { benchmarkTxIndex(1, b) }
  150. func BenchmarkTxIndex500(b *testing.B) { benchmarkTxIndex(500, b) }
  151. func BenchmarkTxIndex1000(b *testing.B) { benchmarkTxIndex(1000, b) }
  152. func BenchmarkTxIndex2000(b *testing.B) { benchmarkTxIndex(2000, b) }
  153. func BenchmarkTxIndex10000(b *testing.B) { benchmarkTxIndex(10000, b) }