subscription_test.go
⎇
Raw
1package server
2
3import (
4 "io"
5 "net/http"
6 "net/http/httptest"
7 "net/url"
8 "strings"
9 "testing"
10)
11
12// postForm posts an application/x-www-form-urlencoded body to the router.
13func postForm(router http.Handler, path string, form url.Values) *httptest.ResponseRecorder {
14 req := httptest.NewRequest("POST", path, strings.NewReader(form.Encode()))
15 req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
16 w := httptest.NewRecorder()
17 router.ServeHTTP(w, req)
18 return w
19}
20
21func TestSubscriptionsPageRenders(t *testing.T) {
22 srv, _, cleanup := setupTestServer(t)
23 defer cleanup()
24
25 req := httptest.NewRequest("GET", "/subscriptions", nil)
26 w := httptest.NewRecorder()
27 srv.Router().ServeHTTP(w, req)
28 if w.Code != http.StatusOK {
29 body, _ := io.ReadAll(w.Body)
30 t.Fatalf("expected 200, got %d: %s", w.Code, body)
31 }
32 if !strings.Contains(w.Body.String(), "Create Subscription") {
33 t.Error("subscriptions page missing create form")
34 }
35}
36
37func TestCreateSubscriptionLifecycle(t *testing.T) {
38 srv, _, cleanup := setupTestServer(t)
39 defer cleanup()
40 router := srv.Router()
41
42 // Valid create redirects (303) and persists.
43 w := postForm(router, "/subscriptions", url.Values{
44 "name": {"My Sub"},
45 "url": {"https://example.com/playlist"},
46 "output_dir": {"subscriptions/mine"},
47 "refresh_mode": {"overwrite"},
48 "schedule_kind": {"daily"},
49 })
50 if w.Code != http.StatusSeeOther {
51 t.Fatalf("create: expected 303, got %d", w.Code)
52 }
53
54 // It now appears on the listing with its details.
55 req := httptest.NewRequest("GET", "/subscriptions", nil)
56 lw := httptest.NewRecorder()
57 router.ServeHTTP(lw, req)
58 body := lw.Body.String()
59 for _, want := range []string{"My Sub", "subscriptions/mine", "Next run:"} {
60 if !strings.Contains(body, want) {
61 t.Errorf("listing missing %q", want)
62 }
63 }
64}
65
66// hasErrorFlash reports whether the response set an error flash cookie (the
67// Post/Redirect/Get feedback mechanism for a rejected form).
68func hasErrorFlash(w *httptest.ResponseRecorder) bool {
69 for _, c := range w.Result().Cookies() {
70 if c.Name == "flash" {
71 if v, err := url.QueryUnescape(c.Value); err == nil {
72 return strings.HasPrefix(v, "error|")
73 }
74 }
75 }
76 return false
77}
78
79func TestCreateSubscriptionValidation(t *testing.T) {
80 srv, _, cleanup := setupTestServer(t)
81 defer cleanup()
82 router := srv.Router()
83
84 // A rejected form redirects back (303) with an error flash rather than a raw
85 // 400, and must not persist anything.
86 cases := []struct {
87 name string
88 form url.Values
89 }{
90 {"empty output_dir", url.Values{
91 "url": {"https://example.com/x"},
92 "schedule_kind": {"daily"},
93 "output_dir": {""},
94 }},
95 {"bad cron", url.Values{
96 "url": {"https://example.com/x"},
97 "output_dir": {"foo"},
98 "schedule_kind": {"cron"},
99 "cron_expr": {"definitely not cron"},
100 }},
101 }
102 for _, tc := range cases {
103 w := postForm(router, "/subscriptions", tc.form)
104 if w.Code != http.StatusSeeOther {
105 t.Errorf("%s: expected 303 redirect, got %d", tc.name, w.Code)
106 }
107 if !hasErrorFlash(w) {
108 t.Errorf("%s: expected an error flash cookie", tc.name)
109 }
110 }
111
112 // None of the rejected forms should have created a subscription.
113 req := httptest.NewRequest("GET", "/subscriptions", nil)
114 lw := httptest.NewRecorder()
115 router.ServeHTTP(lw, req)
116 if !strings.Contains(lw.Body.String(), "No subscriptions yet") {
117 t.Error("rejected forms should not have persisted any subscription")
118 }
119}
120