package metrics import ( "sync" "testing" "github.com/nspcc-dev/neofs-api-go/refs" "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/bucket" "github.com/spaolacci/murmur3" "github.com/stretchr/testify/require" "go.uber.org/zap" ) type ( fakeKV struct { key []byte val []byte } fakeBucket struct { sync.RWMutex kv []fakeKV items map[uint64]int } ) func keyFromBytes(b []byte) uint64 { return murmur3.Sum64(b) } func (f *fakeBucket) Set(key, value []byte) error { f.Lock() defer f.Unlock() var ( id int ok bool uid = keyFromBytes(key) ) if id, ok = f.items[uid]; !ok || id >= len(f.kv) { id = len(f.kv) f.items[uid] = id f.kv = append(f.kv, fakeKV{ key: key, val: value, }) return nil } f.kv[id] = fakeKV{ key: key, val: value, } return nil } func (f *fakeBucket) Del(key []byte) error { f.Lock() defer f.Unlock() delete(f.items, keyFromBytes(key)) return nil } func (f *fakeBucket) List() ([][]byte, error) { f.RLock() defer f.RUnlock() items := make([][]byte, 0, len(f.items)) for _, id := range f.items { // ignore unknown KV if id >= len(f.kv) { continue } items = append(items, f.kv[id].key) } return items, nil } func (f *fakeBucket) Iterate(handler bucket.FilterHandler) error { f.Lock() defer f.Unlock() for _, id := range f.items { // ignore unknown KV if id >= len(f.kv) { continue } kv := f.kv[id] if !handler(kv.key, kv.val) { break } } return nil } func (f *fakeBucket) Get(_ []byte) ([]byte, error) { panic("implement me") } func (f *fakeBucket) Has(_ []byte) bool { panic("implement me") } func (f *fakeBucket) Size() int64 { panic("implement me") } func (f *fakeBucket) Close() error { panic("implement me") } func TestSyncStore(t *testing.T) { buck := &fakeBucket{items: make(map[uint64]int)} sizes := newSyncStore(zap.L(), buck) for i := 0; i < 10; i++ { cid := refs.CID{0, 0, 0, byte(i)} require.NoError(t, buck.Set(cid.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, byte(i)})) } t.Run("load", func(t *testing.T) { sizes.Load() require.Len(t, sizes.items, len(buck.items)) }) t.Run("reset", func(t *testing.T) { sizes.Reset(nil) require.Len(t, sizes.items, 0) }) t.Run("update", func(t *testing.T) { cid := refs.CID{1, 2, 3, 4, 5} { // add space sizes.Update(cid, 8, AddSpace) val, ok := sizes.items[cid] require.True(t, ok) require.Equal(t, uint64(8), val) } { // rem space sizes.Update(cid, 8, RemSpace) val, ok := sizes.items[cid] require.True(t, ok) require.Zero(t, val) } { // rem space (zero - val) sizes.Update(cid, 8, RemSpace) val, ok := sizes.items[cid] require.True(t, ok) require.Zero(t, val) } }) }