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.

138 lines
4.0 KiB

  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(), []string{})
  17. tx := types.Tx("HELLO WORLD")
  18. txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeType_OK, 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.CodeType_OK, 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. tagsToIndex := []string{"account.number", "account.owner", "account.date"}
  40. indexer := NewTxIndex(db.NewMemDB(), tagsToIndex)
  41. tx := types.Tx("HELLO WORLD")
  42. tags := []*abci.KVPair{
  43. {Key: "account.number", ValueType: abci.KVPair_INT, ValueInt: 1},
  44. {Key: "account.owner", ValueType: abci.KVPair_STRING, ValueString: "Ivan"},
  45. {Key: "not_allowed", ValueType: abci.KVPair_STRING, ValueString: "Vlad"},
  46. }
  47. txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeType_OK, Log: "", Tags: tags}}
  48. hash := tx.Hash()
  49. err := indexer.Index(txResult)
  50. require.NoError(t, err)
  51. testCases := []struct {
  52. q string
  53. resultsLength int
  54. }{
  55. // search by hash
  56. {fmt.Sprintf("tx.hash = '%X'", hash), 1},
  57. // search by exact match (one tag)
  58. {"account.number = 1", 1},
  59. // search by exact match (two tags)
  60. {"account.number = 1 AND account.owner = 'Ivan'", 1},
  61. // search by exact match (two tags)
  62. {"account.number = 1 AND account.owner = 'Vlad'", 0},
  63. // search by range
  64. {"account.number >= 1 AND account.number <= 5", 1},
  65. // search using not allowed tag
  66. {"not_allowed = 'boom'", 0},
  67. // search for not existing tx result
  68. {"account.number >= 2 AND account.number <= 5", 0},
  69. // search using not existing tag
  70. {"account.date >= TIME 2013-05-03T14:45:00Z", 0},
  71. // search using CONTAINS
  72. {"account.owner CONTAINS 'an'", 1},
  73. // search using CONTAINS
  74. {"account.owner CONTAINS 'Vlad'", 0},
  75. }
  76. for _, tc := range testCases {
  77. t.Run(tc.q, func(t *testing.T) {
  78. results, err := indexer.Search(query.MustParse(tc.q))
  79. assert.NoError(t, err)
  80. assert.Len(t, results, tc.resultsLength)
  81. if tc.resultsLength > 0 {
  82. assert.Equal(t, []*types.TxResult{txResult}, results)
  83. }
  84. })
  85. }
  86. }
  87. func benchmarkTxIndex(txsCount int, b *testing.B) {
  88. tx := types.Tx("HELLO WORLD")
  89. txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeType_OK, Log: "", Tags: []*abci.KVPair{}}}
  90. dir, err := ioutil.TempDir("", "tx_index_db")
  91. if err != nil {
  92. b.Fatal(err)
  93. }
  94. defer os.RemoveAll(dir) // nolint: errcheck
  95. store := db.NewDB("tx_index", "leveldb", dir)
  96. indexer := NewTxIndex(store, []string{})
  97. batch := txindex.NewBatch(txsCount)
  98. for i := 0; i < txsCount; i++ {
  99. if err := batch.Add(txResult); err != nil {
  100. b.Fatal(err)
  101. }
  102. txResult.Index += 1
  103. }
  104. b.ResetTimer()
  105. for n := 0; n < b.N; n++ {
  106. err = indexer.AddBatch(batch)
  107. }
  108. if err != nil {
  109. b.Fatal(err)
  110. }
  111. }
  112. func BenchmarkTxIndex1(b *testing.B) { benchmarkTxIndex(1, b) }
  113. func BenchmarkTxIndex500(b *testing.B) { benchmarkTxIndex(500, b) }
  114. func BenchmarkTxIndex1000(b *testing.B) { benchmarkTxIndex(1000, b) }
  115. func BenchmarkTxIndex2000(b *testing.B) { benchmarkTxIndex(2000, b) }
  116. func BenchmarkTxIndex10000(b *testing.B) { benchmarkTxIndex(10000, b) }