[#1445] engine/test: Add tests for GC
All checks were successful
Vulncheck / Vulncheck (pull_request) Successful in 2m38s
Tests and linters / gopls check (pull_request) Successful in 3m55s
Pre-commit hooks / Pre-commit (pull_request) Successful in 4m9s
Tests and linters / Run gofumpt (pull_request) Successful in 6m32s
DCO action / DCO (pull_request) Successful in 6m58s
Tests and linters / Tests with -race (pull_request) Successful in 7m3s
Build / Build Components (pull_request) Successful in 7m20s
Tests and linters / Staticcheck (pull_request) Successful in 8m35s
Tests and linters / Lint (pull_request) Successful in 9m23s
Tests and linters / Tests (pull_request) Successful in 8m20s
All checks were successful
Vulncheck / Vulncheck (pull_request) Successful in 2m38s
Tests and linters / gopls check (pull_request) Successful in 3m55s
Pre-commit hooks / Pre-commit (pull_request) Successful in 4m9s
Tests and linters / Run gofumpt (pull_request) Successful in 6m32s
DCO action / DCO (pull_request) Successful in 6m58s
Tests and linters / Tests with -race (pull_request) Successful in 7m3s
Build / Build Components (pull_request) Successful in 7m20s
Tests and linters / Staticcheck (pull_request) Successful in 8m35s
Tests and linters / Lint (pull_request) Successful in 9m23s
Tests and linters / Tests (pull_request) Successful in 8m20s
Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
parent
6bc49eb741
commit
e2d26cd213
1 changed files with 181 additions and 0 deletions
181
pkg/local_object_storage/engine/gc_test.go
Normal file
181
pkg/local_object_storage/engine/gc_test.go
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
objectCore "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
||||||
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/shard"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util"
|
||||||
|
objectV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client"
|
||||||
|
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||||
|
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"
|
||||||
|
"github.com/panjf2000/ants/v2"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func testPopulateWithObjects(t testing.TB, engine *StorageEngine, cnt cid.ID, objectCount int) (objects []*objectSDK.Object) {
|
||||||
|
require.Positive(t, objectCount)
|
||||||
|
|
||||||
|
var putPrm PutPrm
|
||||||
|
for range objectCount {
|
||||||
|
putPrm.Object = testutil.GenerateObjectWithCID(cnt)
|
||||||
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
||||||
|
objects = append(objects, putPrm.Object)
|
||||||
|
}
|
||||||
|
return objects
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInhumeObjects(t testing.TB, engine *StorageEngine, objects []*objectSDK.Object, expEpoch uint64) (tombstone *objectSDK.Object) {
|
||||||
|
require.NotEmpty(t, objects)
|
||||||
|
cnt := objectCore.AddressOf(objects[0]).Container()
|
||||||
|
|
||||||
|
tombstone = testutil.GenerateObjectWithCID(cnt)
|
||||||
|
tombstone.SetType(objectSDK.TypeTombstone)
|
||||||
|
testutil.AddAttribute(tombstone, objectV2.SysAttributeExpEpoch, strconv.FormatUint(expEpoch, 10))
|
||||||
|
|
||||||
|
var putPrm PutPrm
|
||||||
|
putPrm.Object = tombstone
|
||||||
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
||||||
|
|
||||||
|
var addrs []oid.Address
|
||||||
|
for _, object := range objects {
|
||||||
|
addrs = append(addrs, objectCore.AddressOf(object))
|
||||||
|
}
|
||||||
|
tombstoneAddr := objectCore.AddressOf(tombstone)
|
||||||
|
|
||||||
|
pivot := len(objects) / 2
|
||||||
|
|
||||||
|
var inhumePrm InhumePrm
|
||||||
|
inhumePrm.WithTarget(tombstoneAddr, expEpoch, addrs[:pivot]...)
|
||||||
|
_, err := engine.Inhume(context.Background(), inhumePrm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
inhumePrm.WithTarget(tombstoneAddr, meta.NoExpirationEpoch, addrs[pivot:]...)
|
||||||
|
_, err = engine.Inhume(context.Background(), inhumePrm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLockObjects(t testing.TB, engine *StorageEngine, objects []*objectSDK.Object, expEpoch uint64) (lockObject *objectSDK.Object) {
|
||||||
|
require.NotEmpty(t, objects)
|
||||||
|
|
||||||
|
require.NotEmpty(t, objects)
|
||||||
|
cnt := objectCore.AddressOf(objects[0]).Container()
|
||||||
|
|
||||||
|
lockObject = testutil.GenerateObjectWithCID(cnt)
|
||||||
|
lockObject.SetType(objectSDK.TypeLock)
|
||||||
|
testutil.AddAttribute(lockObject, objectV2.SysAttributeExpEpoch, strconv.FormatUint(expEpoch, 10))
|
||||||
|
|
||||||
|
var putPrm PutPrm
|
||||||
|
putPrm.Object = lockObject
|
||||||
|
require.NoError(t, engine.Put(context.Background(), putPrm))
|
||||||
|
|
||||||
|
var lockedIDs []oid.ID
|
||||||
|
for _, object := range objects {
|
||||||
|
lockedIDs = append(lockedIDs, objectCore.AddressOf(object).Object())
|
||||||
|
}
|
||||||
|
lockObjectID := objectCore.AddressOf(lockObject).Object()
|
||||||
|
|
||||||
|
pivot := len(objects) / 2
|
||||||
|
require.NoError(t, engine.Lock(context.Background(), cnt, lockObjectID, lockedIDs[:pivot], expEpoch))
|
||||||
|
require.NoError(t, engine.Lock(context.Background(), cnt, lockObjectID, lockedIDs[pivot:], meta.NoExpirationEpoch))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCHandleExpiredTombstones(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const (
|
||||||
|
numShards = 2
|
||||||
|
objectCount = 10 * numShards
|
||||||
|
expEpoch = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
container := cidtest.ID()
|
||||||
|
|
||||||
|
engine := testNewEngine(t).
|
||||||
|
setShardsNumAdditionalOpts(t, numShards, func(_ int) []shard.Option {
|
||||||
|
return []shard.Option{
|
||||||
|
shard.WithGCWorkerPoolInitializer(func(sz int) util.WorkerPool {
|
||||||
|
pool, err := ants.NewPool(sz)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return pool
|
||||||
|
}),
|
||||||
|
shard.WithTombstoneSource(tss{expEpoch}),
|
||||||
|
}
|
||||||
|
}).prepare(t).engine
|
||||||
|
defer func() { require.NoError(t, engine.Close(context.Background())) }()
|
||||||
|
|
||||||
|
objects := testPopulateWithObjects(t, engine, container, objectCount)
|
||||||
|
tombstone := testInhumeObjects(t, engine, objects, expEpoch)
|
||||||
|
|
||||||
|
engine.HandleNewEpoch(context.Background(), expEpoch+1)
|
||||||
|
|
||||||
|
var headPrm HeadPrm
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
for _, object := range objects {
|
||||||
|
headPrm.WithAddress(objectCore.AddressOf(object))
|
||||||
|
_, err := engine.Head(context.Background(), headPrm)
|
||||||
|
if !client.IsErrObjectNotFound(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headPrm.WithAddress(objectCore.AddressOf(tombstone))
|
||||||
|
_, err := engine.Head(context.Background(), headPrm)
|
||||||
|
return client.IsErrObjectNotFound(err)
|
||||||
|
}, 10*time.Second, 1*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCHandleExpiredLockObjects(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const (
|
||||||
|
numShards = 2
|
||||||
|
objectCount = 10 * numShards
|
||||||
|
expEpoch = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
container := cidtest.ID()
|
||||||
|
|
||||||
|
engine := testNewEngine(t).
|
||||||
|
setShardsNumAdditionalOpts(t, numShards, func(_ int) []shard.Option {
|
||||||
|
return []shard.Option{
|
||||||
|
shard.WithGCWorkerPoolInitializer(func(sz int) util.WorkerPool {
|
||||||
|
pool, err := ants.NewPool(sz)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return pool
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}).prepare(t).engine
|
||||||
|
defer func() { require.NoError(t, engine.Close(context.Background())) }()
|
||||||
|
|
||||||
|
objects := testPopulateWithObjects(t, engine, container, objectCount)
|
||||||
|
lockObject := testLockObjects(t, engine, objects, expEpoch)
|
||||||
|
|
||||||
|
engine.HandleNewEpoch(context.Background(), expEpoch+1)
|
||||||
|
|
||||||
|
var headPrm HeadPrm
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
for _, object := range objects {
|
||||||
|
locked, err := engine.IsLocked(context.Background(), objectCore.AddressOf(object))
|
||||||
|
if err != nil || locked {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
headPrm.WithAddress(objectCore.AddressOf(lockObject))
|
||||||
|
_, err := engine.Head(context.Background(), headPrm)
|
||||||
|
return client.IsErrObjectNotFound(err)
|
||||||
|
}, 10*time.Second, 1*time.Second)
|
||||||
|
}
|
Loading…
Reference in a new issue