Files
memby/server/internal/api/alerts_test.go
T
2026-07-29 15:26:55 +12:00

81 lines
3.1 KiB
Go

package api
import (
"strings"
"testing"
"time"
)
func airedItem(id, name, availability string, airsAt time.Time) sonarrScheduleItem {
return sonarrScheduleItem{
ID: id,
Name: name,
MembyEpisodeCode: "S02E04",
MembyEpisodeTitle: "The Crossing",
MembyAirsAt: airsAt.Format(time.RFC3339),
MembyAvailability: availability,
MembyAvailabilityText: availability,
ImageTags: map[string]string{"Primary": "sonarr"},
}
}
func TestBuildSonarrAlertsAnnouncesOnlyEpisodesNotYetInEmby(t *testing.T) {
location := time.FixedZone("NZST", 12*60*60)
now := time.Date(2026, 7, 27, 21, 30, 0, 0, location)
aired := now.Add(-30 * time.Minute)
alerts := buildSonarrAlerts([]sonarrScheduleItem{
airedItem("sonarr:7:42", "Northbound", "awaiting", aired),
airedItem("sonarr:8:43", "Grabbed Show", "downloading", aired.Add(-time.Minute)),
airedItem("sonarr:9:44", "Already Here", "available", aired),
airedItem("sonarr:10:45", "Not Watched", "unmonitored", aired),
airedItem("sonarr:11:46", "Later Tonight", "upcoming", now.Add(90*time.Minute)),
airedItem("sonarr:12:47", "This Morning", "awaiting", now.Add(-8*time.Hour)),
}, now, 3*time.Hour)
if len(alerts) != 2 {
t.Fatalf("expected 2 alerts, got %d: %+v", len(alerts), alerts)
}
first := alerts[0]
if first.ID != "sonarr:7:42:aired" || first.Kind != alertKindSonarrAired {
t.Fatalf("unexpected alert identity: %+v", first)
}
if first.Title != "Northbound" || first.ItemID != "sonarr:7:42" || first.ImageTag != "sonarr" {
t.Fatalf("unexpected alert payload: %+v", first)
}
if !strings.Contains(first.Message, "S02E04 — The Crossing aired at 9:00 PM") ||
!strings.Contains(first.Message, "in Emby soon") {
t.Fatalf("unexpected awaiting message: %q", first.Message)
}
if !strings.Contains(alerts[1].Message, "downloading now") {
t.Fatalf("unexpected downloading message: %q", alerts[1].Message)
}
}
func TestBuildSonarrAlertsSortsNewestFirstAndCaps(t *testing.T) {
location := time.FixedZone("NZST", 12*60*60)
now := time.Date(2026, 7, 27, 22, 0, 0, 0, location)
items := []sonarrScheduleItem{
airedItem("sonarr:1:1", "Oldest", "awaiting", now.Add(-100*time.Minute)),
airedItem("sonarr:2:2", "Newest", "awaiting", now.Add(-5*time.Minute)),
airedItem("sonarr:3:3", "Middle", "awaiting", now.Add(-40*time.Minute)),
airedItem("sonarr:4:4", "Older", "awaiting", now.Add(-80*time.Minute)),
}
alerts := buildSonarrAlerts(items, now, 3*time.Hour)
if len(alerts) != maxAlerts {
t.Fatalf("expected the list capped at %d, got %d", maxAlerts, len(alerts))
}
if alerts[0].Title != "Newest" || alerts[1].Title != "Middle" || alerts[2].Title != "Older" {
t.Fatalf("alerts are not newest-first: %+v", alerts)
}
}
func TestBuildSonarrAlertsDisabledByZeroWindow(t *testing.T) {
now := time.Date(2026, 7, 27, 22, 0, 0, 0, time.UTC)
items := []sonarrScheduleItem{airedItem("sonarr:1:1", "Northbound", "awaiting", now.Add(-time.Minute))}
if alerts := buildSonarrAlerts(items, now, 0); alerts != nil {
t.Fatalf("a zero window must disable alerts, got %+v", alerts)
}
}