forked from TrueCloudLab/frostfs-node
Initial commit
Initial public review release v0.10.0
This commit is contained in:
commit
dadfd90dcd
276 changed files with 46331 additions and 0 deletions
501
lib/localstore/localstore_test.go
Normal file
501
lib/localstore/localstore_test.go
Normal file
|
@ -0,0 +1,501 @@
|
|||
package localstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neofs-api-go/container"
|
||||
"github.com/nspcc-dev/neofs-api-go/hash"
|
||||
"github.com/nspcc-dev/neofs-api-go/object"
|
||||
"github.com/nspcc-dev/neofs-api-go/refs"
|
||||
"github.com/nspcc-dev/neofs-node/lib/meta"
|
||||
"github.com/nspcc-dev/neofs-node/lib/metrics"
|
||||
"github.com/nspcc-dev/neofs-node/lib/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
testBucket struct {
|
||||
sync.RWMutex
|
||||
items map[string][]byte
|
||||
}
|
||||
|
||||
fakeCollector struct {
|
||||
sync.Mutex
|
||||
items map[refs.CID]uint64
|
||||
}
|
||||
)
|
||||
|
||||
func (f *fakeCollector) Start(_ context.Context) { panic("implement me") }
|
||||
func (f *fakeCollector) UpdateSpaceUsage() { panic("implement me") }
|
||||
func (f *fakeCollector) SetIterator(_ meta.Iterator) { panic("implement me") }
|
||||
func (f *fakeCollector) SetCounter(counter metrics.ObjectCounter) { panic("implement me") }
|
||||
|
||||
func (f *fakeCollector) UpdateContainer(cid refs.CID, size uint64, op metrics.SpaceOp) {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
switch op {
|
||||
case metrics.AddSpace:
|
||||
f.items[cid] += size
|
||||
case metrics.RemSpace:
|
||||
if val, ok := f.items[cid]; !ok || val < size {
|
||||
return
|
||||
}
|
||||
|
||||
f.items[cid] -= size
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func newCollector() metrics.Collector {
|
||||
return &fakeCollector{
|
||||
items: make(map[refs.CID]uint64),
|
||||
}
|
||||
}
|
||||
|
||||
func newTestBucket() *testBucket {
|
||||
return &testBucket{
|
||||
items: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// func (t *testBucket) Get(key []byte) ([]byte, error) {
|
||||
// t.Lock()
|
||||
// defer t.Unlock()
|
||||
//
|
||||
// val, ok := t.items[base58.Encode(key)]
|
||||
// if !ok {
|
||||
// return nil, errors.New("item not found")
|
||||
// }
|
||||
//
|
||||
// return val, nil
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Set(key, value []byte) error {
|
||||
// t.Lock()
|
||||
// defer t.Unlock()
|
||||
//
|
||||
// t.items[base58.Encode(key)] = value
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Del(key []byte) error {
|
||||
// t.RLock()
|
||||
// defer t.RUnlock()
|
||||
//
|
||||
// delete(t.items, base58.Encode(key))
|
||||
//
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Has(key []byte) bool {
|
||||
// panic("implement me")
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Size() int64 {
|
||||
// panic("implement me")
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) List() ([]core.BucketItem, error) {
|
||||
// t.Lock()
|
||||
// defer t.Unlock()
|
||||
//
|
||||
// res := make([]core.BucketItem, 0)
|
||||
//
|
||||
// for k, v := range t.items {
|
||||
// sk, err := base58.Decode(k)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// res = append(res, core.BucketItem{
|
||||
// Key: sk,
|
||||
// Val: v,
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// return res, nil
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Filter(core.FilterHandler) ([]core.BucketItem, error) {
|
||||
// panic("implement me")
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) Close() error {
|
||||
// panic("implement me")
|
||||
// }
|
||||
//
|
||||
// func (t *testBucket) PRead(key []byte, rng object.Range) ([]byte, error) {
|
||||
// panic("implement me")
|
||||
// }
|
||||
|
||||
func testObject(t *testing.T) *Object {
|
||||
var (
|
||||
uid refs.UUID
|
||||
cid CID
|
||||
)
|
||||
|
||||
t.Run("Prepare object", func(t *testing.T) {
|
||||
cnr, err := container.NewTestContainer()
|
||||
require.NoError(t, err)
|
||||
|
||||
cid, err = cnr.ID()
|
||||
require.NoError(t, err)
|
||||
|
||||
id, err := uuid.NewRandom()
|
||||
uid = refs.UUID(id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
obj := &Object{
|
||||
SystemHeader: object.SystemHeader{
|
||||
Version: 1,
|
||||
ID: uid,
|
||||
CID: cid,
|
||||
OwnerID: refs.OwnerID([refs.OwnerIDSize]byte{}), // TODO: avoid hardcode
|
||||
},
|
||||
Headers: []Header{
|
||||
{
|
||||
Value: &object.Header_UserHeader{
|
||||
UserHeader: &object.UserHeader{
|
||||
Key: "Profession",
|
||||
Value: "Developer",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Value: &object.Header_UserHeader{
|
||||
UserHeader: &object.UserHeader{
|
||||
Key: "Language",
|
||||
Value: "GO",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
func newLocalstore(t *testing.T) Localstore {
|
||||
ls, err := New(Params{
|
||||
BlobBucket: test.Bucket(),
|
||||
MetaBucket: test.Bucket(),
|
||||
Logger: zap.L(),
|
||||
Collector: newCollector(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
return ls
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
t.Run("New localstore", func(t *testing.T) {
|
||||
var err error
|
||||
|
||||
_, err = New(Params{})
|
||||
require.Error(t, err)
|
||||
|
||||
_, err = New(Params{
|
||||
BlobBucket: test.Bucket(),
|
||||
MetaBucket: test.Bucket(),
|
||||
Logger: zap.L(),
|
||||
Collector: newCollector(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLocalstore_Del(t *testing.T) {
|
||||
t.Run("Del method", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
obj *Object
|
||||
)
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
obj = testObject(t)
|
||||
obj.SetPayload([]byte("Hello, world"))
|
||||
|
||||
k := *obj.Address()
|
||||
|
||||
store, ok := ls.(*localstore)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, store)
|
||||
|
||||
metric, ok := store.col.(*fakeCollector)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, metric)
|
||||
|
||||
err = ls.Put(context.Background(), obj)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, obj.Payload)
|
||||
require.Contains(t, metric.items, obj.SystemHeader.CID)
|
||||
require.Equal(t, obj.SystemHeader.PayloadLength, metric.items[obj.SystemHeader.CID])
|
||||
|
||||
err = ls.Del(k)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, metric.items, obj.SystemHeader.CID)
|
||||
require.Equal(t, uint64(0), metric.items[obj.SystemHeader.CID])
|
||||
|
||||
_, err = ls.Get(k)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLocalstore_Get(t *testing.T) {
|
||||
t.Run("Get method (default)", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
obj *Object
|
||||
)
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
obj = testObject(t)
|
||||
|
||||
err = ls.Put(context.Background(), obj)
|
||||
require.NoError(t, err)
|
||||
|
||||
k := *obj.Address()
|
||||
|
||||
o, err := ls.Get(k)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, obj, o)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLocalstore_Put(t *testing.T) {
|
||||
t.Run("Put method", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
obj *Object
|
||||
)
|
||||
|
||||
ls = newLocalstore(t)
|
||||
store, ok := ls.(*localstore)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, store)
|
||||
|
||||
metric, ok := store.col.(*fakeCollector)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, metric)
|
||||
|
||||
obj = testObject(t)
|
||||
|
||||
err = ls.Put(context.Background(), obj)
|
||||
require.NoError(t, err)
|
||||
require.Contains(t, metric.items, obj.SystemHeader.CID)
|
||||
require.Equal(t, obj.SystemHeader.PayloadLength, metric.items[obj.SystemHeader.CID])
|
||||
|
||||
o, err := ls.Get(*obj.Address())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, obj, o)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLocalstore_List(t *testing.T) {
|
||||
t.Run("List method (no filters)", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(context.Background(), &objs[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
items, err := ListItems(ls, nil)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, objCount)
|
||||
|
||||
for i := range items {
|
||||
require.Contains(t, objs, *items[i].Object)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("List method ('bad' filter)", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(context.Background(), &objs[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
items, err := ListItems(ls, NewFilter(&FilterParams{
|
||||
FilterFunc: ContainerFilterFunc([]CID{}),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 0)
|
||||
})
|
||||
|
||||
t.Run("List method (filter by cid)", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(context.Background(), &objs[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
cidVals := []CID{objs[0].SystemHeader.CID}
|
||||
|
||||
items, err := ListItems(ls, NewFilter(&FilterParams{
|
||||
FilterFunc: ContainerFilterFunc(cidVals),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
|
||||
for i := range items {
|
||||
require.Contains(t, objs, *items[i].Object)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Filter stored earlier", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
epoch uint64 = 100
|
||||
list []ListItem
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
ctx := context.WithValue(context.Background(), StoreEpochValue, epoch)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(ctx, &objs[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
list, err = ListItems(ls, NewFilter(&FilterParams{
|
||||
FilterFunc: StoredEarlierThanFilterFunc(epoch - 1),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list)
|
||||
|
||||
list, err = ListItems(ls, NewFilter(&FilterParams{
|
||||
FilterFunc: StoredEarlierThanFilterFunc(epoch),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, list)
|
||||
|
||||
list, err = ListItems(ls, NewFilter(&FilterParams{
|
||||
FilterFunc: StoredEarlierThanFilterFunc(epoch + 1),
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, list, objCount)
|
||||
})
|
||||
|
||||
t.Run("Filter with complex filter", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(context.Background(), &objs[i])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
cidVals := []CID{objs[0].SystemHeader.CID}
|
||||
|
||||
mainF, err := AllPassIncludingFilter("TEST_FILTER", &FilterParams{
|
||||
Name: "CID_LIST",
|
||||
FilterFunc: ContainerFilterFunc(cidVals),
|
||||
})
|
||||
|
||||
items, err := ListItems(ls, mainF)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, items, 1)
|
||||
})
|
||||
|
||||
t.Run("Meta info", func(t *testing.T) {
|
||||
var (
|
||||
err error
|
||||
ls Localstore
|
||||
objCount = 10
|
||||
objs = make([]Object, objCount)
|
||||
epoch uint64 = 100
|
||||
)
|
||||
|
||||
for i := range objs {
|
||||
objs[i] = *testObject(t)
|
||||
}
|
||||
|
||||
ls = newLocalstore(t)
|
||||
|
||||
ctx := context.WithValue(context.Background(), StoreEpochValue, epoch)
|
||||
|
||||
for i := range objs {
|
||||
err = ls.Put(ctx, &objs[i])
|
||||
require.NoError(t, err)
|
||||
|
||||
meta, err := ls.Meta(*objs[i].Address())
|
||||
require.NoError(t, err)
|
||||
|
||||
noPayload := objs[i]
|
||||
noPayload.Payload = nil
|
||||
|
||||
require.Equal(t, *meta.Object, noPayload)
|
||||
require.Equal(t, meta.PayloadHash, hash.Sum(objs[i].Payload))
|
||||
require.Equal(t, meta.PayloadSize, uint64(len(objs[i].Payload)))
|
||||
require.Equal(t, epoch, meta.StoreEpoch)
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue