* 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>
80 lines
2.1 KiB
Go
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)
|
|
}
|
|
}
|