From 0147cc59b1a6dbefb0d688588b8d1c6d3f2bf066 Mon Sep 17 00:00:00 2001 From: Deluan Date: Wed, 22 Jul 2026 00:42:42 -0400 Subject: [PATCH] fix(artwork): honor the orphan cutoff in the repository mock The mock's DeleteOrphans now applies createdBefore like the SQL implementation, and a new spec covers a freshly reacquired row surviving prune. --- core/artwork/prune_test.go | 18 ++++++++++++++++++ tests/mock_artwork_repo.go | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/core/artwork/prune_test.go b/core/artwork/prune_test.go index 2e5c80d23..4a45ddd13 100644 --- a/core/artwork/prune_test.go +++ b/core/artwork/prune_test.go @@ -78,6 +78,24 @@ var _ = Describe("Prune", func() { rc.Close() }) + It("spares a candidate whose row was freshly recreated (created_at inside the grace window)", func() { + data := []byte("fresh-reacquired-bytes") + h, _ := HashImage(bytes.NewReader(data)) + Expect(store.Write(h, "image/jpeg", bytes.NewReader(data))).To(Succeed()) + // Reacquisition refreshed created_at after the snapshot; still unreferenced. + Expect(awRepo.PutImage(&model.Artwork{Hash: h, Mime: "image/jpeg", + CreatedAt: time.Now()})).To(Succeed()) + awRepo.OrphanHashes = []string{h} + + Expect(Prune(context.Background(), ds, store)).To(Succeed()) + + _, err := awRepo.GetImage(h) + Expect(err).ToNot(HaveOccurred()) + rc, err := store.Open(h, "image/jpeg") + Expect(err).ToNot(HaveOccurred()) + rc.Close() + }) + It("spares an orphan file freshly touched by an overlapping acquisition", func() { data := []byte("racing-bytes") h, _ := HashImage(bytes.NewReader(data)) diff --git a/tests/mock_artwork_repo.go b/tests/mock_artwork_repo.go index 851ee7f48..9565abd7b 100644 --- a/tests/mock_artwork_repo.go +++ b/tests/mock_artwork_repo.go @@ -73,11 +73,14 @@ func (m *MockArtworkRepo) DeleteOrphans(createdBefore time.Time, hashes []string if m.Err != nil { return m.Err } - // Mirror the SQL reference re-check; createdBefore is ignored in the mock for simplicity. + // Mirror the SQL re-check: only unreferenced rows older than the cutoff are deleted. for _, h := range hashes { if m.referenced(h) { continue } + if a, ok := m.Data[h]; ok && !a.CreatedAt.Before(createdBefore) { + continue + } delete(m.Data, h) } return nil