199 lines
5.4 KiB
Go
199 lines
5.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/Silo-Server/silo-server/internal/catalog"
|
|
)
|
|
|
|
type stubCalendarRepo struct {
|
|
calls int
|
|
last catalog.CalendarFilter
|
|
events []catalog.CalendarEvent
|
|
err error
|
|
}
|
|
|
|
func (r *stubCalendarRepo) ListEvents(_ context.Context, f catalog.CalendarFilter) ([]catalog.CalendarEvent, error) {
|
|
r.calls++
|
|
r.last = f
|
|
return r.events, r.err
|
|
}
|
|
|
|
type stubCalendarImageResolver struct {
|
|
resolveURLCalls int
|
|
resolveURLsCalls int
|
|
lastPaths []string
|
|
lastVariant string
|
|
urls map[string]string
|
|
}
|
|
|
|
func (r *stubCalendarImageResolver) ResolveImageURL(_ context.Context, path string, _ string) string {
|
|
r.resolveURLCalls++
|
|
return r.urls[path]
|
|
}
|
|
|
|
func (r *stubCalendarImageResolver) ResolveImageURLs(_ context.Context, paths []string, variant string) map[string]string {
|
|
r.resolveURLsCalls++
|
|
r.lastPaths = append([]string(nil), paths...)
|
|
r.lastVariant = variant
|
|
|
|
result := make(map[string]string, len(paths))
|
|
for _, path := range paths {
|
|
if url, ok := r.urls[path]; ok {
|
|
result[path] = url
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func TestHandleGetCalendar_RejectsEndBeforeStart(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &stubCalendarRepo{}
|
|
handler := &CalendarHandler{repo: repo}
|
|
req := httptest.NewRequest(http.MethodGet, "/calendar?start=2026-04-12&end=2026-04-06", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCalendar(rec, req)
|
|
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
|
|
}
|
|
if repo.calls != 0 {
|
|
t.Fatalf("expected repo not to be called, got %d calls", repo.calls)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetCalendar_RejectsRangesLongerThan31Days(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &stubCalendarRepo{}
|
|
handler := &CalendarHandler{repo: repo}
|
|
req := httptest.NewRequest(http.MethodGet, "/calendar?start=2026-04-01&end=2026-05-02", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCalendar(rec, req)
|
|
|
|
if rec.Code != http.StatusBadRequest {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
|
|
}
|
|
if repo.calls != 0 {
|
|
t.Fatalf("expected repo not to be called, got %d calls", repo.calls)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetCalendar_ReturnsEmptyEvents(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &stubCalendarRepo{}
|
|
handler := &CalendarHandler{repo: repo}
|
|
req := httptest.NewRequest(http.MethodGet, "/calendar?start=2026-04-06&end=2026-04-12", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCalendar(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String())
|
|
}
|
|
|
|
var resp calendarResponse
|
|
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if len(resp.Events) != 0 {
|
|
t.Fatalf("events len = %d, want 0", len(resp.Events))
|
|
}
|
|
}
|
|
|
|
func TestHandleGetCalendar_GroupsEventsAndBatchResolvesCardPosters(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
repo := &stubCalendarRepo{
|
|
events: []catalog.CalendarEvent{
|
|
{
|
|
ContentID: "episode-1",
|
|
Type: "episode",
|
|
Title: "Series",
|
|
SeriesID: ptrString("series-1"),
|
|
SeasonNumber: ptrInt(1),
|
|
EpisodeNumber: ptrInt(1),
|
|
AirDate: time.Date(2026, time.April, 6, 0, 0, 0, 0, time.UTC),
|
|
PosterPath: "images/poster/original.jpg",
|
|
PosterThumbhash: "thumb-a",
|
|
IsPremiere: true,
|
|
},
|
|
{
|
|
ContentID: "episode-2",
|
|
Type: "episode",
|
|
Title: "Series",
|
|
SeriesID: ptrString("series-1"),
|
|
SeasonNumber: ptrInt(1),
|
|
EpisodeNumber: ptrInt(2),
|
|
AirDate: time.Date(2026, time.April, 6, 0, 0, 0, 0, time.UTC),
|
|
PosterPath: "images/poster/original.jpg",
|
|
PosterThumbhash: "thumb-a",
|
|
IsFinale: true,
|
|
},
|
|
},
|
|
}
|
|
resolver := &stubCalendarImageResolver{
|
|
urls: map[string]string{
|
|
"images/poster/w300.jpg": "https://cdn.example/poster-card.jpg",
|
|
},
|
|
}
|
|
detailSvc := &catalog.DetailService{}
|
|
detailSvc.SetImageResolver(resolver)
|
|
|
|
handler := &CalendarHandler{repo: repo, detailSvc: detailSvc}
|
|
req := httptest.NewRequest(http.MethodGet, "/calendar?start=2026-04-06&end=2026-04-12", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCalendar(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String())
|
|
}
|
|
|
|
if resolver.resolveURLsCalls != 1 {
|
|
t.Fatalf("ResolveImageURLs calls = %d, want 1", resolver.resolveURLsCalls)
|
|
}
|
|
if resolver.resolveURLCalls != 0 {
|
|
t.Fatalf("ResolveImageURL calls = %d, want 0", resolver.resolveURLCalls)
|
|
}
|
|
if len(resolver.lastPaths) != 1 || resolver.lastPaths[0] != "images/poster/w300.jpg" {
|
|
t.Fatalf("lastPaths = %#v, want [images/poster/w300.jpg]", resolver.lastPaths)
|
|
}
|
|
if resolver.lastVariant != "card" {
|
|
t.Fatalf("variant = %q, want card", resolver.lastVariant)
|
|
}
|
|
|
|
var resp calendarResponse
|
|
if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil {
|
|
t.Fatalf("decode response: %v", err)
|
|
}
|
|
if len(resp.Events) != 1 {
|
|
t.Fatalf("days len = %d, want 1", len(resp.Events))
|
|
}
|
|
if got := len(resp.Events[0].Items); got != 2 {
|
|
t.Fatalf("items len = %d, want 2", got)
|
|
}
|
|
for i, item := range resp.Events[0].Items {
|
|
if item.PosterURL != "https://cdn.example/poster-card.jpg" {
|
|
t.Fatalf("item %d poster_url = %q, want resolved card URL", i, item.PosterURL)
|
|
}
|
|
}
|
|
}
|
|
|
|
func ptrString(value string) *string {
|
|
return &value
|
|
}
|
|
|
|
func ptrInt(value int) *int {
|
|
return &value
|
|
}
|