clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/tinyagent
tinyrelay / tinyclient / social_podcasts_test.go
social_podcasts_test.go 3.9K
1package tinyclient23import (4 "context"5 "encoding/json"6 "net/http"7 "net/http/httptest"8 "strings"9 "testing"1011 "github.com/FelineStateMachine/tinyrelay/internal/event"12 "github.com/FelineStateMachine/tinyrelay/internal/podcasts"13 "github.com/FelineStateMachine/tinyrelay/internal/policy"14)1516type nativePodcastBackend struct{ fakeBackend }1718func (b *nativePodcastBackend) Query(ctx context.Context, method string, params []json.RawMessage, actor string) (any, error) {19 key := strings.Repeat("a", 64)20 show := podcasts.Show{ID: "metadata", Pubkey: key, Title: "Mountain Radio", Description: "Stories from the trail", Image: "https://example.test/show.jpg", Websites: []string{"https://example.test"}, Tags: [][]string{{"title", "Mountain Radio"}}}21 post := map[string]any{"id": strings.Repeat("b", 64), "kind": 54, "pubkey": key, "title": "First light", "created_at": 1789000000, "content": "## Field notes\n\nA **quiet** morning.", "tags": [][]string{{"title", "First light"}, {"description", "An early start"}, {"audio", "https://example.test/first.mp3", "audio/mpeg"}}, "podcast": show, "author_name": show.Title}22 switch method {23 case "browsesocial", "browsepodcasts":24 return map[string]any{"show": show, "items": []any{post}}, nil25 case "browsesocialthread":26 return map[string]any{"post": post}, nil27 case "browseprofile":28 return map[string]any{"profile": map[string]any{"name": "Personal profile"}}, nil29 default:30 return b.fakeBackend.Query(ctx, method, params, actor)31 }32}3334func TestNativePodcastPagesRenderAudioAndShowIdentity(t *testing.T) {35 key := strings.Repeat("a", 64)36 b := &nativePodcastBackend{fakeBackend{policy: policy.Defaults(key)}}37 a, err := New(b, Options{Actor: func(*http.Request) (string, error) { return key, nil }})38 if err != nil {39 t.Fatal(err)40 }41 for _, path := range []string{"/social?kind=podcasts&author=" + key, "/social/profile?kind=podcasts&author=" + key, "/social/" + strings.Repeat("b", 64)} {42 w := httptest.NewRecorder()43 a.ServeHTTP(w, httptest.NewRequest(http.MethodGet, path, nil))44 body := w.Body.String()45 for _, want := range []string{"Mountain Radio", "First light", `<audio controls`, `src="https://example.test/first.mp3"`, `data-post-body="podcast"`} {46 if w.Code != 200 || !strings.Contains(body, want) {47 t.Errorf("%s missing %q: %d", path, want, w.Code)48 }49 }50 if strings.Contains(path, "/social/"+strings.Repeat("b", 64)) && (!strings.Contains(body, "Field notes</h2>") || !strings.Contains(body, "<strong>quiet</strong>")) {51 t.Error("Podcast show notes are not Markdown")52 }53 if strings.Contains(path, "profile?") && strings.Contains(body, "Personal profile") {54 t.Error("Podcast profile used personal metadata instead of show")55 }56 }57}5859func TestPodcastComposerUsesNativeEpisodeAndShowModes(t *testing.T) {60 key := strings.Repeat("a", 64)61 a, err := New(&nativePodcastBackend{fakeBackend{policy: policy.Defaults(key)}}, Options{Actor: func(*http.Request) (string, error) { return key, nil }})62 if err != nil {63 t.Fatal(err)64 }65 w := httptest.NewRecorder()66 a.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/social?kind=podcasts&author="+key, nil))67 for _, want := range []string{`mode="podcast"`, `mode="podcast-show"`, `show-tags=`, `accept="audio/*"`, `Publish episode`, `Save podcast details`} {68 if !strings.Contains(w.Body.String(), want) {69 t.Errorf("missing %s", want)70 }71 }72}7374func TestSocialPodcastEventKeepsTheNativeKind(t *testing.T) {75 for _, kind := range []int{1, 30023, 54} {76 e := socialPodcastEvent(map[string]any{"kind": kind, "tags": [][]string{{"audio", "https://example.test/ep.mp3"}}})77 _, ok := podcasts.ParseEpisode(e)78 if ok != (kind == 54) {79 t.Errorf("kind %d parsed as podcast: %v", kind, ok)80 }81 }82 native := event.Event{Kind: 54, ID: "native", Tags: [][]string{{"audio", "https://example.test/ep.mp3"}}}83 if got := socialPodcastEvent(map[string]any{"event": native}); got.ID != "native" {84 t.Fatalf("nested event: %#v", got)85 }86}