Files
mal/internal/playback/handler/episode_metadata_test.go

129 lines
3.7 KiB
Go

package handler
import (
"bytes"
"context"
"encoding/json"
"errors"
"mal/internal/db"
"mal/internal/domain"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/gin-gonic/gin"
)
type episodeMetadataAnimeService struct {
domain.AnimePlaybackService
err error
}
func (s episodeMetadataAnimeService) GetAllEpisodes(context.Context, int) ([]domain.EpisodeData, error) {
if s.err != nil {
return nil, s.err
}
return []domain.EpisodeData{
{MalID: 1, Title: "The Beginning"},
{MalID: 2, Title: "The Follow-Up"},
}, nil
}
func (s episodeMetadataAnimeService) GetAnimeByID(context.Context, int) (domain.Anime, error) {
return domain.Anime{}, nil
}
type failingSkipSegmentPlaybackService struct {
domain.PlaybackService
}
func (s failingSkipSegmentPlaybackService) UpsertSkipSegmentOverride(context.Context, string, int64, int, string, float64, float64) error {
return errors.New("database constraint skip_segments_user_id_fkey failed")
}
func TestEpisodeMetadataRouteReturnsEpisodeTitles(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
router := gin.New()
h := NewPlaybackHandler(nil, episodeMetadataAnimeService{})
h.Register(router)
req := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/api/watch/episodes/123/metadata", nil)
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var got []struct {
MalID int `json:"mal_id"`
Title string `json:"title"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatalf("json.Unmarshal() error = %v", err)
}
if len(got) != 2 {
t.Fatalf("len(got) = %d, want 2", len(got))
}
if got[0].MalID != 1 || got[0].Title != "The Beginning" {
t.Fatalf("got[0] = %+v, want episode 1 title", got[0])
}
}
func TestEpisodeMetadataRouteHidesServiceError(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
router := gin.New()
h := NewPlaybackHandler(nil, episodeMetadataAnimeService{err: errors.New("upstream returned credentials in URL")})
h.Register(router)
req := httptest.NewRequestWithContext(context.Background(), http.MethodGet, "/api/watch/episodes/123/metadata", nil)
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusInternalServerError)
}
body := rec.Body.String()
if !strings.Contains(body, `"error":"failed to load episode metadata"`) {
t.Fatalf("expected stable public error, got %s", body)
}
if strings.Contains(body, "upstream returned credentials") {
t.Fatalf("expected private service error to stay out of response, got %s", body)
}
}
func TestUpsertSkipSegmentRouteHidesServiceError(t *testing.T) {
t.Parallel()
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(func(c *gin.Context) {
c.Set("User", &domain.User{User: db.User{ID: "user-1"}})
})
h := NewPlaybackHandler(failingSkipSegmentPlaybackService{}, nil)
h.Register(router)
body := bytes.NewBufferString(`{"mal_id":123,"episode":1,"skip_type":"op","start_time":10,"end_time":90}`)
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/api/watch/segments", body)
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
router.ServeHTTP(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
}
responseBody := rec.Body.String()
if !strings.Contains(responseBody, `"error":"invalid skip segment"`) {
t.Fatalf("expected stable public error, got %s", responseBody)
}
if strings.Contains(responseBody, "database constraint") {
t.Fatalf("expected private service error to stay out of response, got %s", responseBody)
}
}