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.

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