Skip to content

Commit

Permalink
add test cases, improve coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
yihuang committed Oct 25, 2022
1 parent 55d6ed9 commit 936cc90
Showing 1 changed file with 211 additions and 88 deletions.
299 changes: 211 additions & 88 deletions versiondb/backend_test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tm-db"

"github.com/cosmos/cosmos-sdk/store/types"
)
Expand All @@ -19,84 +20,111 @@ var (
)

func SetupTestDB(t *testing.T, store VersionStore) {
require.NoError(t, store.PutAtVersion(0, []types.StoreKVPair{
{StoreKey: "bank", Key: key1, Value: value1},
{StoreKey: "bank", Key: key2, Value: value2},
{StoreKey: "staking", Key: key1, Value: value1},
{StoreKey: "evm", Key: key1, Value: value1},
}))
require.NoError(t, store.PutAtVersion(1, []types.StoreKVPair{
{StoreKey: "bank", Key: key1, Value: value2},
{StoreKey: "staking", Key: key1_subkey, Value: value1},
}))
require.NoError(t, store.PutAtVersion(2, []types.StoreKVPair{
{StoreKey: "staking", Delete: true, Key: key1},
{StoreKey: "bank", Delete: true, Key: key1},
}))
require.NoError(t, store.PutAtVersion(3, []types.StoreKVPair{
{StoreKey: "staking", Key: key1, Value: value2},
}))
changeSets := [][]types.StoreKVPair{
{
{StoreKey: "evm", Key: []byte("delete-in-block2"), Value: []byte("1")},
{StoreKey: "evm", Key: []byte("re-add-in-block3"), Value: []byte("1")},
{StoreKey: "evm", Key: []byte("z-genesis-only"), Value: []byte("2")},
{StoreKey: "evm", Key: []byte("modify-in-block2"), Value: []byte("1")},
{StoreKey: "staking", Key: []byte("key1"), Value: []byte("value1")},
{StoreKey: "staking", Key: []byte("key1/subkey"), Value: []byte("value1")},
},
{
{StoreKey: "evm", Key: []byte("re-add-in-block3"), Delete: true},
{StoreKey: "evm", Key: []byte("add-in-block1"), Value: []byte("1")},
{StoreKey: "staking", Key: []byte("key1"), Delete: true},
},
{
{StoreKey: "evm", Key: []byte("add-in-block2"), Value: []byte("1")},
{StoreKey: "evm", Key: []byte("delete-in-block2"), Delete: true},
{StoreKey: "evm", Key: []byte("modify-in-block2"), Value: []byte("2")},
{StoreKey: "evm", Key: []byte("key2"), Delete: true},
{StoreKey: "staking", Key: []byte("key1"), Value: []byte("value2")},
},
{
{StoreKey: "evm", Key: []byte("re-add-in-block3"), Value: []byte("2")},
},
{
{StoreKey: "evm", Key: []byte("re-add-in-block3"), Delete: true},
},
}
for i, changeSet := range changeSets {
require.NoError(t, store.PutAtVersion(int64(i), changeSet))
}
}

func Run(t *testing.T, storeCreator func() VersionStore) {
testBasics(t, storeCreator())
testIterator(t, storeCreator())
testHeightInFuture(t, storeCreator())

// test delete in genesis
store := storeCreator()
err := store.PutAtVersion(0, []types.StoreKVPair{
{StoreKey: "evm", Key: []byte{1}, Delete: true},
})
require.Error(t, err)
}

func testBasics(t *testing.T, store VersionStore) {
var v int64

SetupTestDB(t, store)

value, err := store.GetAtVersion("staking", key1, nil)
value, err := store.GetAtVersion("evm", []byte("z-genesis-only"), nil)
require.NoError(t, err)
require.Equal(t, value, value2)
require.Equal(t, value, []byte("2"))

v = 2
ok, err := store.HasAtVersion("staking", key1, &v)
v = 4
ok, err := store.HasAtVersion("evm", []byte("z-genesis-only"), &v)
require.NoError(t, err)
require.False(t, ok)
value, err = store.GetAtVersion("staking", key1, &v)
require.True(t, ok)
value, err = store.GetAtVersion("evm", []byte("z-genesis-only"), &v)
require.NoError(t, err)
require.Equal(t, value, []byte("2"))

value, err = store.GetAtVersion("evm", []byte("re-add-in-block3"), nil)
require.NoError(t, err)
require.Empty(t, value)

v = 1
ok, err = store.HasAtVersion("staking", key1, &v)
ok, err = store.HasAtVersion("staking", key1, nil)
require.NoError(t, err)
require.True(t, ok)

value, err = store.GetAtVersion("staking", key1, nil)
require.NoError(t, err)
require.Equal(t, value, []byte("value2"))

v = 2
value, err = store.GetAtVersion("staking", key1, &v)
require.NoError(t, err)
require.Equal(t, value, value1)
require.Equal(t, value, []byte("value2"))

// never changed since genesis
ok, err = store.HasAtVersion("bank", key2, nil)
ok, err = store.HasAtVersion("staking", key1, &v)
require.NoError(t, err)
require.True(t, ok)
value, err = store.GetAtVersion("bank", key2, nil)
require.NoError(t, err)
require.Equal(t, value2, value)
for i := int64(1); i < 4; i++ {
// never changed
ok, err = store.HasAtVersion("bank", key2, &i)
require.NoError(t, err)
require.True(t, ok)

value, err = store.GetAtVersion("bank", key2, &i)
require.NoError(t, err)
require.Equal(t, value2, value)
}

require.NoError(t, store.PutAtVersion(4, []types.StoreKVPair{
{StoreKey: "bank", Key: key2, Value: value3},
}))
v = 3
value, err = store.GetAtVersion("bank", key2, &v)
v = 0
value, err = store.GetAtVersion("staking", key1, &v)
require.NoError(t, err)
require.Equal(t, value2, value)
v = 4
value, err = store.GetAtVersion("bank", key2, &v)
require.Equal(t, value, []byte("value1"))

v = 1
value, err = store.GetAtVersion("staking", key1, &v)
require.NoError(t, err)
require.Empty(t, value)

ok, err = store.HasAtVersion("staking", key1, &v)
require.NoError(t, err)
require.False(t, ok)

v = 0
value, err = store.GetAtVersion("staking", key1, &v)
require.NoError(t, err)
require.Equal(t, value3, value)
require.Equal(t, value1, value)
value, err = store.GetAtVersion("staking", key1_subkey, &v)
require.NoError(t, err)
require.Equal(t, value1, value)
}

type KVPair struct {
Expand All @@ -107,47 +135,142 @@ type KVPair struct {
func testIterator(t *testing.T, store VersionStore) {
SetupTestDB(t, store)

result := []struct {
version int64
reverse bool
storeKey string
expItems []KVPair
}{
{-1, false, "bank", []KVPair{{Key: key2, Value: value2}}},
{3, false, "bank", []KVPair{{Key: key2, Value: value2}}},
{1, false, "bank", []KVPair{{Key: key1, Value: value2}, {Key: key2, Value: value2}}},
{1, true, "bank", []KVPair{{Key: key2, Value: value2}, {Key: key1, Value: value2}}},
{2, true, "bank", []KVPair{{Key: key2, Value: value2}}},
{0, false, "bank", []KVPair{{Key: key1, Value: value1}, {Key: key2, Value: value2}}},
{0, true, "bank", []KVPair{{Key: key2, Value: value2}, {Key: key1, Value: value1}}},
{-1, true, "staking", []KVPair{{Key: key1_subkey, Value: value1}, {Key: key1, Value: value2}}},
{3, false, "staking", []KVPair{{Key: key1, Value: value2}, {Key: key1_subkey, Value: value1}}},
{3, true, "staking", []KVPair{{Key: key1_subkey, Value: value1}, {Key: key1, Value: value2}}},
{2, false, "staking", []KVPair{{Key: key1_subkey, Value: value1}}},
{1, false, "staking", []KVPair{{Key: key1, Value: value1}, {Key: key1_subkey, Value: value1}}},
expItems := [][]KVPair{
{
KVPair{[]byte("delete-in-block2"), []byte("1")},
KVPair{[]byte("modify-in-block2"), []byte("1")},
KVPair{[]byte("re-add-in-block3"), []byte("1")},
KVPair{[]byte("z-genesis-only"), []byte("2")},
},
{
KVPair{[]byte("add-in-block1"), []byte("1")},
KVPair{[]byte("delete-in-block2"), []byte("1")},
KVPair{[]byte("modify-in-block2"), []byte("1")},
KVPair{[]byte("z-genesis-only"), []byte("2")},
},
{
KVPair{[]byte("add-in-block1"), []byte("1")},
KVPair{[]byte("add-in-block2"), []byte("1")},
KVPair{[]byte("modify-in-block2"), []byte("2")},
KVPair{[]byte("z-genesis-only"), []byte("2")},
},
{
KVPair{[]byte("add-in-block1"), []byte("1")},
KVPair{[]byte("add-in-block2"), []byte("1")},
KVPair{[]byte("modify-in-block2"), []byte("2")},
KVPair{[]byte("re-add-in-block3"), []byte("2")},
KVPair{[]byte("z-genesis-only"), []byte("2")},
},
{
KVPair{[]byte("add-in-block1"), []byte("1")},
KVPair{[]byte("add-in-block2"), []byte("1")},
KVPair{[]byte("modify-in-block2"), []byte("2")},
KVPair{[]byte("z-genesis-only"), []byte("2")},
},
}

for _, tc := range result {
t.Run(fmt.Sprintf("%s-%d-%t", tc.storeKey, tc.version, tc.reverse), func(t *testing.T) {
var version *int64
if tc.version >= 0 {
version = &tc.version
}
var it types.Iterator
var err error
if tc.reverse {
it, err = store.ReverseIteratorAtVersion(tc.storeKey, nil, nil, version)
} else {
it, err = store.IteratorAtVersion(tc.storeKey, nil, nil, version)
}
for i, exp := range expItems {
t.Run(fmt.Sprintf("block-%d", i), func(t *testing.T) {
v := int64(i)
it, err := store.IteratorAtVersion("evm", nil, nil, &v)
require.NoError(t, err)
defer it.Close()
require.Equal(t, exp, consumeIterator(it))

var result []KVPair
for ; it.Valid(); it.Next() {
result = append(result, KVPair{it.Key(), it.Value()})
}
require.Equal(t, tc.expItems, result)
it, err = store.ReverseIteratorAtVersion("evm", nil, nil, &v)
require.NoError(t, err)
actual := consumeIterator(it)
require.Equal(t, len(exp), len(actual))
require.Equal(t, reversed(exp), actual)
})
}

it, err := store.IteratorAtVersion("evm", nil, nil, nil)
require.Equal(t, expItems[len(expItems)-1], consumeIterator(it))

it, err = store.ReverseIteratorAtVersion("evm", nil, nil, nil)
require.Equal(t, reversed(expItems[len(expItems)-1]), consumeIterator(it))

// with start parameter
v := int64(2)
it, err = store.IteratorAtVersion("evm", []byte("\xff"), nil, &v)
require.NoError(t, err)
require.Empty(t, consumeIterator(it))
it, err = store.ReverseIteratorAtVersion("evm", nil, []byte("\x00"), &v)
require.NoError(t, err)
require.Empty(t, consumeIterator(it))

it, err = store.IteratorAtVersion("evm", []byte("modify-in-block2"), nil, &v)
require.NoError(t, err)
require.Equal(t, expItems[2][len(expItems[2])-2:], consumeIterator(it))

it, err = store.ReverseIteratorAtVersion("evm", nil, []byte("mp"), &v)
require.NoError(t, err)
require.Equal(t,
reversed(expItems[2][:len(expItems[2])-1]),
consumeIterator(it),
)

it, err = store.ReverseIteratorAtVersion("evm", nil, []byte("modify-in-block3"), &v)
require.NoError(t, err)
require.Equal(t,
reversed(expItems[2][:len(expItems[2])-1]),
consumeIterator(it),
)

// delete the last key, cover some edge cases
v = int64(len(expItems))
err = store.PutAtVersion(
v,
[]types.StoreKVPair{
{StoreKey: "evm", Key: []byte("z-genesis-only"), Delete: true},
},
)
require.NoError(t, err)
it, err = store.IteratorAtVersion("evm", nil, nil, &v)
require.NoError(t, err)
require.Equal(t,
expItems[v-1][:len(expItems[v-1])-1],
consumeIterator(it),
)
v -= 1
it, err = store.IteratorAtVersion("evm", nil, nil, &v)
require.NoError(t, err)
require.Equal(t,
expItems[v],
consumeIterator(it),
)
}

func testHeightInFuture(t *testing.T, store VersionStore) {
SetupTestDB(t, store)

latest, err := store.GetLatestVersion()
require.NoError(t, err)

v := latest + 1
_, err = store.GetAtVersion("staking", key1, &v)
require.Error(t, err)
_, err = store.HasAtVersion("staking", key1, &v)
require.Error(t, err)
_, err = store.IteratorAtVersion("staking", nil, nil, &v)
require.Error(t, err)
_, err = store.ReverseIteratorAtVersion("staking", nil, nil, &v)
require.Error(t, err)
}

func consumeIterator(it dbm.Iterator) []KVPair {
var result []KVPair
for ; it.Valid(); it.Next() {
result = append(result, KVPair{it.Key(), it.Value()})
}
it.Close()
return result
}

// reversed clone and reverse the slice
func reversed[S ~[]E, E any](s S) []E {
r := make([]E, len(s))
for i, j := 0, len(s)-1; i <= j; i, j = i+1, j-1 {
r[i], r[j] = s[j], s[i]
}
return r
}

0 comments on commit 936cc90

Please sign in to comment.