tendermint/state/txindex/kv/kv_test.go

238 lines
6.5 KiB
Go
Raw Normal View History

2017-04-18 16:29:02 -07:00
package kv
import (
2017-11-26 17:16:21 -08:00
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2018-06-21 21:59:02 -07:00
abci "github.com/tendermint/tendermint/abci/types"
2018-07-01 19:36:49 -07:00
cmn "github.com/tendermint/tendermint/libs/common"
db "github.com/tendermint/tendermint/libs/db"
2018-04-03 06:50:53 -07:00
"github.com/tendermint/tendermint/libs/pubsub/query"
2018-04-03 06:50:53 -07:00
"github.com/tendermint/tendermint/state/txindex"
"github.com/tendermint/tendermint/types"
)
2017-04-18 16:29:02 -07:00
func TestTxIndex(t *testing.T) {
2017-11-30 18:02:39 -08:00
indexer := NewTxIndex(db.NewMemDB())
tx := types.Tx("HELLO WORLD")
2018-04-03 06:50:53 -07:00
txResult := &types.TxResult{1, 0, tx, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: nil}}
hash := tx.Hash()
batch := txindex.NewBatch(1)
2017-11-26 17:16:21 -08:00
if err := batch.Add(txResult); err != nil {
2017-09-06 08:50:43 -07:00
t.Error(err)
}
2017-11-28 16:58:39 -08:00
err := indexer.AddBatch(batch)
2017-11-26 17:16:21 -08:00
require.NoError(t, err)
2017-04-18 16:29:02 -07:00
loadedTxResult, err := indexer.Get(hash)
2017-11-26 17:16:21 -08:00
require.NoError(t, err)
assert.Equal(t, txResult, loadedTxResult)
tx2 := types.Tx("BYE BYE WORLD")
2018-04-03 06:50:53 -07:00
txResult2 := &types.TxResult{1, 0, tx2, abci.ResponseDeliverTx{Data: []byte{0}, Code: abci.CodeTypeOK, Log: "", Tags: nil}}
hash2 := tx2.Hash()
2017-11-28 16:58:39 -08:00
err = indexer.Index(txResult2)
2017-11-26 17:16:21 -08:00
require.NoError(t, err)
loadedTxResult2, err := indexer.Get(hash2)
2017-11-26 17:16:21 -08:00
require.NoError(t, err)
assert.Equal(t, txResult2, loadedTxResult2)
}
2017-11-26 17:16:21 -08:00
func TestTxSearch(t *testing.T) {
2017-11-30 18:15:03 -08:00
allowedTags := []string{"account.number", "account.owner", "account.date"}
indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
2017-11-26 17:16:21 -08:00
txResult := txResultWithTags([]cmn.KVPair{
{Key: []byte("account.number"), Value: []byte("1")},
{Key: []byte("account.owner"), Value: []byte("Ivan")},
{Key: []byte("not_allowed"), Value: []byte("Vlad")},
2017-11-30 21:02:40 -08:00
})
hash := txResult.Tx.Hash()
2017-11-26 17:16:21 -08:00
2017-11-28 16:58:39 -08:00
err := indexer.Index(txResult)
2017-11-26 17:16:21 -08:00
require.NoError(t, err)
testCases := []struct {
q string
resultsLength int
}{
// search by hash
2017-11-28 16:58:39 -08:00
{fmt.Sprintf("tx.hash = '%X'", hash), 1},
2017-11-26 17:16:21 -08:00
// search by exact match (one tag)
2017-11-28 16:58:39 -08:00
{"account.number = 1", 1},
2017-11-26 17:16:21 -08:00
// search by exact match (two tags)
2017-11-28 16:58:39 -08:00
{"account.number = 1 AND account.owner = 'Ivan'", 1},
2017-11-26 17:16:21 -08:00
// search by exact match (two tags)
2017-11-28 16:58:39 -08:00
{"account.number = 1 AND account.owner = 'Vlad'", 0},
2017-11-26 17:16:21 -08:00
// search by range
2017-11-28 16:58:39 -08:00
{"account.number >= 1 AND account.number <= 5", 1},
2017-11-29 18:04:00 -08:00
// search by range (lower bound)
{"account.number >= 1", 1},
// search by range (upper bound)
{"account.number <= 5", 1},
2017-11-26 17:16:21 -08:00
// search using not allowed tag
2017-11-28 16:58:39 -08:00
{"not_allowed = 'boom'", 0},
2017-11-26 17:16:21 -08:00
// search for not existing tx result
2017-11-28 16:58:39 -08:00
{"account.number >= 2 AND account.number <= 5", 0},
2017-11-26 17:16:21 -08:00
// search using not existing tag
2017-11-28 16:58:39 -08:00
{"account.date >= TIME 2013-05-03T14:45:00Z", 0},
2017-11-26 17:16:21 -08:00
// search using CONTAINS
2017-11-28 16:58:39 -08:00
{"account.owner CONTAINS 'an'", 1},
2017-11-26 17:16:21 -08:00
// search using CONTAINS
2017-11-28 16:58:39 -08:00
{"account.owner CONTAINS 'Vlad'", 0},
2017-11-26 17:16:21 -08:00
}
for _, tc := range testCases {
t.Run(tc.q, func(t *testing.T) {
results, err := indexer.Search(query.MustParse(tc.q))
2017-11-28 16:58:39 -08:00
assert.NoError(t, err)
2017-11-26 17:16:21 -08:00
assert.Len(t, results, tc.resultsLength)
if tc.resultsLength > 0 {
2017-11-28 16:58:39 -08:00
assert.Equal(t, []*types.TxResult{txResult}, results)
2017-11-26 17:16:21 -08:00
}
})
}
}
func TestTxSearchOneTxWithMultipleSameTagsButDifferentValues(t *testing.T) {
2017-11-30 18:15:03 -08:00
allowedTags := []string{"account.number"}
indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
txResult := txResultWithTags([]cmn.KVPair{
{Key: []byte("account.number"), Value: []byte("1")},
{Key: []byte("account.number"), Value: []byte("2")},
2017-11-30 21:02:40 -08:00
})
err := indexer.Index(txResult)
require.NoError(t, err)
results, err := indexer.Search(query.MustParse("account.number >= 1"))
assert.NoError(t, err)
assert.Len(t, results, 1)
assert.Equal(t, []*types.TxResult{txResult}, results)
}
func TestTxSearchMultipleTxs(t *testing.T) {
allowedTags := []string{"account.number"}
indexer := NewTxIndex(db.NewMemDB(), IndexTags(allowedTags))
// indexed first, but bigger height (to test the order of transactions)
txResult := txResultWithTags([]cmn.KVPair{
{Key: []byte("account.number"), Value: []byte("1")},
})
txResult.Tx = types.Tx("Bob's account")
txResult.Height = 2
err := indexer.Index(txResult)
require.NoError(t, err)
// indexed second, but smaller height (to test the order of transactions)
txResult2 := txResultWithTags([]cmn.KVPair{
{Key: []byte("account.number"), Value: []byte("2")},
})
txResult2.Tx = types.Tx("Alice's account")
txResult2.Height = 1
err = indexer.Index(txResult2)
require.NoError(t, err)
results, err := indexer.Search(query.MustParse("account.number >= 1"))
assert.NoError(t, err)
require.Len(t, results, 2)
assert.Equal(t, []*types.TxResult{txResult2, txResult}, results)
}
2017-11-30 21:02:40 -08:00
func TestIndexAllTags(t *testing.T) {
indexer := NewTxIndex(db.NewMemDB(), IndexAllTags())
txResult := txResultWithTags([]cmn.KVPair{
cmn.KVPair{Key: []byte("account.owner"), Value: []byte("Ivan")},
cmn.KVPair{Key: []byte("account.number"), Value: []byte("1")},
2017-11-30 21:02:40 -08:00
})
err := indexer.Index(txResult)
require.NoError(t, err)
results, err := indexer.Search(query.MustParse("account.number >= 1"))
assert.NoError(t, err)
2017-11-30 21:02:40 -08:00
assert.Len(t, results, 1)
assert.Equal(t, []*types.TxResult{txResult}, results)
2017-11-30 21:02:40 -08:00
results, err = indexer.Search(query.MustParse("account.owner = 'Ivan'"))
assert.NoError(t, err)
assert.Len(t, results, 1)
assert.Equal(t, []*types.TxResult{txResult}, results)
}
func txResultWithTags(tags []cmn.KVPair) *types.TxResult {
2017-11-30 21:02:40 -08:00
tx := types.Tx("HELLO WORLD")
2018-04-07 09:47:19 -07:00
return &types.TxResult{
Height: 1,
Index: 0,
Tx: tx,
Result: abci.ResponseDeliverTx{
Data: []byte{0},
Code: abci.CodeTypeOK,
Log: "",
Tags: tags,
},
}
2017-11-30 21:02:40 -08:00
}
2018-05-11 01:09:41 -07:00
func benchmarkTxIndex(txsCount int64, b *testing.B) {
2017-04-18 17:55:40 -07:00
dir, err := ioutil.TempDir("", "tx_index_db")
if err != nil {
b.Fatal(err)
}
2017-10-03 15:49:20 -07:00
defer os.RemoveAll(dir) // nolint: errcheck
2018-09-17 02:25:17 -07:00
store := db.NewDB("tx_index", "leveldb", dir)
2017-11-30 18:02:39 -08:00
indexer := NewTxIndex(store)
batch := txindex.NewBatch(txsCount)
txIndex := uint32(0)
2018-05-11 01:09:41 -07:00
for i := int64(0); i < txsCount; i++ {
tx := cmn.RandBytes(250)
txResult := &types.TxResult{
Height: 1,
Index: txIndex,
Tx: tx,
Result: abci.ResponseDeliverTx{
Data: []byte{0},
Code: abci.CodeTypeOK,
Log: "",
Tags: []cmn.KVPair{},
},
}
2017-11-26 17:16:21 -08:00
if err := batch.Add(txResult); err != nil {
2017-09-06 08:50:43 -07:00
b.Fatal(err)
}
txIndex++
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
2017-11-28 16:58:39 -08:00
err = indexer.AddBatch(batch)
2017-06-27 13:05:21 -07:00
}
if err != nil {
b.Fatal(err)
}
}
2017-04-18 16:29:02 -07:00
func BenchmarkTxIndex1(b *testing.B) { benchmarkTxIndex(1, b) }
func BenchmarkTxIndex500(b *testing.B) { benchmarkTxIndex(500, b) }
func BenchmarkTxIndex1000(b *testing.B) { benchmarkTxIndex(1000, b) }
func BenchmarkTxIndex2000(b *testing.B) { benchmarkTxIndex(2000, b) }
func BenchmarkTxIndex10000(b *testing.B) { benchmarkTxIndex(10000, b) }