261 lines
6.1 KiB
Go
261 lines
6.1 KiB
Go
package store_test
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jrapoport/chestnut/log"
|
|
"github.com/jrapoport/chestnut/storage"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
type testCase struct {
|
|
name string
|
|
key string
|
|
value string
|
|
err assert.ErrorAssertionFunc
|
|
has assert.BoolAssertionFunc
|
|
}
|
|
|
|
type testObject struct {
|
|
Value string
|
|
}
|
|
|
|
var (
|
|
testName = "test-name"
|
|
testKey = "test-key"
|
|
testValue = "test-value"
|
|
testObj = &testObject{"hello"}
|
|
)
|
|
|
|
var putTests = []testCase{
|
|
{"", "", "", assert.Error, assert.False},
|
|
{"a", testKey, "", assert.Error, assert.False},
|
|
{"b", testKey, testValue, assert.NoError, assert.True},
|
|
{"c/c", testKey, testValue, assert.NoError, assert.True},
|
|
{".d", testKey, testValue, assert.NoError, assert.True},
|
|
{testName, "", "", assert.Error, assert.False},
|
|
{testName, "a", "", assert.Error, assert.False},
|
|
{testName, "b", testValue, assert.NoError, assert.True},
|
|
{testName, "c/c", testValue, assert.NoError, assert.True},
|
|
{testName, ".d", testValue, assert.NoError, assert.True},
|
|
{testName, testKey, testValue, assert.NoError, assert.True},
|
|
}
|
|
|
|
var tests = append(putTests,
|
|
testCase{testName, "not-found", "", assert.Error, assert.False},
|
|
)
|
|
|
|
type storeFunc = func(string, ...storage.StoreOption) storage.Storage
|
|
|
|
type storeTestSuite struct {
|
|
suite.Suite
|
|
storeFunc
|
|
store storage.Storage
|
|
path string
|
|
}
|
|
|
|
// TestStore tests a store
|
|
func TestStore(t *testing.T, fn storeFunc) {
|
|
ts := new(storeTestSuite)
|
|
ts.storeFunc = fn
|
|
suite.Run(t, ts)
|
|
}
|
|
|
|
// SetupTest
|
|
func (ts *storeTestSuite) SetupTest() {
|
|
ts.path = ts.T().TempDir()
|
|
ts.store = ts.storeFunc(ts.path)
|
|
err := ts.store.Open()
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
|
|
// TearDownTest
|
|
func (ts *storeTestSuite) TearDownTest() {
|
|
err := ts.store.Close()
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
|
|
// BeforeTest
|
|
func (ts *storeTestSuite) BeforeTest(_, testName string) {
|
|
switch testName {
|
|
case "TestStorePut",
|
|
"TestStoreSave",
|
|
"TestStoreLoad",
|
|
"TestStoreList",
|
|
"TestStoreListAll",
|
|
"TestStoreWithLogger":
|
|
break
|
|
default:
|
|
ts.TestStorePut()
|
|
}
|
|
}
|
|
|
|
// TestStorePut
|
|
func (ts *storeTestSuite) TestStorePut() {
|
|
for i, test := range putTests {
|
|
err := ts.store.Put(test.name, []byte(test.key), []byte(test.value))
|
|
test.err(ts.T(), err, "%d test name: %s key: %s", i, test.name, test.key)
|
|
}
|
|
}
|
|
|
|
// TestStoreSave
|
|
func (ts *storeTestSuite) TestStoreSave() {
|
|
err := ts.store.Save(testName, []byte(testKey), testObj)
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
|
|
// TestStoreLoad
|
|
func (ts *storeTestSuite) TestStoreLoad() {
|
|
ts.T().Run("Setup", func(t *testing.T) {
|
|
ts.TestStoreSave()
|
|
})
|
|
to := &testObject{}
|
|
err := ts.store.Load(testName, []byte(testKey), to)
|
|
assert.NoError(ts.T(), err)
|
|
assert.Equal(ts.T(), testObj, to)
|
|
}
|
|
|
|
// TestStoreGet
|
|
func (ts *storeTestSuite) TestStoreGet() {
|
|
for i, test := range tests {
|
|
value, err := ts.store.Get(test.name, []byte(test.key))
|
|
test.err(ts.T(), err, "%d test name: %s key: %s", i, test.name, test.key)
|
|
assert.Equal(ts.T(), test.value, string(value),
|
|
"%d test key: %s", i, test.key)
|
|
}
|
|
}
|
|
|
|
// TestStoreHas
|
|
func (ts *storeTestSuite) TestStoreHas() {
|
|
for i, test := range tests {
|
|
has, _ := ts.store.Has(test.name, []byte(test.key))
|
|
test.has(ts.T(), has, "%d test key: %s", i, test.key)
|
|
}
|
|
}
|
|
|
|
// TestStoreList
|
|
func (ts *storeTestSuite) TestStoreList() {
|
|
const listLen = 100
|
|
list := make([]string, listLen)
|
|
for i := 0; i < listLen; i++ {
|
|
list[i] = uuid.New().String()
|
|
err := ts.store.Put(testName, []byte(list[i]), []byte(testValue))
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
keys, err := ts.store.List(testName)
|
|
assert.NoError(ts.T(), err)
|
|
assert.Len(ts.T(), keys, listLen)
|
|
// put both lists in the same order so we can compare them
|
|
strKeys := make([]string, len(keys))
|
|
for i, k := range keys {
|
|
strKeys[i] = string(k)
|
|
}
|
|
sort.Strings(list)
|
|
sort.Strings(strKeys)
|
|
assert.Equal(ts.T(), list, strKeys)
|
|
}
|
|
|
|
// TestStoreListAll
|
|
func (ts *storeTestSuite) TestStoreListAll() {
|
|
const listLen = 100
|
|
list := make([]string, listLen)
|
|
for i := 0; i < listLen; i++ {
|
|
list[i] = uuid.New().String()
|
|
ns := fmt.Sprintf("%s%d", testName, i)
|
|
err := ts.store.Put(ns, []byte(list[i]), []byte(testValue))
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
keyMap, err := ts.store.ListAll()
|
|
assert.NoError(ts.T(), err)
|
|
var keys []string
|
|
for _, ks := range keyMap {
|
|
for _, k := range ks {
|
|
keys = append(keys, string(k))
|
|
}
|
|
}
|
|
assert.Len(ts.T(), keys, listLen)
|
|
sort.Strings(list)
|
|
sort.Strings(keys)
|
|
assert.Equal(ts.T(), list, keys)
|
|
}
|
|
|
|
// TestStoreDelete
|
|
func (ts *storeTestSuite) TestStoreDelete() {
|
|
var deleteTests = []struct {
|
|
key string
|
|
err assert.ErrorAssertionFunc
|
|
}{
|
|
{"", assert.Error},
|
|
{"a", assert.NoError},
|
|
{"b", assert.NoError},
|
|
{"c/c", assert.NoError},
|
|
{".d", assert.NoError},
|
|
{"eee", assert.NoError},
|
|
{"not-found", assert.NoError},
|
|
}
|
|
for i, test := range deleteTests {
|
|
err := ts.store.Delete(testName, []byte(test.key))
|
|
test.err(ts.T(), err, "%d test key: %s", i, test.key)
|
|
}
|
|
}
|
|
|
|
// TestStoreExport
|
|
func (ts *storeTestSuite) TestStoreExport() {
|
|
exTests := []struct {
|
|
path string
|
|
Err assert.ErrorAssertionFunc
|
|
}{
|
|
{"", assert.Error},
|
|
{ts.path, assert.Error},
|
|
{ts.T().TempDir(), assert.NoError},
|
|
}
|
|
for _, test := range exTests {
|
|
err := ts.store.Export(test.path)
|
|
test.Err(ts.T(), err)
|
|
if err == nil {
|
|
s2 := ts.storeFunc(test.path)
|
|
assert.NotNil(ts.T(), s2)
|
|
err = s2.Open()
|
|
assert.NoError(ts.T(), err)
|
|
keys, err := s2.ListAll()
|
|
assert.NoError(ts.T(), err)
|
|
assert.NotEmpty(ts.T(), keys)
|
|
err = s2.Close()
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestStoreWithLogger
|
|
func (ts *storeTestSuite) TestStoreWithLogger() {
|
|
levels := []log.Level{
|
|
log.DebugLevel,
|
|
log.InfoLevel,
|
|
log.WarnLevel,
|
|
log.ErrorLevel,
|
|
log.PanicLevel,
|
|
}
|
|
type LoggerOpt func(log.Level) storage.StoreOption
|
|
logOpts := []LoggerOpt{
|
|
storage.WithLogrusLogger,
|
|
storage.WithStdLogger,
|
|
storage.WithZapLogger,
|
|
}
|
|
path := ts.T().TempDir()
|
|
for _, level := range levels {
|
|
for _, logOpt := range logOpts {
|
|
opt := logOpt(level)
|
|
store := ts.storeFunc(path, opt)
|
|
assert.NotNil(ts.T(), store)
|
|
err := store.Open()
|
|
assert.NoError(ts.T(), err)
|
|
err = store.Close()
|
|
assert.NoError(ts.T(), err)
|
|
}
|
|
}
|
|
}
|