Publish current app and server
This commit is contained in:
@@ -4,11 +4,58 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ponzischeme89/memby/server/internal/recommend"
|
||||
"github.com/ponzischeme89/memby/server/internal/store"
|
||||
"github.com/ponzischeme89/memby/server/internal/tracearr"
|
||||
)
|
||||
|
||||
func TestRankPreparedForTimeMovesTypicalPosterAheadWithinRelevantPool(t *testing.T) {
|
||||
location := time.UTC
|
||||
contextProfile := recommend.NewContextAffinityProfile()
|
||||
comedyHistory := recommend.Item{Genres: []string{"Comedy"}}
|
||||
for i := 0; i < 5; i++ {
|
||||
contextProfile.Add(
|
||||
comedyHistory,
|
||||
time.Date(2026, 6, 29+i*7, 20, 0, 0, 0, location),
|
||||
1,
|
||||
i,
|
||||
location,
|
||||
)
|
||||
}
|
||||
rawContext, err := json.Marshal(contextProfile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
items := []store.PreparedForYouItem{
|
||||
{
|
||||
ItemID: "drama", BaseRank: 1, BaseScore: 5,
|
||||
Payload: json.RawMessage(`{"Id":"drama","Genres":["Drama"]}`),
|
||||
ContextAffinity: rawContext,
|
||||
},
|
||||
{
|
||||
ItemID: "comedy", BaseRank: 2, BaseScore: 4.8,
|
||||
Payload: json.RawMessage(`{"Id":"comedy","Genres":["Comedy"]}`),
|
||||
RecommendationReason: "Matches your viewing",
|
||||
ContextAffinity: rawContext,
|
||||
},
|
||||
}
|
||||
|
||||
ranked := rankPreparedForTime(
|
||||
items,
|
||||
time.Date(2026, 7, 27, 20, 0, 0, 0, location),
|
||||
location,
|
||||
)
|
||||
if ranked[0].ItemID != "comedy" {
|
||||
t.Fatalf("first contextual poster = %q, want comedy", ranked[0].ItemID)
|
||||
}
|
||||
if ranked[0].RecommendationReason !=
|
||||
"Matches your viewing · fits what you watch around this time" {
|
||||
t.Fatalf("context reason = %q", ranked[0].RecommendationReason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImportedSessionUsesStableKeyAndRecommendationFingerprint(t *testing.T) {
|
||||
session := tracearr.Session{
|
||||
ID: "session-1", MediaType: "movie", MediaTitle: "Arrival",
|
||||
@@ -35,6 +82,52 @@ func TestImportedSessionUsesStableKeyAndRecommendationFingerprint(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTracearrSessionTerminalRequiresCompletedState(t *testing.T) {
|
||||
active := store.TracearrSession{State: "playing"}
|
||||
if tracearrSessionTerminal(active) {
|
||||
t.Fatal("active session was terminal")
|
||||
}
|
||||
stopped := active
|
||||
stopped.State = "stopped"
|
||||
if !tracearrSessionTerminal(stopped) {
|
||||
t.Fatal("stopped session was not terminal")
|
||||
}
|
||||
watched := active
|
||||
watched.Watched = true
|
||||
if !tracearrSessionTerminal(watched) {
|
||||
t.Fatal("watched session was not terminal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextDailyRebuildUsesConfiguredLocalHour(t *testing.T) {
|
||||
location := time.FixedZone("NZST", 12*60*60)
|
||||
now := time.Date(2026, 7, 31, 5, 30, 0, 0, location)
|
||||
next := nextDailyRebuild(now, location, 4)
|
||||
want := time.Date(2026, 8, 1, 4, 0, 0, 0, location)
|
||||
if !next.Equal(want) {
|
||||
t.Fatalf("next rebuild = %v, want %v", next, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoredResultCapsCandidatePoolAndPersistsAlgorithmVersion(t *testing.T) {
|
||||
result := recommend.PreparedResult{
|
||||
Candidates: make([]recommend.PreparedCandidate, maxPreparedCandidates+50),
|
||||
}
|
||||
for i := range result.Candidates {
|
||||
result.Candidates[i].ItemID = itoaForTest(i + 1)
|
||||
}
|
||||
profile, candidates, err := storedResult("user", time.Now(), result)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(candidates) != maxPreparedCandidates {
|
||||
t.Fatalf("candidate count = %d, want %d", len(candidates), maxPreparedCandidates)
|
||||
}
|
||||
if profile.AlgorithmVersion != preparedAlgorithmVersion {
|
||||
t.Fatalf("algorithm version = %q", profile.AlgorithmVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPreparedRowsUsesMultipleSourcesAndDeduplicatesTitles(t *testing.T) {
|
||||
items := make([]store.PreparedForYouItem, 0, 120)
|
||||
for i := 0; i < 120; i++ {
|
||||
@@ -84,15 +177,23 @@ func TestBuildPreparedRowsUsesMultipleSourcesAndDeduplicatesTitles(t *testing.T)
|
||||
}
|
||||
|
||||
func TestBuildPreparedRowsKeepsASingleGenuinePickup(t *testing.T) {
|
||||
rows := buildPreparedRows([]store.PreparedForYouItem{{
|
||||
ItemID: "show-1", BaseRank: 1,
|
||||
Payload: json.RawMessage(`{"Id":"show-1"}`),
|
||||
ReasonKind: "pick-up",
|
||||
RecommendationReason: "You left this in season 1 · pick it up again",
|
||||
}}, 0, 4)
|
||||
rows := buildPreparedRows([]store.PreparedForYouItem{
|
||||
{
|
||||
ItemID: "show-1", BaseRank: 1,
|
||||
Payload: json.RawMessage(`{"Id":"show-1"}`),
|
||||
ReasonKind: "pick-up",
|
||||
RecommendationReason: "You left this in season 1 · pick it up again",
|
||||
},
|
||||
{
|
||||
ItemID: "show-2", BaseRank: 2,
|
||||
Payload: json.RawMessage(`{"Id":"show-2"}`),
|
||||
ReasonKind: "pick-up",
|
||||
RecommendationReason: "You made it through season 2 · season 3 is waiting",
|
||||
},
|
||||
}, 0, 4)
|
||||
|
||||
if len(rows) != 1 || rows[0].ID != "for-you:pick-up" ||
|
||||
rows[0].Title != "Pick these up again" || len(rows[0].Items) != 1 {
|
||||
rows[0].Title != "Pick this show up again" || len(rows[0].Items) != 1 {
|
||||
t.Fatalf("pickup rows = %+v", rows)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user