mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-20 22:27:04 +00:00
test(s3/lifecycle): integration coverage for config update between sweeps
An operator changes the lifecycle rule between two shell-driven
sweeps. The second sweep must respect the NEW rule, not a cached
copy of the old one. Each runLifecycleShard invocation spawns a
fresh weed shell subprocess, so cached engine state from a previous
sweep doesn't persist — but a regression that caches rules across
PutBucketLifecycleConfiguration calls within the S3 server itself
would still surface here.
Sweep 1: rule prefix="first/", PUT + backdate firstKey, run worker
→ firstKey expires.
Update rule to prefix="second/", PUT + backdate secondKey AND a
new key under the OLD prefix ("first/post-update.txt"). Sweep 2
must expire only the second-prefix object; the post-update old-
prefix one must survive — config replacement, not merge.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
// Lifecycle config update across sweeps.
|
||||
package lifecycle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestLifecycleConfigUpdateBetweenSweeps: an operator changes the
|
||||
// lifecycle rule between two shell-driven sweeps. The second sweep
|
||||
// must respect the NEW rule, not a cached version of the old one.
|
||||
//
|
||||
// Each `runLifecycleShard` invocation spawns a fresh `weed shell`
|
||||
// subprocess, so cached engine state from a previous sweep doesn't
|
||||
// persist across runs. This test pins that the freshly-loaded config
|
||||
// actually changes routing — under the new prefix only matching
|
||||
// objects expire, even if there are still backdated objects sitting
|
||||
// under the old prefix.
|
||||
func TestLifecycleConfigUpdateBetweenSweeps(t *testing.T) {
|
||||
c := s3Client(t)
|
||||
fc, fcClose := filerClient(t)
|
||||
defer fcClose()
|
||||
|
||||
bucket := uniqueBucket("config-update")
|
||||
mustCreateBucket(t, c, bucket)
|
||||
|
||||
// Sweep 1: rule expires anything under "first/".
|
||||
putExpirationLifecycle(t, c, bucket, "first/", 1)
|
||||
|
||||
const firstKey = "first/initial.txt"
|
||||
putObject(t, c, bucket, firstKey, "first")
|
||||
backdateMtime(t, fc, bucket, firstKey, 30)
|
||||
|
||||
out := runLifecycleShard(t)
|
||||
t.Logf("sweep 1 output:\n%s", out)
|
||||
|
||||
require.Eventuallyf(t, func() bool {
|
||||
_, err := c.HeadObject(context.Background(), &s3.HeadObjectInput{
|
||||
Bucket: aws.String(bucket), Key: aws.String(firstKey),
|
||||
})
|
||||
return isS3NotFound(err)
|
||||
}, 30*time.Second, 500*time.Millisecond, "sweep 1 must expire %s", firstKey)
|
||||
|
||||
// Update the rule to a different prefix. The old "first/" prefix
|
||||
// is no longer covered by any rule; objects under it must NOT be
|
||||
// expired by sweep 2 even when backdated.
|
||||
putExpirationLifecycle(t, c, bucket, "second/", 1)
|
||||
|
||||
const secondKey = "second/new.txt"
|
||||
const oldPrefixKey = "first/post-update.txt"
|
||||
putObject(t, c, bucket, secondKey, "second")
|
||||
putObject(t, c, bucket, oldPrefixKey, "stale rule")
|
||||
backdateMtime(t, fc, bucket, secondKey, 30)
|
||||
backdateMtime(t, fc, bucket, oldPrefixKey, 30)
|
||||
|
||||
out = runLifecycleShard(t)
|
||||
t.Logf("sweep 2 output:\n%s", out)
|
||||
|
||||
// Sweep 2 expires the new-prefix object.
|
||||
require.Eventuallyf(t, func() bool {
|
||||
_, err := c.HeadObject(context.Background(), &s3.HeadObjectInput{
|
||||
Bucket: aws.String(bucket), Key: aws.String(secondKey),
|
||||
})
|
||||
return isS3NotFound(err)
|
||||
}, 30*time.Second, 500*time.Millisecond, "sweep 2 must expire %s under the new rule", secondKey)
|
||||
|
||||
// Sweep 2 must NOT expire the old-prefix object — the rule was
|
||||
// replaced, not merged. A regression that caches old rules across
|
||||
// PutBucketLifecycleConfiguration calls would fail here.
|
||||
_, err := c.HeadObject(context.Background(), &s3.HeadObjectInput{
|
||||
Bucket: aws.String(bucket), Key: aws.String(oldPrefixKey),
|
||||
})
|
||||
require.NoError(t, err, "old-prefix object must survive after rule update — config replacement, not merge")
|
||||
}
|
||||
Reference in New Issue
Block a user