Files
memby/server/internal/store/settings_test.go
T
2026-08-17 07:34:23 +12:00

155 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package store
import (
"testing"
"time"
)
func TestQuietTimeActiveHandlesDaytimeAndOvernightWindows(t *testing.T) {
location := time.FixedZone("NZST", 12*60*60)
at := func(hour, minute int) time.Time {
return time.Date(2026, time.August, 17, hour, minute, 0, 0, location)
}
tests := []struct {
name string
policy QuietTime
now time.Time
want bool
}{
{"disabled", QuietTime{StartTime: "23:00", EndTime: "07:00"}, at(23, 30), false},
{"overnight evening", QuietTime{Enabled: true, StartTime: "23:00", EndTime: "07:00"}, at(23, 0), true},
{"overnight morning", QuietTime{Enabled: true, StartTime: "23:00", EndTime: "07:00"}, at(6, 59), true},
{"overnight end exclusive", QuietTime{Enabled: true, StartTime: "23:00", EndTime: "07:00"}, at(7, 0), false},
{"daytime inside", QuietTime{Enabled: true, StartTime: "09:00", EndTime: "17:00"}, at(12, 0), true},
{"daytime outside", QuietTime{Enabled: true, StartTime: "09:00", EndTime: "17:00"}, at(18, 0), false},
{"equal endpoints are safe", QuietTime{Enabled: true, StartTime: "09:00", EndTime: "09:00"}, at(9, 0), false},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := QuietTimeActive(test.policy, test.now, location); got != test.want {
t.Fatalf("QuietTimeActive() = %v, want %v", got, test.want)
}
})
}
}
func TestRequestPolicyAllowsOnlyListedUsers(t *testing.T) {
policy := RequestPolicy{AllowedUserIDs: []string{"user-2"}}
if policy.Allows("user-1") {
t.Fatal("unlisted user was allowed")
}
if !policy.Allows("user-2") {
t.Fatal("listed user was denied")
}
}
func TestPlaybackPolicyDefaultsAndClampsDuration(t *testing.T) {
defaults := DefaultPlaybackPolicy()
if !defaults.PrerollEnabled || defaults.PrerollDurationMs != 6_500 {
t.Fatalf("default playback policy = %+v", defaults)
}
if got := normalizePlaybackPolicy(PlaybackPolicy{PrerollDurationMs: 500}); got.PrerollDurationMs != 1_000 {
t.Fatalf("short duration = %d, want 1000", got.PrerollDurationMs)
}
if got := normalizePlaybackPolicy(PlaybackPolicy{PrerollDurationMs: 60_000}); got.PrerollDurationMs != 30_000 {
t.Fatalf("long duration = %d, want 30000", got.PrerollDurationMs)
}
}
func TestHeroPolicyKeepsFourUniqueTrimmedItemIDsInOrder(t *testing.T) {
got := normalizeHeroPolicy(HeroPolicy{PinnedItemIDs: []string{
" movie-2 ", "movie-1", "movie-2", "", "movie-3", "movie-4", "movie-5",
}, PrimeSubtitle: " Tonights pick "})
want := []string{"movie-2", "movie-1", "movie-3", "movie-4"}
if len(got.PinnedItemIDs) != len(want) {
t.Fatalf("pinned ids = %v, want %v", got.PinnedItemIDs, want)
}
for index := range want {
if got.PinnedItemIDs[index] != want[index] {
t.Fatalf("pinned ids = %v, want %v", got.PinnedItemIDs, want)
}
}
if got.PrimeSubtitle != "Tonights pick" {
t.Fatalf("prime subtitle = %q", got.PrimeSubtitle)
}
}
func TestHeroPolicyReadsTheEarlierMovieOnlyShape(t *testing.T) {
got := normalizeHeroPolicy(HeroPolicy{LegacyPinnedMovieIDs: []string{"movie-1"}})
if len(got.PinnedItemIDs) != 1 || got.PinnedItemIDs[0] != "movie-1" {
t.Fatalf("legacy pinned ids = %v", got.PinnedItemIDs)
}
}
func TestHeroPolicyMigratesHomeAndKeepsPlacementsIndependent(t *testing.T) {
got := normalizeHeroPolicy(HeroPolicy{
PinnedItemIDs: []string{"home-1"},
Placements: map[string]HeroPlacementPolicy{
HeroPlacementMovies: {PinnedItemIDs: []string{"film-1"}},
HeroPlacementTVShows: {PinnedItemIDs: []string{"series-1"}},
},
})
if got.Placement(HeroPlacementHome).PinnedItemIDs[0] != "home-1" {
t.Fatalf("legacy Home policy was not migrated: %+v", got.Placements)
}
if got.Placement(HeroPlacementMovies).PinnedItemIDs[0] != "film-1" ||
got.Placement(HeroPlacementTVShows).PinnedItemIDs[0] != "series-1" {
t.Fatalf("placement policies crossed: %+v", got.Placements)
}
}
func TestHeroSchedulesDefaultToHomeAndNormalisePlacementNames(t *testing.T) {
now := time.Now()
got := normalizeHeroPolicy(HeroPolicy{Schedules: []HeroSchedule{
{ID: "old", ItemID: "one", StartAt: now, EndAt: now.Add(time.Hour), Enabled: true},
{ID: "new", ItemID: "two", StartAt: now, EndAt: now.Add(time.Hour), Enabled: true, Placements: []string{" MOVIES ", "movies", "bad"}},
}})
if len(got.Schedules[0].Placements) != 1 || got.Schedules[0].Placements[0] != HeroPlacementHome {
t.Fatalf("old schedule placements = %v", got.Schedules[0].Placements)
}
if len(got.Schedules[1].Placements) != 1 || got.Schedules[1].Placements[0] != HeroPlacementMovies {
t.Fatalf("new schedule placements = %v", got.Schedules[1].Placements)
}
}
func TestHeroPolicyKeepsRecurringSchedulesWithoutAbsoluteDates(t *testing.T) {
got := normalizeHeroPolicy(HeroPolicy{Schedules: []HeroSchedule{
{ID: "daily", ItemID: "one", Frequency: "DAILY", StartTime: " 18:00 ", EndTime: "22:30", Enabled: true},
{ID: "weekly", ItemID: "two", Frequency: "weekly", StartTime: "22:00", EndTime: "02:00", Weekdays: []int{5, 5, 7}, Enabled: true},
}})
if len(got.Schedules) != 2 {
t.Fatalf("recurring schedules = %+v", got.Schedules)
}
if got.Schedules[0].Frequency != "daily" || len(got.Schedules[0].Weekdays) != 0 {
t.Fatalf("daily schedule = %+v", got.Schedules[0])
}
if got.Schedules[1].StartTime != "22:00" || len(got.Schedules[1].Weekdays) != 1 || got.Schedules[1].Weekdays[0] != 5 {
t.Fatalf("weekly schedule = %+v", got.Schedules[1])
}
}
func TestMDBListSettingsAreOptionalAndNormalizeSources(t *testing.T) {
defaults := DefaultMDBListSettings()
if defaults.Enabled || defaults.APIKey != "" || len(defaults.Sources) == 0 {
t.Fatalf("default MDBList settings = %+v", defaults)
}
got := normalizeMDBListSettings(MDBListSettings{
APIKey: " secret ", Sources: []string{"IMDb", "imdb", "unknown", "letterboxd"},
})
if got.APIKey != "secret" || len(got.Sources) != 2 ||
got.Sources[0] != "imdb" || got.Sources[1] != "letterboxd" {
t.Fatalf("normalised MDBList settings = %+v", got)
}
}
func TestFeaturePolicyDefaultsAreRecoverable(t *testing.T) {
policy := normalizeFeaturePolicy(FeaturePolicy{})
if policy.Overrides == nil || policy.SafeMode || policy.Revision != 0 {
t.Fatalf("default feature policy = %+v", policy)
}
policy.Overrides["sonarr_preroll"] = false
if policy.Overrides["sonarr_preroll"] {
t.Fatal("explicit off override was not retained")
}
}