app/api_test.go

v1.5.5
skunky-art/app/api_test.go history · blame · raw

147 lines · 4991 bytes

  1package app
  2
  3import (
  4	"net/http"
  5	"net/http/httptest"
  6	"net/url"
  7	"strings"
  8	"testing"
  9
 10	"github.com/krazywarez/devianter"
 11)
 12
 13// fullviewDeviation returns a deviation whose media assembles into a non-empty
 14// wixmp URL, i.e. one that sendMedia is meant to serve.
 15func fullviewDeviation() *devianter.Deviation {
 16	d := &devianter.Deviation{}
 17	d.Media.BaseUri = "https://images-wixmp-abc.wixmp.com/f/u/x.png"
 18	d.Media.Name = "x"
 19	d.Media.Types = append(d.Media.Types, struct {
 20		T    string
 21		H, W int
 22	}{T: "fullview", H: 1920, W: 1280})
 23	return d
 24}
 25
 26// TestSendMediaServesRealMedia is the regression test for the inverted guard: a
 27// deviation that has media must be sent, not dropped. In non-proxy mode that is
 28// a 302 to the wixmp URL; the pre-fix guard returned before writing anything.
 29func TestSendMediaServesRealMedia(t *testing.T) {
 30	proxy := CFG.Proxy
 31	CFG.Proxy = false
 32	defer func() { CFG.Proxy = proxy }()
 33
 34	w := httptest.NewRecorder()
 35	API{main: &skunkyart{Writer: w}}.sendMedia(fullviewDeviation())
 36
 37	if w.Code != 302 {
 38		t.Errorf("status is %d, want a 302 redirect to the media", w.Code)
 39	}
 40	if w.Header().Get("Location") == "" {
 41		t.Error("no Location header set — the media was dropped")
 42	}
 43}
 44
 45// TestSendMediaIgnoresEmptyMedia pins the other half of the bug: a deviation
 46// with no media must be a no-op. With proxy on, the pre-fix code fell through to
 47// mediaURL[21:] on an empty string and panicked.
 48func TestSendMediaIgnoresEmptyMedia(t *testing.T) {
 49	proxy := CFG.Proxy
 50	CFG.Proxy = true
 51	defer func() { CFG.Proxy = proxy }()
 52
 53	w := httptest.NewRecorder()
 54	API{main: &skunkyart{Writer: w}}.sendMedia(&devianter.Deviation{})
 55
 56	if w.Code != 200 {
 57		t.Errorf("status is %d, want nothing written (recorder default 200)", w.Code)
 58	}
 59	if loc := w.Header().Get("Location"); loc != "" {
 60		t.Errorf("Location %q set for a media-less deviation, want none", loc)
 61	}
 62}
 63
 64// withDailyDeviations scripts the daily deviations fetch with the given
 65// entries and counts the calls.
 66func withDailyDeviations(t *testing.T, devs ...devianter.Deviation) *int {
 67	t.Helper()
 68	orig := fetchDailyDeviations
 69	calls := 0
 70	fetchDailyDeviations = func(int) (devianter.DailyDeviations, devianter.Error) {
 71		calls++
 72		return devianter.DailyDeviations{Deviations: devs}, devianter.Error{}
 73	}
 74	t.Cleanup(func() { fetchDailyDeviations = orig })
 75	return &calls
 76}
 77
 78// TestRandomPicksFromTheDailyDeviations pins the new source: one fetch of the
 79// daily page, and the pick is served as media.
 80func TestRandomPicksFromTheDailyDeviations(t *testing.T) {
 81	proxy, nsfw := CFG.Proxy, CFG.Nsfw
 82	CFG.Proxy, CFG.Nsfw = false, true
 83	defer func() { CFG.Proxy, CFG.Nsfw = proxy, nsfw }()
 84	calls := withDailyDeviations(t, *fullviewDeviation())
 85
 86	w := httptest.NewRecorder()
 87	API{main: &skunkyart{Writer: w}}.Random()
 88
 89	if *calls != 1 {
 90		t.Errorf("daily deviations fetched %d times, want 1", *calls)
 91	}
 92	if w.Code != 302 || w.Header().Get("Location") == "" {
 93		t.Errorf("status %d, Location %q; want a 302 to the pick's media", w.Code, w.Header().Get("Location"))
 94	}
 95}
 96
 97// TestRandomHonoursNSFW pins that a pick is drawn only from what the instance
 98// may show: with nsfw off and only mature entries there is nothing to serve.
 99func TestRandomHonoursNSFW(t *testing.T) {
100	proxy, nsfw := CFG.Proxy, CFG.Nsfw
101	CFG.Proxy, CFG.Nsfw = false, false
102	defer func() { CFG.Proxy, CFG.Nsfw = proxy, nsfw }()
103	mature := *fullviewDeviation()
104	mature.NSFW = true
105	withDailyDeviations(t, mature)
106
107	w := httptest.NewRecorder()
108	API{main: &skunkyart{Writer: w}}.Random()
109
110	if w.Code != 404 || w.Header().Get("Location") != "" {
111		t.Errorf("status %d, Location %q; want 404 and no media", w.Code, w.Header().Get("Location"))
112	}
113}
114
115// TestSendMediaProxiesWithTheTokenInTheQuery is the regression test for
116// /api/random answering 401 with proxying on: the signing token was passed
117// inside the path, so wixmp never saw it as a parameter.
118func TestSendMediaProxiesWithTheTokenInTheQuery(t *testing.T) {
119	proxy, cache := CFG.Proxy, CFG.Cache.Enabled
120	CFG.Proxy, CFG.Cache.Enabled = true, false
121	defer func() { CFG.Proxy, CFG.Cache.Enabled = proxy, cache }()
122
123	var fetched string
124	orig := fetchMedia
125	fetchMedia = func(u string) Downloaded {
126		fetched = u
127		return Downloaded{Status: 200, Body: []byte("png"), Headers: http.Header{"Content-Type": {"image/png"}}}
128	}
129	defer func() { fetchMedia = orig }()
130
131	d := fullviewDeviation()
132	d.Media.Token = []string{"tok.en.sig"}
133
134	w := httptest.NewRecorder()
135	API{main: &skunkyart{Writer: w, Args: url.Values{}}}.sendMedia(d)
136
137	u, err := url.Parse(fetched)
138	if err != nil || u.Host != "images-wixmp-abc.wixmp.com" {
139		t.Fatalf("fetched %q, want a wixmp URL on the deviation's subdomain", fetched)
140	}
141	if strings.Contains(u.Path, "token") || u.Query().Get("token") == "" {
142		t.Errorf("token not passed as a query parameter: path %q query %q", u.Path, u.RawQuery)
143	}
144	if w.Code != 200 || w.Body.String() != "png" {
145		t.Errorf("response %d %q, want the proxied image", w.Code, w.Body.String())
146	}
147}