This commit is contained in:
ponzischeme89
2026-08-20 07:54:03 +12:00
parent 769fe01c84
commit 434371e9cf
37 changed files with 1767 additions and 102 deletions
+112
View File
@@ -0,0 +1,112 @@
package api
import (
"testing"
"time"
"github.com/ponzischeme89/memby/server/internal/store"
)
var heroRevisionZone = time.FixedZone("NZST", 12*60*60)
func heroRevisionAt(policy store.HeroPolicy, user string, at time.Time) string {
return heroRevision(policy, user, at, heroRevisionZone)
}
func pinnedPolicy(placement string, ids ...string) store.HeroPolicy {
return store.HeroPolicy{Placements: map[string]store.HeroPlacementPolicy{
placement: {PinnedItemIDs: ids},
}}
}
func TestHeroRevisionIsStableWithinASlot(t *testing.T) {
policy := pinnedPolicy(store.HeroPlacementHome, "film-1")
morning := time.Date(2026, 8, 20, 8, 0, 0, 0, heroRevisionZone)
if heroRevisionAt(policy, "user-1", morning) != heroRevisionAt(policy, "user-1", morning.Add(90*time.Minute)) {
t.Fatal("hero revision moved without anything changing; every poll would refetch")
}
}
func TestHeroRevisionMovesWhenAnOperatorEditsPins(t *testing.T) {
now := time.Date(2026, 8, 20, 8, 0, 0, 0, heroRevisionZone)
before := heroRevisionAt(pinnedPolicy(store.HeroPlacementHome, "film-1"), "user-1", now)
for name, policy := range map[string]store.HeroPolicy{
"added": pinnedPolicy(store.HeroPlacementHome, "film-1", "film-2"),
"removed": pinnedPolicy(store.HeroPlacementHome),
"replaced": pinnedPolicy(store.HeroPlacementHome, "film-2"),
} {
if heroRevisionAt(policy, "user-1", now) == before {
t.Fatalf("hero revision did not move when a pin was %s", name)
}
}
// Order is the operator's decision about which card leads, so reordering is a change
// even though the same titles are pinned.
reordered := pinnedPolicy(store.HeroPlacementHome, "film-2", "film-1")
if heroRevisionAt(reordered, "user-1", now) ==
heroRevisionAt(pinnedPolicy(store.HeroPlacementHome, "film-1", "film-2"), "user-1", now) {
t.Fatal("hero revision did not move when pins were reordered")
}
}
func TestHeroRevisionSeparatesPlacements(t *testing.T) {
now := time.Date(2026, 8, 20, 8, 0, 0, 0, heroRevisionZone)
home := heroRevisionAt(pinnedPolicy(store.HeroPlacementHome, "film-1"), "user-1", now)
movies := heroRevisionAt(pinnedPolicy(store.HeroPlacementMovies, "film-1"), "user-1", now)
if home == movies {
t.Fatal("pinning a title to Movies read as the same policy as pinning it to Home")
}
}
func TestHeroRevisionIgnoresACosmeticSave(t *testing.T) {
now := time.Date(2026, 8, 20, 8, 0, 0, 0, heroRevisionZone)
saved := pinnedPolicy(store.HeroPlacementHome, "film-1")
// UpdatedAt moves on every write. Hashing the document rather than what it resolves to
// would repaint every launcher in the house for a save that changed nothing.
resaved := pinnedPolicy(store.HeroPlacementHome, "film-1")
resaved.UpdatedAt = now
if heroRevisionAt(saved, "user-1", now) != heroRevisionAt(resaved, "user-1", now) {
t.Fatal("hero revision moved for a save that changed nothing")
}
}
func TestHeroRevisionMovesWhenAScheduleOpensAndCloses(t *testing.T) {
policy := store.HeroPolicy{Schedules: []store.HeroSchedule{{
ID: "s1", ItemID: "film-9", Enabled: true,
Frequency: "daily", StartTime: "20:00", EndTime: "22:00",
Placements: []string{store.HeroPlacementHome},
}}}
before := time.Date(2026, 8, 20, 19, 0, 0, 0, heroRevisionZone)
during := time.Date(2026, 8, 20, 21, 0, 0, 0, heroRevisionZone)
// Two readings within one rotation slot, so only the schedule can be the difference.
if heroRotationSlot(before, heroRevisionZone) != heroRotationSlot(during, heroRevisionZone) {
t.Fatal("test times straddle a rotation slot; the schedule is no longer the only variable")
}
if heroRevisionAt(policy, "user-1", before) == heroRevisionAt(policy, "user-1", during) {
t.Fatal("hero revision did not move when a scheduled hero came into force")
}
empty := store.HeroPolicy{}
if heroRevisionAt(policy, "user-1", before) != heroRevisionAt(empty, "user-1", before) {
t.Fatal("a schedule that is not yet in force changed the revision; the launcher would repaint for nothing")
}
}
func TestHeroRevisionIsPerViewerForAPersonalSchedule(t *testing.T) {
now := time.Date(2026, 8, 20, 21, 0, 0, 0, heroRevisionZone)
policy := store.HeroPolicy{Schedules: []store.HeroSchedule{{
ID: "s1", ItemID: "film-9", Enabled: true, UserID: "user-1",
Frequency: "daily", StartTime: "20:00", EndTime: "22:00",
Placements: []string{store.HeroPlacementHome},
}}}
if heroRevisionAt(policy, "user-1", now) == heroRevisionAt(policy, "user-2", now) {
t.Fatal("one viewer's scheduled hero moved another viewer's revision")
}
}
func TestHeroRevisionMovesWithTheRotationSlot(t *testing.T) {
policy := pinnedPolicy(store.HeroPlacementHome, "film-1")
morning := time.Date(2026, 8, 20, 8, 0, 0, 0, heroRevisionZone)
evening := time.Date(2026, 8, 20, 20, 0, 0, 0, heroRevisionZone)
if heroRevisionAt(policy, "user-1", morning) == heroRevisionAt(policy, "user-1", evening) {
t.Fatal("hero revision did not move across rotation slots; the day's draw would never be refetched")
}
}