Files
gronod d40646211f
Build and publish / Test and build (darwin) (push) Failing after 1m42s
Build and publish / Test and build (linux) (push) Failing after 1m53s
Build and publish / Test and build (windows) (push) Failing after 2m50s
Build and publish / Build and publish Docker image (push) Skipped
Initial Go implementation of Emby.MCP
Go rewrite of the Python Emby.MCP server with tool parity (20 tools),
plus a streamable-HTTP transport with per-request Emby authentication
(Basic / Bearer token passthrough), a multi-arch Docker build, and a
Gitea CI workflow.
2026-09-20 22:52:46 +01:00

124 lines
3.8 KiB
Go

package emby
import (
"context"
"encoding/json"
"net/http"
"strings"
"testing"
)
func TestGetPlayerSessions(t *testing.T) {
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
if got := r.URL.Query().Get("ControllableByUserId"); got != "u1" {
t.Errorf("ControllableByUserId = %q", got)
}
json.NewEncoder(w).Encode([]map[string]any{
{
"Client": "Emby Web", "Id": "s1", "DeviceId": "d1",
"DeviceName": "Chrome", "RemoteEndPoint": "127.0.0.1",
"PlayableMediaTypes": []string{"Audio", "Video"},
"NowPlayingItem": map[string]any{
"Name": "Track", "Id": "i1", "Artists": []string{"A"},
"Album": "Alb", "RunTimeTicks": 36610000000,
},
"PlayState": map[string]any{"PositionTicks": 610000000, "IsPaused": true},
},
{"Client": "Idle", "Id": "s2", "PlayableMediaTypes": []string{}},
})
})
defer srv.Close()
ss, err := c.GetPlayerSessions(context.Background(), "u1", "audio")
if err != nil {
t.Fatal(err)
}
if len(ss) != 1 {
t.Fatalf("sessions = %+v", ss)
}
s := ss[0]
if !s.LocalToMediaServer {
t.Error("expected local_to_media_server true for 127.0.0.1")
}
if s.NowPlayingTitle != "Track" || s.NowPlayingTotalTime != "01:01:01" {
t.Errorf("now_playing = %+v", s)
}
if s.NowPlayingPositionMilliseconds == nil || *s.NowPlayingPositionMilliseconds != 61000 {
t.Errorf("position = %v", s.NowPlayingPositionMilliseconds)
}
if s.NowPlayingIsPaused == nil || !*s.NowPlayingIsPaused {
t.Error("expected is_paused")
}
}
func TestGetPlayerSessionsMediaTypeFilter(t *testing.T) {
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"Client": "A", "Id": "s1", "PlayableMediaTypes": []string{"Video"}},
{"Client": "B", "Id": "s2", "PlayableMediaTypes": []string{"Audio"}},
})
})
defer srv.Close()
ss, _ := c.GetPlayerSessions(context.Background(), "", "Audio")
if len(ss) != 1 || ss[0].SessionID != "s2" {
t.Fatalf("sessions = %+v", ss)
}
}
func TestSendPlayerCommandPlayNow(t *testing.T) {
var path, q string
var body map[string]any
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
path, q = r.URL.Path, r.URL.RawQuery
json.NewDecoder(r.Body).Decode(&body)
w.WriteHeader(200)
})
defer srv.Close()
err := c.SendPlayerCommand(context.Background(), "s1", "PlayNow", "i1,i2", "u1", 0)
if err != nil {
t.Fatal(err)
}
if path != "/Sessions/s1/Playing" {
t.Errorf("path = %s", path)
}
if !strings.Contains(q, "Ids=i1%2Ci2") || !strings.Contains(q, "PlayCommand=PlayNow") {
t.Errorf("query = %s", q)
}
}
func TestSendPlayerCommandRewindBecomesSeekRelative(t *testing.T) {
var path string
var body map[string]any
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
path = r.URL.Path
json.NewDecoder(r.Body).Decode(&body)
w.WriteHeader(200)
})
defer srv.Close()
if err := c.SendPlayerCommand(context.Background(), "s1", "Rewind", "", "u1", 0); err != nil {
t.Fatal(err)
}
if path != "/Sessions/s1/Playing/SeekRelative" {
t.Errorf("path = %s", path)
}
if body["Command"] != "SeekRelative" || body["SeekPositionTicks"] != float64(-30000*10000) {
t.Errorf("body = %v", body)
}
if body["ControllingUserId"] != "u1" {
t.Errorf("body = %v", body)
}
}
func TestSendPlayerCommandValidation(t *testing.T) {
c, srv := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {})
defer srv.Close()
if err := c.SendPlayerCommand(context.Background(), "s1", "PlayNow", "", "u1", 0); err == nil {
t.Error("expected item_ids error")
}
if err := c.SendPlayerCommand(context.Background(), "s1", "Bogus", "", "u1", 0); err == nil {
t.Error("expected unsupported command error")
}
if err := c.SendPlayerCommand(context.Background(), "s1", "Pause", "", "", 0); err == nil {
t.Error("expected user_id error")
}
}