2020-07-10 14:17:51 +00:00
|
|
|
package metrics
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/binary"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/object"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
2020-07-24 13:54:03 +00:00
|
|
|
meta2 "github.com/nspcc-dev/neofs-node/pkg/local_object_storage/meta"
|
2020-07-10 14:17:51 +00:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
fakeCounter int
|
|
|
|
fakeIterator string
|
|
|
|
fakeMetaStore []*object.Object
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2020-07-24 13:54:03 +00:00
|
|
|
_ ObjectCounter = (*fakeCounter)(nil)
|
|
|
|
_ meta2.Iterator = (*fakeIterator)(nil)
|
2020-07-10 14:17:51 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func (f fakeCounter) ObjectsCount() (uint64, error) {
|
|
|
|
return uint64(f), nil
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (f fakeIterator) Iterate(_ meta2.IterateFunc) error {
|
2020-07-10 14:17:51 +00:00
|
|
|
if f == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return errors.New(string(f))
|
|
|
|
}
|
|
|
|
|
2020-07-24 13:54:03 +00:00
|
|
|
func (f fakeMetaStore) Iterate(cb meta2.IterateFunc) error {
|
2020-07-10 14:17:51 +00:00
|
|
|
if cb == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range f {
|
|
|
|
if err := cb(f[i]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCollector(t *testing.T) {
|
|
|
|
buck := &fakeBucket{items: make(map[uint64]int)}
|
|
|
|
|
|
|
|
t.Run("check errors", func(t *testing.T) {
|
|
|
|
t.Run("empty logger", func(t *testing.T) {
|
|
|
|
svc, err := New(Params{MetricsStore: buck})
|
|
|
|
require.Nil(t, svc)
|
|
|
|
require.EqualError(t, err, errEmptyLogger.Error())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("empty metrics store", func(t *testing.T) {
|
|
|
|
svc, err := New(Params{Logger: zap.L()})
|
|
|
|
require.Nil(t, svc)
|
|
|
|
require.EqualError(t, err, errEmptyMetricsStore.Error())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
svc, err := New(Params{
|
|
|
|
Logger: zap.L(),
|
|
|
|
MetricsStore: buck,
|
|
|
|
Options: []string{
|
|
|
|
"/Location:Europe/Country:Russia/City:Moscow",
|
|
|
|
"/Some:Another/Key:Value",
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, svc)
|
|
|
|
|
|
|
|
coll, ok := svc.(*collector)
|
|
|
|
require.True(t, ok)
|
|
|
|
require.NotNil(t, coll)
|
|
|
|
|
|
|
|
t.Run("check start", func(t *testing.T) {
|
|
|
|
coll.interval = time.Second
|
|
|
|
|
|
|
|
t.Run("stop by context", func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
counter.Store(-1)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
svc.Start(ctx)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
require.Equal(t, float64(-1), counter.Load())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("should fail on empty counter", func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
counter.Store(0)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
svc.Start(ctx)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
require.Equal(t, float64(0), counter.Load())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("should success on fakeCounter", func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
coll.SetCounter(fakeCounter(8))
|
|
|
|
counter.Store(0)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
svc.Start(ctx)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
cancel()
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
require.Equal(t, float64(8), counter.Load())
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("iterator", func(t *testing.T) {
|
|
|
|
{
|
|
|
|
coll.SetIterator(nil)
|
|
|
|
require.Nil(t, coll.metas.iter)
|
|
|
|
require.EqualError(t, coll.metas.Iterate(nil), errEmptyMetaStore.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
iter := fakeIterator("")
|
|
|
|
coll.SetIterator(iter)
|
|
|
|
require.Equal(t, iter, coll.metas.iter)
|
|
|
|
require.NoError(t, coll.metas.Iterate(nil))
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
iter := fakeIterator("test")
|
|
|
|
coll.SetIterator(iter)
|
|
|
|
require.Equal(t, iter, coll.metas.iter)
|
|
|
|
require.EqualError(t, coll.metas.Iterate(nil), string(iter))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("add-rem space", func(t *testing.T) {
|
|
|
|
cid := refs.CID{1, 2, 3, 4, 5}
|
|
|
|
buf := make([]byte, 8)
|
|
|
|
key := keyFromBytes(cid.Bytes())
|
|
|
|
|
|
|
|
zero := make([]byte, 8)
|
|
|
|
size := uint64(100)
|
|
|
|
|
|
|
|
binary.BigEndian.PutUint64(buf, size)
|
|
|
|
|
|
|
|
{
|
|
|
|
coll.UpdateContainer(cid, size, AddSpace)
|
|
|
|
require.Len(t, coll.sizes.items, 1)
|
|
|
|
require.Len(t, buck.items, 1)
|
|
|
|
require.Contains(t, buck.items, key)
|
|
|
|
require.Contains(t, buck.kv, fakeKV{key: cid.Bytes(), val: buf})
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
coll.UpdateContainer(cid, size, RemSpace)
|
|
|
|
require.Len(t, coll.sizes.items, 1)
|
|
|
|
require.Len(t, buck.items, 1)
|
|
|
|
require.Contains(t, buck.items, key)
|
|
|
|
require.Contains(t, buck.kv, fakeKV{key: cid.Bytes(), val: zero})
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
coll.UpdateContainer(cid, size, RemSpace)
|
|
|
|
require.Len(t, coll.sizes.items, 1)
|
|
|
|
require.Len(t, buck.items, 1)
|
|
|
|
require.Contains(t, buck.kv, fakeKV{key: cid.Bytes(), val: zero})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("add-rem multi thread", func(t *testing.T) {
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
wg.Add(10)
|
|
|
|
|
|
|
|
size := uint64(100)
|
|
|
|
zero := make([]byte, 8)
|
|
|
|
|
|
|
|
// reset
|
|
|
|
coll.UpdateSpaceUsage()
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
cid := refs.CID{1, 2, 3, 4, byte(i)}
|
|
|
|
coll.UpdateContainer(cid, size, AddSpace)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
coll.UpdateContainer(cid, size, RemSpace)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
require.Len(t, coll.sizes.items, 10)
|
|
|
|
require.Len(t, buck.items, 10)
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
cid := refs.CID{1, 2, 3, 4, byte(i)}
|
|
|
|
require.Contains(t, buck.kv, fakeKV{key: cid.Bytes(), val: zero})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("reset buckets", func(t *testing.T) {
|
|
|
|
coll.UpdateSpaceUsage()
|
|
|
|
require.Len(t, coll.sizes.items, 0)
|
|
|
|
require.Len(t, buck.items, 0)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("reset from metaStore", func(t *testing.T) {
|
|
|
|
cid := refs.CID{1, 2, 3, 4, 5}
|
|
|
|
buf := make([]byte, 8)
|
|
|
|
key := keyFromBytes(cid.Bytes())
|
|
|
|
size := uint64(100)
|
|
|
|
binary.BigEndian.PutUint64(buf, size)
|
|
|
|
|
|
|
|
iter := fakeMetaStore{
|
|
|
|
{
|
|
|
|
SystemHeader: object.SystemHeader{
|
|
|
|
PayloadLength: size,
|
|
|
|
CID: cid,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
Headers: []object.Header{
|
|
|
|
{
|
|
|
|
Value: &object.Header_Tombstone{Tombstone: &object.Tombstone{}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
coll.SetIterator(iter)
|
|
|
|
|
|
|
|
coll.UpdateSpaceUsage()
|
|
|
|
require.Len(t, coll.sizes.items, 1)
|
|
|
|
require.Len(t, buck.items, 1)
|
|
|
|
|
|
|
|
require.Contains(t, buck.items, key)
|
|
|
|
require.Contains(t, buck.kv, fakeKV{key: cid.Bytes(), val: buf})
|
|
|
|
})
|
|
|
|
}
|