package shard import ( "bytes" "context" "errors" "testing" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" "github.com/stretchr/testify/require" ) func TestShard_Get(t *testing.T) { t.Parallel() t.Run("without write cache", func(t *testing.T) { t.Parallel() testShardGet(t, false) }) t.Run("with write cache", func(t *testing.T) { t.Parallel() testShardGet(t, true) }) } func testShardGet(t *testing.T, hasWriteCache bool) { sh := newShard(t, hasWriteCache) defer func() { require.NoError(t, sh.Close()) }() var putPrm PutPrm var getPrm GetPrm t.Run("small object", func(t *testing.T) { obj := testutil.GenerateObject() testutil.AddAttribute(obj, "foo", "bar") testutil.AddPayload(obj, 1<<5) putPrm.SetObject(obj) _, err := sh.Put(context.Background(), putPrm) require.NoError(t, err) getPrm.SetAddress(object.AddressOf(obj)) res, err := testGet(t, sh, getPrm, hasWriteCache) require.NoError(t, err) require.Equal(t, obj, res.Object()) }) t.Run("big object", func(t *testing.T) { obj := testutil.GenerateObject() testutil.AddAttribute(obj, "foo", "bar") obj.SetID(oidtest.ID()) testutil.AddPayload(obj, 1<<20) // big obj putPrm.SetObject(obj) _, err := sh.Put(context.Background(), putPrm) require.NoError(t, err) getPrm.SetAddress(object.AddressOf(obj)) res, err := testGet(t, sh, getPrm, hasWriteCache) require.NoError(t, err) require.Equal(t, obj, res.Object()) }) t.Run("parent object", func(t *testing.T) { obj := testutil.GenerateObject() testutil.AddAttribute(obj, "foo", "bar") cnr := cidtest.ID() splitID := objectSDK.NewSplitID() parent := testutil.GenerateObjectWithCID(cnr) testutil.AddAttribute(parent, "parent", "attribute") child := testutil.GenerateObjectWithCID(cnr) child.SetParent(parent) idParent, _ := parent.ID() child.SetParentID(idParent) child.SetSplitID(splitID) testutil.AddPayload(child, 1<<5) putPrm.SetObject(child) _, err := sh.Put(context.Background(), putPrm) require.NoError(t, err) getPrm.SetAddress(object.AddressOf(child)) res, err := testGet(t, sh, getPrm, hasWriteCache) require.NoError(t, err) require.True(t, binaryEqual(child, res.Object())) getPrm.SetAddress(object.AddressOf(parent)) _, err = testGet(t, sh, getPrm, hasWriteCache) var si *objectSDK.SplitInfoError require.True(t, errors.As(err, &si)) _, ok := si.SplitInfo().Link() require.False(t, ok) id1, _ := child.ID() id2, _ := si.SplitInfo().LastPart() require.Equal(t, id1, id2) require.Equal(t, splitID, si.SplitInfo().SplitID()) }) } func testGet(t *testing.T, sh *Shard, getPrm GetPrm, hasWriteCache bool) (GetRes, error) { res, err := sh.Get(context.Background(), getPrm) if hasWriteCache { require.Eventually(t, func() bool { if client.IsErrObjectNotFound(err) { res, err = sh.Get(context.Background(), getPrm) } return !client.IsErrObjectNotFound(err) }, time.Second, time.Millisecond*100) } return res, err } // binary equal is used when object contains empty lists in the structure and // requre.Equal fails on comparing and []{} lists. func binaryEqual(a, b *objectSDK.Object) bool { binaryA, err := a.Marshal() if err != nil { return false } binaryB, err := b.Marshal() if err != nil { return false } return bytes.Equal(binaryA, binaryB) }