Files
silo-server/internal/metadata/provider_404_test.go
99d205676f fix(metadata): prevent stale cross-provider IDs (#480)
* fix(metadata): prevent stale cross-provider IDs

* fix(metadata): address stale ID review findings

* fix(migrations): build the stale-ID primary key concurrently

ALTER TABLE ... ADD PRIMARY KEY builds the index under ACCESS EXCLUSIVE,
blocking reads and writes on stale_media_ids for the whole build. Create the
wider unique index with CREATE UNIQUE INDEX CONCURRENTLY and attach it with
ADD CONSTRAINT ... PRIMARY KEY USING INDEX instead; all three key columns are
already NOT NULL, so the attach is metadata-only. Same treatment on the
rollback path, plus the repo's INVALID-remnant cleanup so a failed concurrent
build is not silently accepted by IF NOT EXISTS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Quick <31828688+Quick104@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 11:19:33 -04:00

80 lines
2.1 KiB
Go

package metadata
import (
"errors"
"testing"
)
func TestHandleScopedProvider404KeepsProviderID(t *testing.T) {
t.Parallel()
ids := map[string]string{
"tmdb": "32843",
"tvdb": "164951",
}
if !handleScopedProvider404("tmdb", ids, errors.New("tmdb: HTTP 404: not found"), "season", 0) {
t.Fatal("handleScopedProvider404() = false, want true")
}
if ids["tmdb"] != "32843" {
t.Fatalf("tmdb id = %q, want preserved", ids["tmdb"])
}
if ids["tvdb"] != "164951" {
t.Fatalf("tvdb id = %q, want preserved", ids["tvdb"])
}
}
func TestHandleProvider404DropsProviderID(t *testing.T) {
t.Parallel()
ids := map[string]string{
"tmdb": "32843",
"tvdb": "164951",
}
if !handleProvider404(nil, ids, "tmdb", errors.New("tmdb: HTTP 404: not found")) {
t.Fatal("handleProvider404() = false, want true")
}
if _, ok := ids["tmdb"]; ok {
t.Fatalf("tmdb id was not dropped: %v", ids)
}
if ids["tvdb"] != "164951" {
t.Fatalf("tvdb id = %q, want preserved", ids["tvdb"])
}
}
func TestProvider404StateKeepsAllRejectedValues(t *testing.T) {
t.Parallel()
state := newProvider404State()
state.record("tmdb", "111")
state.record("tmdb", "222")
if _, ok := state.stale["tmdb"]["111"]; !ok {
t.Fatal("first rejected tmdb value was lost")
}
if _, ok := state.stale["tmdb"]["222"]; !ok {
t.Fatal("second rejected tmdb value was not recorded")
}
}
func TestApplyProvider404sDropsNonDurableIDsWithoutPersistingThem(t *testing.T) {
t.Parallel()
state := newProvider404State()
state.record(testMetaDBProvider, "ephemeral-1")
accumulator := &MetadataResult{ProviderIDs: map[string]string{
testMetaDBProvider: "ephemeral-1",
"tmdb": "603",
}}
applyProvider404sToAccumulator(accumulator, state)
if accumulator.ProviderIDs[testMetaDBProvider] != "" {
t.Fatalf("rejected metadb id was resurrected: %#v", accumulator.ProviderIDs)
}
if accumulator.ProviderIDs["tmdb"] != "603" {
t.Fatalf("unrelated tmdb id was removed: %#v", accumulator.ProviderIDs)
}
if len(accumulator.sameRunStaleProviderIDs) != 0 {
t.Fatalf("ephemeral ID was marked durable stale: %#v", accumulator.sameRunStaleProviderIDs)
}
}