167 lines
5.4 KiB
Go
167 lines
5.4 KiB
Go
package catalog
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"os"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
||
|
|
|
||
|
|
"github.com/Silo-Server/silo-server/internal/models"
|
||
|
|
)
|
||
|
|
|
||
|
|
func newRestampTestPool(t *testing.T) *pgxpool.Pool {
|
||
|
|
t.Helper()
|
||
|
|
dsn := os.Getenv("SILO_TEST_DATABASE_URL")
|
||
|
|
if dsn == "" {
|
||
|
|
t.Skip("SILO_TEST_DATABASE_URL is not set")
|
||
|
|
}
|
||
|
|
pool, err := pgxpool.New(context.Background(), dsn)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("connect test database: %v", err)
|
||
|
|
}
|
||
|
|
t.Cleanup(pool.Close)
|
||
|
|
return pool
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestItemUpsertRestampsDefaultMetadataLanguage covers the persistence half of
|
||
|
|
// issue #211: when a refresh adopts a new canonical language, the upsert must
|
||
|
|
// accept the incoming non-empty default_metadata_language instead of pinning
|
||
|
|
// to the stamp written at first match. An empty incoming value must still
|
||
|
|
// keep the existing stamp (scanner skeleton writes send the zero value).
|
||
|
|
func TestItemUpsertRestampsDefaultMetadataLanguage(t *testing.T) {
|
||
|
|
ctx := context.Background()
|
||
|
|
pool := newRestampTestPool(t)
|
||
|
|
repo := NewItemRepository(pool)
|
||
|
|
|
||
|
|
contentID := fmt.Sprintf("restamp-item-%d", time.Now().UnixNano())
|
||
|
|
t.Cleanup(func() {
|
||
|
|
_, _ = pool.Exec(ctx, `DELETE FROM media_items WHERE content_id = $1`, contentID)
|
||
|
|
})
|
||
|
|
|
||
|
|
base := &models.MediaItem{
|
||
|
|
ContentID: contentID,
|
||
|
|
Type: "movie",
|
||
|
|
Title: "Gammel Titel",
|
||
|
|
Status: "matched",
|
||
|
|
DefaultMetadataLanguage: "zh",
|
||
|
|
Studios: []string{},
|
||
|
|
Networks: []string{},
|
||
|
|
Countries: []string{},
|
||
|
|
Genres: []string{},
|
||
|
|
}
|
||
|
|
if err := repo.Upsert(ctx, base); err != nil {
|
||
|
|
t.Fatalf("initial upsert: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
restamped := *base
|
||
|
|
restamped.Title = "Ny Titel"
|
||
|
|
restamped.DefaultMetadataLanguage = "da"
|
||
|
|
if err := repo.Upsert(ctx, &restamped); err != nil {
|
||
|
|
t.Fatalf("restamp upsert: %v", err)
|
||
|
|
}
|
||
|
|
got, err := repo.GetByID(ctx, contentID)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("get item: %v", err)
|
||
|
|
}
|
||
|
|
if got.DefaultMetadataLanguage != "da" {
|
||
|
|
t.Errorf("default_metadata_language = %q, want da (incoming non-empty stamp must win)", got.DefaultMetadataLanguage)
|
||
|
|
}
|
||
|
|
|
||
|
|
emptied := restamped
|
||
|
|
emptied.DefaultMetadataLanguage = ""
|
||
|
|
if err := repo.Upsert(ctx, &emptied); err != nil {
|
||
|
|
t.Fatalf("empty-language upsert: %v", err)
|
||
|
|
}
|
||
|
|
got, err = repo.GetByID(ctx, contentID)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("get item after empty upsert: %v", err)
|
||
|
|
}
|
||
|
|
if got.DefaultMetadataLanguage != "da" {
|
||
|
|
t.Errorf("default_metadata_language = %q, want da kept when incoming is empty", got.DefaultMetadataLanguage)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// TestSeasonAndEpisodeUpsertRestampDefaultMetadataLanguage verifies the same
|
||
|
|
// restamp-on-upsert semantics for the season and episode tables, which carry
|
||
|
|
// their own default_metadata_language pins.
|
||
|
|
func TestSeasonAndEpisodeUpsertRestampDefaultMetadataLanguage(t *testing.T) {
|
||
|
|
ctx := context.Background()
|
||
|
|
pool := newRestampTestPool(t)
|
||
|
|
|
||
|
|
suffix := time.Now().UnixNano()
|
||
|
|
seriesID := fmt.Sprintf("restamp-series-%d", suffix)
|
||
|
|
seasonID := fmt.Sprintf("restamp-season-%d", suffix)
|
||
|
|
episodeID := fmt.Sprintf("restamp-episode-%d", suffix)
|
||
|
|
t.Cleanup(func() {
|
||
|
|
// Seasons and episodes cascade from the series row (FK ON DELETE
|
||
|
|
// CASCADE), so a single delete cleans up everything seeded here.
|
||
|
|
_, _ = pool.Exec(ctx, `DELETE FROM media_items WHERE content_id = $1`, seriesID)
|
||
|
|
})
|
||
|
|
|
||
|
|
itemRepo := NewItemRepository(pool)
|
||
|
|
if err := itemRepo.Upsert(ctx, &models.MediaItem{
|
||
|
|
ContentID: seriesID,
|
||
|
|
Type: "series",
|
||
|
|
Title: "Restamp Series",
|
||
|
|
Status: "matched",
|
||
|
|
DefaultMetadataLanguage: "zh",
|
||
|
|
Studios: []string{},
|
||
|
|
Networks: []string{},
|
||
|
|
Countries: []string{},
|
||
|
|
Genres: []string{},
|
||
|
|
}); err != nil {
|
||
|
|
t.Fatalf("seed series: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
seasonRepo := NewSeasonRepository(pool)
|
||
|
|
season := &models.Season{
|
||
|
|
ContentID: seasonID,
|
||
|
|
SeriesID: seriesID,
|
||
|
|
SeasonNumber: 1,
|
||
|
|
Title: "Sæson 1",
|
||
|
|
DefaultMetadataLanguage: "zh",
|
||
|
|
}
|
||
|
|
if err := seasonRepo.Upsert(ctx, season); err != nil {
|
||
|
|
t.Fatalf("seed season: %v", err)
|
||
|
|
}
|
||
|
|
season.DefaultMetadataLanguage = "da"
|
||
|
|
if err := seasonRepo.Upsert(ctx, season); err != nil {
|
||
|
|
t.Fatalf("restamp season: %v", err)
|
||
|
|
}
|
||
|
|
var seasonLang string
|
||
|
|
if err := pool.QueryRow(ctx, `SELECT default_metadata_language FROM seasons WHERE content_id = $1`, seasonID).Scan(&seasonLang); err != nil {
|
||
|
|
t.Fatalf("read season language: %v", err)
|
||
|
|
}
|
||
|
|
if seasonLang != "da" {
|
||
|
|
t.Errorf("season default_metadata_language = %q, want da", seasonLang)
|
||
|
|
}
|
||
|
|
|
||
|
|
episodeRepo := NewEpisodeRepository(pool)
|
||
|
|
episode := &models.Episode{
|
||
|
|
ContentID: episodeID,
|
||
|
|
SeriesID: seriesID,
|
||
|
|
SeasonID: seasonID,
|
||
|
|
SeasonNumber: 1,
|
||
|
|
EpisodeNumber: 1,
|
||
|
|
Title: "Afsnit 1",
|
||
|
|
DefaultMetadataLanguage: "zh",
|
||
|
|
}
|
||
|
|
if err := episodeRepo.Upsert(ctx, episode); err != nil {
|
||
|
|
t.Fatalf("seed episode: %v", err)
|
||
|
|
}
|
||
|
|
episode.DefaultMetadataLanguage = "da"
|
||
|
|
if err := episodeRepo.Upsert(ctx, episode); err != nil {
|
||
|
|
t.Fatalf("restamp episode: %v", err)
|
||
|
|
}
|
||
|
|
var episodeLang string
|
||
|
|
if err := pool.QueryRow(ctx, `SELECT default_metadata_language FROM episodes WHERE content_id = $1`, episodeID).Scan(&episodeLang); err != nil {
|
||
|
|
t.Fatalf("read episode language: %v", err)
|
||
|
|
}
|
||
|
|
if episodeLang != "da" {
|
||
|
|
t.Errorf("episode default_metadata_language = %q, want da", episodeLang)
|
||
|
|
}
|
||
|
|
}
|