mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-07 13:56:37 +08:00
refactor: split emby handler compatibility tests
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/gorilla/websocket"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service"
|
||||
)
|
||||
|
||||
func TestEmbyVirtualFoldersRouteReturnsJSON(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open db: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.User{}, &model.Library{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
repos := repository.New(db)
|
||||
if err := repos.User.Create(t.Context(), &model.User{
|
||||
Base: model.Base{ID: "user-1"},
|
||||
Username: "tester",
|
||||
PasswordHash: "x",
|
||||
Role: "admin",
|
||||
Tier: "plus",
|
||||
IsActive: true,
|
||||
}); err != nil {
|
||||
t.Fatalf("create user: %v", err)
|
||||
}
|
||||
for _, lib := range []model.Library{
|
||||
{Name: "电影", Path: "D:\\media\\movies", Type: "movie", Enabled: true},
|
||||
{Name: "剧集", Path: "D:\\media\\tv", Type: "tv", Enabled: true},
|
||||
{Name: "综艺", Path: "D:\\media\\variety", Type: "variety", Enabled: true},
|
||||
} {
|
||||
if err := repos.Library.Create(t.Context(), &lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
const secret = "test-secret"
|
||||
router := gin.New()
|
||||
registerEmbyRoutes(router, secret, &service.Container{Repo: repos})
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/Library/VirtualFolders", nil)
|
||||
req.Header.Set("X-Emby-Token", signedTestToken(t, secret))
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
if contentType := w.Header().Get("Content-Type"); !strings.Contains(contentType, "application/json") {
|
||||
t.Fatalf("expected JSON content type, got %q body=%s", contentType, w.Body.String())
|
||||
}
|
||||
if strings.HasPrefix(strings.TrimSpace(w.Body.String()), "<!doctype html>") {
|
||||
t.Fatalf("route returned frontend HTML instead of JSON")
|
||||
}
|
||||
|
||||
var folders []map[string]any
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &folders); err != nil {
|
||||
t.Fatalf("decode folders: %v", err)
|
||||
}
|
||||
if len(folders) != 3 {
|
||||
t.Fatalf("expected 3 folders, got %d: %#v", len(folders), folders)
|
||||
}
|
||||
if folders[1]["CollectionType"] != "tvshows" || folders[2]["CollectionType"] != "tvshows" {
|
||||
t.Fatalf("episodic libraries should expose tvshows collection type: %#v", folders)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyItemsCountsRouteReturnsJSON(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open db: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.User{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
repos := repository.New(db)
|
||||
if err := repos.User.Create(t.Context(), &model.User{
|
||||
Base: model.Base{ID: "user-1"},
|
||||
Username: "tester",
|
||||
PasswordHash: "x",
|
||||
Role: "admin",
|
||||
Tier: "plus",
|
||||
IsActive: true,
|
||||
}); err != nil {
|
||||
t.Fatalf("create user: %v", err)
|
||||
}
|
||||
|
||||
const secret = "test-secret"
|
||||
router := gin.New()
|
||||
registerEmbyRoutes(router, secret, &service.Container{Repo: repos})
|
||||
|
||||
for _, path := range []string{"/Items/Counts", "/Users/user-1/Items/Counts", "/items/counts"} {
|
||||
req := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
req.Header.Set("X-Emby-Token", signedTestToken(t, secret))
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("%s status=%d body=%s", path, w.Code, w.Body.String())
|
||||
}
|
||||
var body map[string]any
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("%s decode response: %v", path, err)
|
||||
}
|
||||
if _, ok := body["MovieCount"]; !ok {
|
||||
t.Fatalf("%s missing MovieCount: %#v", path, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyDisplayPreferencesAllowsAnonymousCompatibility(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
registerEmbyRoutes(router, "secret", &service.Container{})
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/emby/DisplayPreferences/usersettings", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("unexpected GET status: %d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
var body map[string]any
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("decode display preferences: %v", err)
|
||||
}
|
||||
if body["Id"] != "usersettings" {
|
||||
t.Fatalf("unexpected preferences payload: %#v", body)
|
||||
}
|
||||
customPrefs, ok := body["CustomPrefs"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("missing CustomPrefs: %#v", body)
|
||||
}
|
||||
if customPrefs["homesection0"] != "smalllibrarytiles" || customPrefs["homesection2"] != "latestmedia" {
|
||||
t.Fatalf("homepage sections should expose library tiles and latest media: %#v", customPrefs)
|
||||
}
|
||||
|
||||
req = httptest.NewRequest(http.MethodPost, "/emby/displaypreferences/usersettings", strings.NewReader(`{}`))
|
||||
w = httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusNoContent {
|
||||
t.Fatalf("unexpected POST status: %d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyWebSocketRouteUpgradesForOfficialClients(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
registerEmbyRoutes(router, "secret", &service.Container{})
|
||||
server := httptest.NewServer(router)
|
||||
defer server.Close()
|
||||
|
||||
wsURL := "ws" + strings.TrimPrefix(server.URL, "http") + "/embywebsocket?api_key=test-token&deviceId=device-1"
|
||||
conn, resp, err := websocket.DefaultDialer.Dial(wsURL, nil)
|
||||
if err != nil {
|
||||
status := 0
|
||||
if resp != nil {
|
||||
status = resp.StatusCode
|
||||
}
|
||||
t.Fatalf("websocket dial failed status=%d err=%v", status, err)
|
||||
}
|
||||
defer conn.Close()
|
||||
if resp == nil || resp.StatusCode != http.StatusSwitchingProtocols {
|
||||
t.Fatalf("expected websocket upgrade, got resp=%#v", resp)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user