2019-10-07 16:45:01 +00:00
|
|
|
package storage
|
|
|
|
|
|
|
|
import (
|
2021-12-28 14:07:52 +00:00
|
|
|
"bytes"
|
2019-10-07 16:45:01 +00:00
|
|
|
"reflect"
|
|
|
|
"runtime"
|
2021-12-28 14:07:52 +00:00
|
|
|
"sort"
|
2019-10-07 16:45:01 +00:00
|
|
|
"testing"
|
|
|
|
|
2021-07-18 13:32:10 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
2019-10-07 16:45:01 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
type dbSetup struct {
|
|
|
|
name string
|
2021-10-05 12:13:19 +00:00
|
|
|
create func(testing.TB) Store
|
2019-10-07 16:45:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type dbTestFunction func(*testing.T, Store)
|
|
|
|
|
|
|
|
func testStoreClose(t *testing.T, s Store) {
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStorePutAndGet(t *testing.T, s Store) {
|
|
|
|
key := []byte("foo")
|
|
|
|
value := []byte("bar")
|
|
|
|
|
|
|
|
require.NoError(t, s.Put(key, value))
|
|
|
|
|
|
|
|
result, err := s.Get(key)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
require.Equal(t, value, result)
|
|
|
|
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStoreGetNonExistent(t *testing.T, s Store) {
|
|
|
|
key := []byte("sparse")
|
|
|
|
|
|
|
|
_, err := s.Get(key)
|
|
|
|
assert.Equal(t, err, ErrKeyNotFound)
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStorePutBatch(t *testing.T, s Store) {
|
|
|
|
var (
|
|
|
|
key = []byte("foo")
|
|
|
|
value = []byte("bar")
|
|
|
|
batch = s.Batch()
|
|
|
|
)
|
|
|
|
// Test that key and value are copied when batching.
|
2021-07-18 13:32:10 +00:00
|
|
|
keycopy := slice.Copy(key)
|
|
|
|
valuecopy := slice.Copy(value)
|
2019-10-07 16:45:01 +00:00
|
|
|
|
|
|
|
batch.Put(keycopy, valuecopy)
|
|
|
|
copy(valuecopy, key)
|
|
|
|
copy(keycopy, value)
|
|
|
|
|
|
|
|
require.NoError(t, s.PutBatch(batch))
|
|
|
|
newVal, err := s.Get(key)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
require.Equal(t, value, newVal)
|
|
|
|
assert.Equal(t, value, newVal)
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStoreSeek(t *testing.T, s Store) {
|
2021-12-16 13:55:50 +00:00
|
|
|
// Use the same set of kvs to test Seek with different prefix/start values.
|
|
|
|
kvs := []KeyValue{
|
|
|
|
{[]byte("10"), []byte("bar")},
|
|
|
|
{[]byte("11"), []byte("bara")},
|
|
|
|
{[]byte("20"), []byte("barb")},
|
|
|
|
{[]byte("21"), []byte("barc")},
|
|
|
|
{[]byte("22"), []byte("bard")},
|
|
|
|
{[]byte("30"), []byte("bare")},
|
|
|
|
{[]byte("31"), []byte("barf")},
|
2019-10-07 16:45:01 +00:00
|
|
|
}
|
2021-12-16 13:55:50 +00:00
|
|
|
for _, v := range kvs {
|
2021-12-28 14:07:52 +00:00
|
|
|
require.NoError(t, s.Put(v.Key, v.Value))
|
2019-10-07 16:45:01 +00:00
|
|
|
}
|
|
|
|
|
2022-01-17 17:41:51 +00:00
|
|
|
check := func(t *testing.T, goodprefix, start []byte, goodkvs []KeyValue, backwards bool, cont func(k, v []byte) bool) {
|
2021-12-28 13:01:44 +00:00
|
|
|
// Seek result expected to be sorted in an ascending (for forwards seeking) or descending (for backwards seeking) way.
|
|
|
|
cmpFunc := func(i, j int) bool {
|
2021-12-16 13:55:50 +00:00
|
|
|
return bytes.Compare(goodkvs[i].Key, goodkvs[j].Key) < 0
|
2021-12-28 13:01:44 +00:00
|
|
|
}
|
|
|
|
if backwards {
|
|
|
|
cmpFunc = func(i, j int) bool {
|
|
|
|
return bytes.Compare(goodkvs[i].Key, goodkvs[j].Key) > 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Slice(goodkvs, cmpFunc)
|
2021-12-16 13:55:50 +00:00
|
|
|
|
2021-12-28 13:01:44 +00:00
|
|
|
rng := SeekRange{
|
2021-12-16 13:55:50 +00:00
|
|
|
Prefix: goodprefix,
|
|
|
|
Start: start,
|
2021-12-28 13:01:44 +00:00
|
|
|
}
|
|
|
|
if backwards {
|
|
|
|
rng.Backwards = true
|
|
|
|
}
|
|
|
|
actual := make([]KeyValue, 0, len(goodkvs))
|
2022-01-17 17:41:51 +00:00
|
|
|
s.Seek(rng, func(k, v []byte) bool {
|
2021-12-16 13:55:50 +00:00
|
|
|
actual = append(actual, KeyValue{
|
|
|
|
Key: slice.Copy(k),
|
|
|
|
Value: slice.Copy(v),
|
|
|
|
})
|
2022-01-17 17:41:51 +00:00
|
|
|
if cont == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return cont(k, v)
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
|
|
|
assert.Equal(t, goodkvs, actual)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("non-empty prefix, empty start", func(t *testing.T) {
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("forwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
// Given this prefix...
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
// and empty start range...
|
|
|
|
start := []byte{}
|
|
|
|
// these pairs should be found.
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, false, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("0")
|
|
|
|
start := []byte{}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, false, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
// Given this prefix...
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
// and empty start range...
|
|
|
|
start := []byte{}
|
|
|
|
// these pairs should be found.
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, false, func(k, v []byte) bool {
|
|
|
|
return string(k) < "21"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
|
|
|
|
t.Run("backwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte{}
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, true, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("0")
|
|
|
|
start := []byte{}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, true, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte{}
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, true, func(k, v []byte) bool {
|
|
|
|
return string(k) > "21"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("non-empty prefix, non-empty start", func(t *testing.T) {
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("forwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
2022-01-17 17:41:51 +00:00
|
|
|
start := []byte("1") // start will be appended to goodprefix to start seek from
|
2021-12-28 13:01:44 +00:00
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, false, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte("3") // start is more than all keys prefixed by '2'.
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, false, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte("0") // start will be appended to goodprefix to start seek from
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, false, func(k, v []byte) bool {
|
|
|
|
return string(k) < "21"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("backwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
2022-01-17 17:41:51 +00:00
|
|
|
start := []byte("1") // start will be appended to goodprefix to start seek from
|
2021-12-28 13:01:44 +00:00
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, true, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte(".") // start is less than all keys prefixed by '2'.
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, true, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodprefix := []byte("2")
|
|
|
|
start := []byte("2") // start will be appended to goodprefix to start seek from
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[4], // key = "24"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, true, func(k, v []byte) bool {
|
|
|
|
return string(k) > "21"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
2021-12-28 14:07:52 +00:00
|
|
|
})
|
|
|
|
|
2021-12-16 13:55:50 +00:00
|
|
|
t.Run("empty prefix, non-empty start", func(t *testing.T) {
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("forwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("21")
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
kvs[5], // key = "30"
|
|
|
|
kvs[6], // key = "31"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, false, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("32") // start is more than all keys.
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, false, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("21")
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
kvs[5], // key = "30"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, false, func(k, v []byte) bool {
|
|
|
|
return string(k) < "30"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("backwards", func(t *testing.T) {
|
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("21")
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[1], // key = "11"
|
|
|
|
kvs[0], // key = "10"
|
|
|
|
}
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, goodkvs, true, nil)
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("no matching items", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("0") // start is less than all keys.
|
2022-01-17 17:41:51 +00:00
|
|
|
check(t, goodprefix, start, []KeyValue{}, true, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte("21")
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[1], // key = "11"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, true, func(k, v []byte) bool {
|
|
|
|
return string(k) > "11"
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-28 14:07:52 +00:00
|
|
|
})
|
2019-10-07 16:45:01 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
|
|
|
|
t.Run("empty prefix, empty start", func(t *testing.T) {
|
|
|
|
goodprefix := []byte{}
|
|
|
|
start := []byte{}
|
|
|
|
goodkvs := make([]KeyValue, len(kvs))
|
|
|
|
copy(goodkvs, kvs)
|
2021-12-28 13:01:44 +00:00
|
|
|
t.Run("forwards", func(t *testing.T) {
|
2022-01-17 17:41:51 +00:00
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
check(t, goodprefix, start, goodkvs, false, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[0], // key = "10"
|
|
|
|
kvs[1], // key = "11"
|
|
|
|
kvs[2], // key = "20"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, false, func(k, v []byte) bool {
|
|
|
|
return string(k) < "21"
|
|
|
|
})
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
|
|
|
t.Run("backwards", func(t *testing.T) {
|
2022-01-17 17:41:51 +00:00
|
|
|
t.Run("good", func(t *testing.T) {
|
|
|
|
check(t, goodprefix, start, goodkvs, true, nil)
|
|
|
|
})
|
|
|
|
t.Run("early stop", func(t *testing.T) {
|
|
|
|
goodkvs := []KeyValue{
|
|
|
|
kvs[6], // key = "31"
|
|
|
|
kvs[5], // key = "30"
|
|
|
|
kvs[4], // key = "22"
|
|
|
|
kvs[3], // key = "21"
|
|
|
|
}
|
|
|
|
check(t, goodprefix, start, goodkvs, true, func(k, v []byte) bool {
|
|
|
|
return string(k) > "21"
|
|
|
|
})
|
|
|
|
})
|
2021-12-28 13:01:44 +00:00
|
|
|
})
|
2021-12-16 13:55:50 +00:00
|
|
|
})
|
|
|
|
|
2019-10-07 16:45:01 +00:00
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStoreDeleteNonExistent(t *testing.T, s Store) {
|
|
|
|
key := []byte("sparse")
|
|
|
|
|
|
|
|
assert.NoError(t, s.Delete(key))
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStorePutAndDelete(t *testing.T, s Store) {
|
|
|
|
key := []byte("foo")
|
|
|
|
value := []byte("bar")
|
|
|
|
|
|
|
|
require.NoError(t, s.Put(key, value))
|
|
|
|
|
|
|
|
err := s.Delete(key)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
|
|
|
_, err = s.Get(key)
|
|
|
|
assert.NotNil(t, err)
|
|
|
|
assert.Equal(t, err, ErrKeyNotFound)
|
|
|
|
|
|
|
|
// Double delete.
|
|
|
|
err = s.Delete(key)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func testStorePutBatchWithDelete(t *testing.T, s Store) {
|
|
|
|
var (
|
|
|
|
toBeStored = map[string][]byte{
|
|
|
|
"foo": []byte("bar"),
|
|
|
|
"bar": []byte("baz"),
|
|
|
|
}
|
|
|
|
deletedInBatch = map[string][]byte{
|
|
|
|
"edc": []byte("rfv"),
|
|
|
|
"tgb": []byte("yhn"),
|
|
|
|
}
|
|
|
|
readdedToBatch = map[string][]byte{
|
|
|
|
"yhn": []byte("ujm"),
|
|
|
|
}
|
|
|
|
toBeDeleted = map[string][]byte{
|
|
|
|
"qaz": []byte("wsx"),
|
|
|
|
"qwe": []byte("123"),
|
|
|
|
}
|
|
|
|
toStay = map[string][]byte{
|
|
|
|
"key": []byte("val"),
|
|
|
|
"faa": []byte("bra"),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
for k, v := range toBeDeleted {
|
|
|
|
require.NoError(t, s.Put([]byte(k), v))
|
|
|
|
}
|
|
|
|
for k, v := range toStay {
|
|
|
|
require.NoError(t, s.Put([]byte(k), v))
|
|
|
|
}
|
|
|
|
batch := s.Batch()
|
|
|
|
for k, v := range toBeStored {
|
|
|
|
batch.Put([]byte(k), v)
|
|
|
|
}
|
|
|
|
for k := range toBeDeleted {
|
|
|
|
batch.Delete([]byte(k))
|
|
|
|
}
|
|
|
|
for k, v := range readdedToBatch {
|
|
|
|
batch.Put([]byte(k), v)
|
|
|
|
}
|
|
|
|
for k, v := range deletedInBatch {
|
|
|
|
batch.Put([]byte(k), v)
|
|
|
|
}
|
|
|
|
for k := range deletedInBatch {
|
|
|
|
batch.Delete([]byte(k))
|
|
|
|
}
|
|
|
|
for k := range readdedToBatch {
|
|
|
|
batch.Delete([]byte(k))
|
|
|
|
}
|
|
|
|
for k, v := range readdedToBatch {
|
|
|
|
batch.Put([]byte(k), v)
|
|
|
|
}
|
|
|
|
require.NoError(t, s.PutBatch(batch))
|
|
|
|
toBe := []map[string][]byte{toStay, toBeStored, readdedToBatch}
|
|
|
|
notToBe := []map[string][]byte{deletedInBatch, toBeDeleted}
|
|
|
|
for _, kvs := range toBe {
|
|
|
|
for k, v := range kvs {
|
|
|
|
value, err := s.Get([]byte(k))
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, value, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, kvs := range notToBe {
|
|
|
|
for k, v := range kvs {
|
|
|
|
_, err := s.Get([]byte(k))
|
|
|
|
assert.Equal(t, ErrKeyNotFound, err, "%s:%s", k, v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NoError(t, s.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAllDBs(t *testing.T) {
|
|
|
|
var DBs = []dbSetup{
|
|
|
|
{"BoltDB", newBoltStoreForTesting},
|
|
|
|
{"LevelDB", newLevelDBForTesting},
|
2019-10-16 13:41:50 +00:00
|
|
|
{"MemCached", newMemCachedStoreForTesting},
|
2019-10-07 16:45:01 +00:00
|
|
|
{"Memory", newMemoryStoreForTesting},
|
|
|
|
}
|
|
|
|
var tests = []dbTestFunction{testStoreClose, testStorePutAndGet,
|
|
|
|
testStoreGetNonExistent, testStorePutBatch, testStoreSeek,
|
|
|
|
testStoreDeleteNonExistent, testStorePutAndDelete,
|
|
|
|
testStorePutBatchWithDelete}
|
|
|
|
for _, db := range DBs {
|
|
|
|
for _, test := range tests {
|
|
|
|
s := db.create(t)
|
|
|
|
twrapper := func(t *testing.T) {
|
|
|
|
test(t, s)
|
|
|
|
}
|
|
|
|
fname := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name()
|
|
|
|
t.Run(db.name+"/"+fname, twrapper)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|