package meta import ( "context" "path/filepath" "testing" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard/mode" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" 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 TestInhumeECObject(t *testing.T) { t.Parallel() db := New( WithPath(filepath.Join(t.TempDir(), "metabase")), WithPermissions(0o600), WithEpochState(epochState{uint64(12)}), ) require.NoError(t, db.Open(context.Background(), mode.ReadWrite)) require.NoError(t, db.Init()) defer func() { require.NoError(t, db.Close()) }() cnr := cidtest.ID() ecChunk := oidtest.ID() ecChunk2 := oidtest.ID() ecParent := oidtest.ID() tombstoneID := oidtest.ID() chunkObj := testutil.GenerateObjectWithCID(cnr) chunkObj.SetContainerID(cnr) chunkObj.SetID(ecChunk) chunkObj.SetPayload([]byte{0, 1, 2, 3, 4}) chunkObj.SetPayloadSize(uint64(5)) chunkObj.SetECHeader(objectSDK.NewECHeader(objectSDK.ECParentInfo{ID: ecParent}, 0, 3, []byte{}, 0)) chunkObj2 := testutil.GenerateObjectWithCID(cnr) chunkObj2.SetContainerID(cnr) chunkObj2.SetID(ecChunk2) chunkObj2.SetPayload([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) chunkObj2.SetPayloadSize(uint64(10)) chunkObj2.SetECHeader(objectSDK.NewECHeader(objectSDK.ECParentInfo{ID: ecParent}, 1, 3, []byte{}, 0)) // put object with EC var prm PutPrm prm.SetObject(chunkObj) prm.SetStorageID([]byte("0/0")) _, err := db.Put(context.Background(), prm) require.NoError(t, err) prm.SetObject(chunkObj2) _, err = db.Put(context.Background(), prm) require.NoError(t, err) var ecChunkAddress oid.Address ecChunkAddress.SetContainer(cnr) ecChunkAddress.SetObject(ecChunk) var ecParentAddress oid.Address ecParentAddress.SetContainer(cnr) ecParentAddress.SetObject(ecParent) var chunkObjectAddress oid.Address chunkObjectAddress.SetContainer(cnr) chunkObjectAddress.SetObject(ecChunk) var getPrm GetPrm getPrm.SetAddress(ecChunkAddress) _, err = db.Get(context.Background(), getPrm) require.NoError(t, err) var ecInfoError *objectSDK.ECInfoError getPrm.SetAddress(ecParentAddress) _, err = db.Get(context.Background(), getPrm) require.ErrorAs(t, err, &ecInfoError) require.True(t, len(ecInfoError.ECInfo().Chunks) == 2 && ecInfoError.ECInfo().Chunks[0].Index == 0 && ecInfoError.ECInfo().Chunks[0].Total == 3) // inhume Chunk var inhumePrm InhumePrm var tombAddress oid.Address inhumePrm.SetAddresses(chunkObjectAddress) res, err := db.Inhume(context.Background(), inhumePrm) require.NoError(t, err) require.True(t, len(res.deletionDetails) == 1) require.True(t, res.deletionDetails[0].Size == 5) // inhume EC parent (like Delete does) tombAddress.SetContainer(cnr) tombAddress.SetObject(tombstoneID) inhumePrm.SetAddresses(ecParentAddress) inhumePrm.SetTombstoneAddress(tombAddress) res, err = db.Inhume(context.Background(), inhumePrm) require.NoError(t, err) // Previously deleted chunk shouldn't be in the details, because it is marked as garbage require.True(t, len(res.deletionDetails) == 1) require.True(t, res.deletionDetails[0].Size == 10) getPrm.SetAddress(ecParentAddress) _, err = db.Get(context.Background(), getPrm) require.ErrorAs(t, err, new(*apistatus.ObjectAlreadyRemoved)) getPrm.SetAddress(ecChunkAddress) _, err = db.Get(context.Background(), getPrm) require.ErrorAs(t, err, new(*apistatus.ObjectAlreadyRemoved)) }