Skip to content

Commit dc3ec65

Browse files
test(sessions): a lease that cannot be taken keeps the session, and does not stop a resume
Prune fails closed when it cannot take a session's lease at all, so a process whose own hold fails the same way can carry on: prune cannot remove the session either. Refusing there instead would stop resume and fork wherever locking does not work, for people who never prune.
1 parent 7fa2017 commit dc3ec65

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

‎internal/sessions/prune_test.go‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,3 +446,45 @@ func TestResumeIsRefusedWhilePruneHoldsTheSession(t *testing.T) {
446446
t.Errorf("old kept for %q, want %q", reason, PruneKeptOpen)
447447
}
448448
}
449+
450+
// A lease that cannot be taken at all is not a free one: prune keeps the
451+
// session. That is why a process whose own hold fails the same way carries on
452+
// with the session instead of being refused. Prune cannot remove it either, and
453+
// refusing would stop resume and fork wherever locking does not work, for people
454+
// who never prune.
455+
func TestPruneKeepsASessionWhoseLeaseCannotBeChecked(t *testing.T) {
456+
root := t.TempDir()
457+
createFinishedSession(t, root, "old", "2026-06-01T00:00:00Z", "")
458+
lease := filepath.Join(root, "old", leaseFileName)
459+
if err := os.Remove(lease); err != nil && !errors.Is(err, os.ErrNotExist) {
460+
t.Fatalf("remove the lease file: %v", err)
461+
}
462+
// A directory where the lease file goes cannot be opened as one.
463+
if err := os.Mkdir(lease, 0o700); err != nil {
464+
t.Fatalf("SETUP INVALID: %v", err)
465+
}
466+
if _, locked, err := pruneStore(root).HoldExclusive("old"); err == nil || locked {
467+
t.Fatalf("SETUP INVALID: the lease could still be taken: locked=%v, %v", locked, err)
468+
}
469+
470+
for _, dryRun := range []bool{true, false} {
471+
report, err := pruneStore(root).Prune(PruneOptions{OlderThan: thirtyDays, DryRun: dryRun})
472+
if err != nil {
473+
t.Fatalf("Prune (dry run %v): %v", dryRun, err)
474+
}
475+
if reason := keptReason(report, "old"); !strings.HasPrefix(reason, "its lease could not be checked") || len(report.Removed) != 0 || len(report.Failed) != 0 {
476+
t.Fatalf("dry run %v: kept for %q, removed %v, failed %v, want it kept because its lease could not be checked", dryRun, reason, pruneIDs(report.Removed), pruneIDs(report.Failed))
477+
}
478+
}
479+
if !sessionDirExists(t, root, "old") {
480+
t.Fatal("a session whose lease could not be checked was removed")
481+
}
482+
483+
other := NewStore(StoreOptions{RootDir: root})
484+
if _, err := other.ReadRehydratedEvents("old"); err != nil {
485+
t.Fatalf("resume a session whose lease cannot be taken: %v", err)
486+
}
487+
if _, err := other.Fork("old", ForkInput{SessionID: "fork"}); err != nil {
488+
t.Fatalf("fork a session whose lease cannot be taken: %v", err)
489+
}
490+
}

0 commit comments

Comments
 (0)