Files
silo-server/internal/artworkkey/artworkkey_test.go
1664c60425 fix(metadata): publish artwork revisions atomically (#399)
* fix(metadata): publish artwork revisions atomically

* fix(metadata): harden artwork revision cleanup

* fix(metadata): address artwork revision review findings

- restore image applies for all media_items types and reject unsupported
  target/image combinations with 400 before uploading; episodes coerce to
  stills and the web dialog no longer offers image tabs episodes can't use
- add WHEN clauses to displacement triggers and hoist to_jsonb so bulk
  catalog upserts that assign unchanged artwork columns skip the trigger
- make artworkkey the single variant-ladder owner: imagecache derives its
  widths from it and triggers store image_type instead of hardcoded
  variant arrays, expanded by the collector at deletion time
- sweep dormant registry rows periodically so references lost through
  untriggered surfaces degrade to slow cleanup instead of leaking
- park just-published revisions dormant, keep dormant rows dormant on
  re-cache, and batch the GC reference pre-check per run
- heal rows re-referencing a just-deleted revision via reconciler-style
  resets after the deletion commits
- share a per-URL image-loaded hook across DetailHero, ItemCard,
  SectionItemCard, GlobalSearch, and CollectionPosterCard
- deduplicate Cache/CacheBytes finalization and drop unused VariantPaths
  plumbing

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(catalog): cast reused timestamp parameter in revision upsert

Postgres cannot deduce one type for $3 used both as a plain value and
inside a CASE arm; the dev deploy surfaced it as SQLSTATE 42P08 on every
publication. Cast both uses and cover the arm/park/track upserts with
database-backed tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(metadata): address artwork revision review comments

- keep a durable heal path: deletion marks deleted_at instead of removing
  the registry row, so a failed post-delete heal retries with backoff and
  broken references never park; trackers clear the marker on re-upload
- never treat bare existence as an immutable-content match; backends
  without content verification rewrite the object
- exercise revisioned cover keys in scanner/enrichment fakes, compare the
  tracked manifest exactly, and honor cancellation in the blocking test
  deleter

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Quick104 <31828688+Quick104@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 17:33:21 -04:00

39 lines
1.2 KiB
Go

package artworkkey
import "testing"
func TestRevisionedArtworkKeys(t *testing.T) {
base := "tmdb/movies/550/poster"
original := Original(base, "abc123", ".webp")
if original != base+"/original.abc123.webp" {
t.Fatalf("Original() = %q", original)
}
if got := Variant(original, "w500"); got != base+"/w500.abc123.webp" {
t.Fatalf("Variant() = %q", got)
}
if got := Revision(original); got != "abc123" {
t.Fatalf("Revision() = %q", got)
}
if got := Directory(original); got != base+"/" {
t.Fatalf("Directory() = %q", got)
}
}
func TestLegacyArtworkKeysRemainSupported(t *testing.T) {
original := "tmdb/movies/550/poster/original.webp"
if got := Variant(original, "w300"); got != "tmdb/movies/550/poster/w300.webp" {
t.Fatalf("Variant() = %q", got)
}
if got := Revision(original); got != "" {
t.Fatalf("Revision() = %q, want empty", got)
}
}
func TestVariantOnlyRewritesOriginalFilename(t *testing.T) {
original := "tmdb/movies/original.segment/550/poster/original.abc123.webp"
want := "tmdb/movies/original.segment/550/poster/w500.abc123.webp"
if got := Variant(original, "w500"); got != want {
t.Fatalf("Variant() = %q, want %q", got, want)
}
}