Update src/__tests__/task-history-retention.spec.ts

Co-authored-by: Seth Miller <sethmillerp@gmail.com>
This commit is contained in:
Hannes Rudolph 2026-01-19 20:15:17 -07:00
parent 06df1ca068
commit 64b08fb107

View file

@ -138,4 +138,128 @@ describe("utils/task-history-retention.ts purgeOldTasks()", () => {
await fs.rm(base, { recursive: true, force: true })
}
})
it("deletes orphan checkpoint-only directories regardless of age", async () => {
const base = await mkTempBase()
try {
const now = Date.now()
const days = (n: number) => n * 24 * 60 * 60 * 1000
// Create a normal task that is recent (should be kept)
const normalTask = await createTask(base, "task-normal", now - days(1))
// Create an orphan checkpoint-only directory (only has checkpoints/ subdirectory, no metadata)
const orphanDir = path.join(base, "tasks", "task-orphan-checkpoints")
await fs.mkdir(orphanDir, { recursive: true })
const checkpointsDir = path.join(orphanDir, "checkpoints")
await fs.mkdir(checkpointsDir, { recursive: true })
// Add a dummy file inside checkpoints to make it realistic
await fs.writeFile(path.join(checkpointsDir, "checkpoint-1.json"), "{}", "utf8")
// Create another orphan with just checkpoints (no other files)
const orphanDir2 = path.join(base, "tasks", "task-orphan-empty")
await fs.mkdir(orphanDir2, { recursive: true })
const checkpointsDir2 = path.join(orphanDir2, "checkpoints")
await fs.mkdir(checkpointsDir2, { recursive: true })
// Run purge with 7 day retention - orphans should be deleted regardless of age
const { purgedCount } = await purgeOldTasks("7", base, () => {})
// Orphan directories should be deleted even though they're "recent"
expect(await exists(orphanDir)).toBe(false)
expect(await exists(orphanDir2)).toBe(false)
// Normal task should still exist (it's recent)
expect(await exists(normalTask)).toBe(true)
// Should have deleted 2 orphan directories
expect(purgedCount).toBe(2)
} finally {
await fs.rm(base, { recursive: true, force: true })
}
})
it("does not delete directories with checkpoints AND other content", async () => {
const base = await mkTempBase()
try {
const now = Date.now()
const days = (n: number) => n * 24 * 60 * 60 * 1000
// Create a task directory with both checkpoints and other files (but recent, so should be kept)
const taskDir = path.join(base, "tasks", "task-with-content")
await fs.mkdir(taskDir, { recursive: true })
const checkpointsDir = path.join(taskDir, "checkpoints")
await fs.mkdir(checkpointsDir, { recursive: true })
await fs.writeFile(path.join(checkpointsDir, "checkpoint-1.json"), "{}", "utf8")
// Add other files (not just checkpoints)
await fs.writeFile(path.join(taskDir, "some-file.txt"), "content", "utf8")
// Note: No metadata file, so it's technically invalid but has content
const { purgedCount } = await purgeOldTasks("7", base, () => {})
// Should NOT be deleted because it has content besides checkpoints
expect(await exists(taskDir)).toBe(true)
expect(purgedCount).toBe(0)
} finally {
await fs.rm(base, { recursive: true, force: true })
}
})
it("falls back to directory mtime for legacy tasks without metadata", async () => {
const base = await mkTempBase()
try {
const now = Date.now()
const days = (n: number) => n * 24 * 60 * 60 * 1000
// Create a legacy task directory without any metadata file
const oldLegacyDir = path.join(base, "tasks", "task-legacy-old")
await fs.mkdir(oldLegacyDir, { recursive: true })
// Add some content file
await fs.writeFile(path.join(oldLegacyDir, "content.txt"), "old task", "utf8")
// Manually set mtime to 10 days ago by touching the directory
const oldTime = new Date(now - days(10))
await fs.utimes(oldLegacyDir, oldTime, oldTime)
// Create another legacy task that is recent
const recentLegacyDir = path.join(base, "tasks", "task-legacy-recent")
await fs.mkdir(recentLegacyDir, { recursive: true })
await fs.writeFile(path.join(recentLegacyDir, "content.txt"), "recent task", "utf8")
// This one has recent mtime (now)
// Run purge with 7 day retention
const { purgedCount } = await purgeOldTasks("7", base, () => {})
// Old legacy task should be deleted based on mtime
expect(await exists(oldLegacyDir)).toBe(false)
// Recent legacy task should be kept
expect(await exists(recentLegacyDir)).toBe(true)
expect(purgedCount).toBe(1)
} finally {
await fs.rm(base, { recursive: true, force: true })
}
})
it("prioritizes metadata timestamp over mtime when both exist", async () => {
const base = await mkTempBase()
try {
const now = Date.now()
const days = (n: number) => n * 24 * 60 * 60 * 1000
// Create task with old metadata ts but recent mtime
const taskDir = path.join(base, "tasks", "task-priority-test")
await fs.mkdir(taskDir, { recursive: true })
const metadataPath = path.join(taskDir, GlobalFileNames.taskMetadata)
// Metadata says it's 10 days old (should be deleted with 7 day retention)
const metadata = JSON.stringify({ ts: now - days(10) }, null, 2)
await fs.writeFile(metadataPath, metadata, "utf8")
// But directory mtime is recent (could happen after editing)
// (Directory mtime is automatically recent from mkdir/writeFile)
const { purgedCount } = await purgeOldTasks("7", base, () => {})
// Should be deleted based on metadata ts, not mtime
expect(await exists(taskDir)).toBe(false)
expect(purgedCount).toBe(1)
} finally {
await fs.rm(base, { recursive: true, force: true })
}
})
})