package subsonic import ( "fmt" "net/http" "net/http/httptest" "testing" "time" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) const podcastFeedXML = ` Test Cast desc Ep 1 ep1 ` func TestPodcastLifecycle(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "admin", "adminpassword1", true) var feedURL string mux := http.NewServeMux() mux.HandleFunc("/feed.xml", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, podcastFeedXML, feedURL) }) feedSrv := httptest.NewServer(mux) defer feedSrv.Close() feedURL = feedSrv.URL q := baseParams("admin", "adminpassword1") q.Set("url", feedSrv.URL+"/feed.xml") resp := getPath(t, srv.URL, "/rest/createPodcastChannel.view", q) x := decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("createPodcastChannel failed: %+v", x) } // createPodcastChannel refreshes asynchronously; poll briefly. var channelID string deadline := time.Now().Add(5 * time.Second) for time.Now().Before(deadline) { q2 := baseParams("admin", "adminpassword1") q2.Set("f", "json") resp = getPath(t, srv.URL, "/rest/getPodcasts.view", q2) j := decodeJSON(t, resp) channels, ok := j["podcasts"].(map[string]any)["channel"].([]any) if ok && len(channels) == 1 { ch := channels[0].(map[string]any) if ch["title"] == "Test Cast" { channelID = ch["id"].(string) break } } time.Sleep(50 * time.Millisecond) } if channelID == "" { t.Fatal("channel never finished refreshing") } q3 := baseParams("admin", "adminpassword1") q3.Set("id", channelID) q3.Set("f", "json") resp = getPath(t, srv.URL, "/rest/getPodcasts.view", q3) j := decodeJSON(t, resp) channels := j["podcasts"].(map[string]any)["channel"].([]any) ch := channels[0].(map[string]any) episodes, ok := ch["episode"].([]any) if !ok || len(episodes) != 1 { t.Fatalf("episodes = %v, want 1", ch["episode"]) } q4 := baseParams("admin", "adminpassword1") q4.Set("id", channelID) resp = getPath(t, srv.URL, "/rest/deletePodcastChannel.view", q4) x = decodeXML(t, resp) if x.Status != "ok" { t.Fatalf("deletePodcastChannel failed: %+v", x) } } func TestPodcastRequiresAdmin(t *testing.T) { s, srv := newTestRecorderServer(t) createTestUser(t, s, "alice", "password123", false) q := baseParams("alice", "password123") q.Set("url", "http://example.com/feed.xml") resp := getPath(t, srv.URL, "/rest/createPodcastChannel.view", q) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50, got %+v", x) } } func TestGetPodcastsRequiresPermission(t *testing.T) { s, db := newTestServer(t) u := createTestUser(t, s, "alice", "password123", false) srv := httptest.NewServer(s.Router()) defer srv.Close() perms := u.Permissions perms.Podcast = false if err := database.SetUserPermissions(db, u.ID, perms); err != nil { t.Fatal(err) } resp := getPath(t, srv.URL, "/rest/getPodcasts.view", baseParams("alice", "password123")) x := decodeXML(t, resp) if x.Status != "failed" || x.Error == nil || x.Error.Code != ErrUnauthorized { t.Fatalf("expected error 50 without podcast permission, got %+v", x) } } func TestGetNewestPodcastsEmpty(t *testing.T) { s, db := newTestServer(t) u := createTestUser(t, s, "alice", "password123", false) srv := httptest.NewServer(s.Router()) defer srv.Close() perms := u.Permissions perms.Podcast = true if err := database.SetUserPermissions(db, u.ID, perms); err != nil { t.Fatal(err) } q := baseParams("alice", "password123") q.Set("f", "json") resp := getPath(t, srv.URL, "/rest/getNewestPodcasts.view", q) j := decodeJSON(t, resp) if j["status"] != "ok" { t.Fatalf("status = %v", j["status"]) } }