Files
silo-server/internal/metadata/match_identity_fallback_test.go
383973ec22 feat(metadata): improve match accuracy and localized titles (#461)
* feat(metadata): improve match accuracy and localized titles

* fix(metadata): address matching review findings

* test(catalog): align empty alias snapshot scope

---------

Co-authored-by: Quick104 <31828688+Quick104@users.noreply.github.com>
2026-07-24 12:02:52 -04:00

127 lines
4.4 KiB
Go

//nolint:goconst // Repeated titles and provider IDs document each fallback scenario.
package metadata
import (
"context"
"sync"
"testing"
)
type identityFallbackProvider struct {
mu sync.Mutex
queries []SearchQuery
}
type typeMismatchProvider struct{}
func (p *typeMismatchProvider) Slug() string { return "tmdb" }
func (p *typeMismatchProvider) Name() string { return "TMDB" }
func (p *typeMismatchProvider) ForTypes() []string { return []string{"movie", "series"} }
func (p *typeMismatchProvider) Search(_ context.Context, query SearchQuery) ([]SearchResult, error) {
if query.ContentType != "series" || query.ProviderIDs["imdb"] != "tt10473306" {
return nil, nil
}
return []SearchResult{{
Name: "Are You Afraid of the Dark?", Year: 2019, Provider: "tmdb",
ProviderIDs: map[string]string{"imdb": "tt10473306", "tmdb": "83755"},
}}, nil
}
func (p *typeMismatchProvider) GetMetadata(context.Context, MetadataRequest) (*MetadataResult, error) {
return &MetadataResult{}, nil
}
func (p *identityFallbackProvider) Slug() string { return "tmdb" }
func (p *identityFallbackProvider) Name() string { return "TMDB" }
func (p *identityFallbackProvider) ForTypes() []string { return []string{"movie"} }
func (p *identityFallbackProvider) Search(_ context.Context, query SearchQuery) ([]SearchResult, error) {
p.mu.Lock()
p.queries = append(p.queries, query)
p.mu.Unlock()
if query.Title != "Alien Invasion" || query.Year != 2018 {
return nil, nil
}
return []SearchResult{{
Name: "Alien Invasion", Year: 2018, Provider: "tmdb",
ProviderIDs: map[string]string{"tmdb": "4242"},
}}, nil
}
func (p *identityFallbackProvider) GetMetadata(_ context.Context, req MetadataRequest) (*MetadataResult, error) {
return &MetadataResult{
HasMetadata: true, Title: "Alien Invasion", Year: 2018,
ProviderIDs: map[string]string{"tmdb": req.ProviderIDs["tmdb"]},
}, nil
}
func TestInitialMatchUsesAlternatePathIdentityAfterPrimaryMiss(t *testing.T) {
t.Parallel()
harness := newTestHarness()
provider := &identityFallbackProvider{}
result, err := harness.service.ProcessWithProviders(context.Background(), ProcessRequest{
Hints: &MatchHints{
Title: "After the Lethargy", Year: 2018, Type: "movie",
AlternateIdentities: []MatchIdentityHint{{Title: "Alien Invasion", Year: 2018, Source: "filename"}},
},
Mode: ModeInitialMatch,
}, []Provider{provider})
if err != nil {
t.Fatalf("ProcessWithProviders() error = %v", err)
}
if result == nil || !result.Updated || result.Decision == nil || result.Decision.Outcome != "matched" {
t.Fatalf("result = %#v, want alternate-identity match", result)
}
item, err := harness.itemRepo.GetByID(context.Background(), result.ContentID)
if err != nil {
t.Fatalf("load item: %v", err)
}
if item.Title != "Alien Invasion" || item.TmdbID != "4242" {
t.Fatalf("item = title %q tmdb %q", item.Title, item.TmdbID)
}
provider.mu.Lock()
defer provider.mu.Unlock()
if len(provider.queries) != 2 || provider.queries[1].Title != "Alien Invasion" {
t.Fatalf("queries = %#v, want primary then filename fallback", provider.queries)
}
}
func TestCompactAlternateMatchIdentitiesDeduplicatesAndBounds(t *testing.T) {
t.Parallel()
hints := &MatchHints{
Title: "Primary", Year: 2020,
AlternateIdentities: []MatchIdentityHint{
{Title: "Primary", Year: 2020},
{Title: "A", Year: 2020},
{Title: "A", Year: 2020},
{Title: "B", Year: 2021},
{Title: "C", Year: 2022},
{Title: "D", Year: 2023},
},
}
got := compactAlternateMatchIdentities(hints)
if len(got) != maxProviderIdentityFallbacks || got[0].Title != "A" || got[2].Title != "C" {
t.Fatalf("compact identities = %#v", got)
}
}
func TestInitialMatchDiagnosesTrustedIDInOppositeContentType(t *testing.T) {
t.Parallel()
harness := newTestHarness()
result, err := harness.service.ProcessWithProviders(context.Background(), ProcessRequest{
Hints: &MatchHints{
Title: "Are You Afraid of the Dark!", Year: 2019, Type: "movie", ImdbID: "tt10473306",
},
Mode: ModeInitialMatch,
}, []Provider{&typeMismatchProvider{}})
if err != nil {
t.Fatalf("ProcessWithProviders() error = %v", err)
}
if result == nil || result.Decision == nil || result.Decision.Outcome != "trusted_id_type_mismatch" {
t.Fatalf("result = %#v, want trusted-ID type mismatch", result)
}
if result.Decision.CandidateCount != 1 {
t.Fatalf("decision = %+v, want one opposite-type candidate", result.Decision)
}
}