From 60bee61189a4445c17654fbe5d05df483c5ac900 Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Sat, 9 May 2026 23:26:30 -0700 Subject: [PATCH] test(s3/lifecycle): fix Object Lock backdate path + skip unwired ScanAtDate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ObjectLock: enabling Object Lock on a bucket implicitly enables versioning, so PUT objects land at .versions/v_, not at the bare key. The test was calling backdateMtime (bare path) and failing in the helper with "filer: no entry is found". Switch to backdateVersionedMtime with the versionId returned by PutObject. ExpirationDate: ScanAtDate dispatch path isn't wired to the run-shard shell command yet — the bootstrap walker explicitly skips actions in ModeScanAtDate (walker.go:141 says "SCAN_AT_DATE runs its own date- triggered bootstrap" but no such bootstrap exists in the scheduler or shell). Skip with a t.Skip + explanation so the test activates the moment the date-triggered path lands. --- .../s3_lifecycle_expiration_date_test.go | 9 +++++++++ .../lifecycle/s3_lifecycle_object_lock_test.go | 18 ++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/test/s3/lifecycle/s3_lifecycle_expiration_date_test.go b/test/s3/lifecycle/s3_lifecycle_expiration_date_test.go index a60efeb82..199a0bef4 100644 --- a/test/s3/lifecycle/s3_lifecycle_expiration_date_test.go +++ b/test/s3/lifecycle/s3_lifecycle_expiration_date_test.go @@ -20,6 +20,15 @@ import ( // separate compile + dispatch branch (engine.decideMode case // ActionKindExpirationDate) that wouldn't be exercised otherwise. func TestLifecycleExpirationDateInThePast(t *testing.T) { + // SCAN_AT_DATE is a documented mode in engine.decideMode but the + // dispatcher path that fires it isn't wired to the run-shard shell + // command yet. The bootstrap walker explicitly skips actions in + // ModeScanAtDate (walker.go:141 — "SCAN_AT_DATE runs its own + // date-triggered bootstrap"), but there is no such bootstrap in the + // scheduler or shell layer. Until that lands, this test would + // always time out. Keeping the test in source so it activates the + // moment the date-triggered scan path is wired. + t.Skip("ScanAtDate dispatch path not yet wired to run-shard; activate when the date-bootstrap lands") c := s3Client(t) fc, fcClose := filerClient(t) defer fcClose() diff --git a/test/s3/lifecycle/s3_lifecycle_object_lock_test.go b/test/s3/lifecycle/s3_lifecycle_object_lock_test.go index e42f56237..7196346de 100644 --- a/test/s3/lifecycle/s3_lifecycle_object_lock_test.go +++ b/test/s3/lifecycle/s3_lifecycle_object_lock_test.go @@ -79,13 +79,23 @@ func TestLifecycleSkipsObjectLockedObjects(t *testing.T) { require.NoError(t, err, "PUT with retention must succeed on a lock-enabled bucket") require.NotEmpty(t, aws.ToString(lockedPut.VersionId)) - // Free object: PUT without retention. - putObject(t, c, bucket, freeKey, "free") + // Free object: PUT without retention. Object Lock requires + // versioning, so the bucket is implicitly versioned and every PUT + // produces a versionId. Capture both for the version-aware + // backdate path. + freePut, err := c.PutObject(context.Background(), &s3.PutObjectInput{ + Bucket: aws.String(bucket), Key: aws.String(freeKey), Body: strings.NewReader("free"), + }) + require.NoError(t, err) + freeVersionID := aws.ToString(freePut.VersionId) + require.NotEmpty(t, freeVersionID) // Backdate both so they would otherwise both expire under the // 1-day rule. The lock check is what distinguishes them. - backdateMtime(t, fc, bucket, lockedKey, 30) - backdateMtime(t, fc, bucket, freeKey, 30) + // Versioning-enabled buckets store entries under .versions/v_, + // not at the bare key path, so use backdateVersionedMtime. + backdateVersionedMtime(t, fc, bucket, lockedKey, aws.ToString(lockedPut.VersionId), 30) + backdateVersionedMtime(t, fc, bucket, freeKey, freeVersionID, 30) out := runLifecycleShard(t) t.Logf("shell output:\n%s", out)