package blobstor import ( "context" "encoding/binary" "errors" "os" "testing" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/common" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/memstore" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/blobstor/teststore" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" "github.com/stretchr/testify/require" ) func TestIterateObjects(t *testing.T) { p := t.Name() const smalSz = 50 // create BlobStor instance blobStor := New( WithStorages(defaultStorages(p, smalSz)), WithCompressObjects(true), ) defer os.RemoveAll(p) // open Blobstor require.NoError(t, blobStor.Open(context.Background(), mode.ReadWrite)) // initialize Blobstor require.NoError(t, blobStor.Init(context.Background())) defer blobStor.Close(context.Background()) const objNum = 5 type addrData struct { big bool addr oid.Address data []byte } mObjs := make(map[string]addrData) for i := range uint64(objNum) { sz := smalSz big := i < objNum/2 if big { sz++ } data := make([]byte, sz) binary.BigEndian.PutUint64(data, i) addr := oidtest.Address() mObjs[string(data)] = addrData{ big: big, addr: addr, data: data, } } for _, v := range mObjs { _, err := blobStor.Put(context.Background(), common.PutPrm{Address: v.addr, RawData: v.data}) require.NoError(t, err) } err := IterateBinaryObjects(context.Background(), blobStor, func(addr oid.Address, data []byte, descriptor []byte) error { v, ok := mObjs[string(data)] require.True(t, ok) require.Equal(t, v.data, data) if v.big { require.True(t, descriptor != nil && len(descriptor) == 0) } else { require.NotEmpty(t, descriptor) } delete(mObjs, string(data)) return nil }) require.NoError(t, err) require.Empty(t, mObjs) } func TestIterate_IgnoreErrors(t *testing.T) { ctx := context.Background() myErr := errors.New("unique error") nopIter := func(common.IteratePrm) (common.IterateRes, error) { return common.IterateRes{}, nil } panicIter := func(common.IteratePrm) (common.IterateRes, error) { panic("unreachable") } errIter := func(common.IteratePrm) (common.IterateRes, error) { return common.IterateRes{}, myErr } var s1iter, s2iter func(common.IteratePrm) (common.IterateRes, error) st1 := teststore.New( teststore.WithSubstorage(memstore.New()), teststore.WithIterate(func(prm common.IteratePrm) (common.IterateRes, error) { return s1iter(prm) })) st2 := teststore.New( teststore.WithSubstorage(memstore.New()), teststore.WithIterate(func(prm common.IteratePrm) (common.IterateRes, error) { return s2iter(prm) })) bsOpts := []Option{WithStorages([]SubStorage{ {Storage: st1}, {Storage: st2}, })} bs := New(bsOpts...) require.NoError(t, bs.Open(ctx, mode.ReadWrite)) require.NoError(t, bs.Init(ctx)) nopHandler := func(e common.IterationElement) error { return nil } t.Run("no errors", func(t *testing.T) { s1iter = nopIter s2iter = nopIter _, err := bs.Iterate(ctx, common.IteratePrm{Handler: nopHandler}) require.NoError(t, err) }) t.Run("error in the first sub storage, the second one is not iterated over", func(t *testing.T) { s1iter = errIter s2iter = panicIter _, err := bs.Iterate(ctx, common.IteratePrm{Handler: nopHandler}) require.ErrorIs(t, err, myErr) }) t.Run("ignore errors, storage 1", func(t *testing.T) { s1iter = errIter s2iter = nopIter _, err := bs.Iterate(ctx, common.IteratePrm{IgnoreErrors: true, Handler: nopHandler}) require.NoError(t, err) }) t.Run("ignore errors, storage 2", func(t *testing.T) { s1iter = nopIter s2iter = errIter _, err := bs.Iterate(ctx, common.IteratePrm{IgnoreErrors: true, Handler: nopHandler}) require.NoError(t, err) }) }