subscription_run_test.go
⎇
Raw
1package server
2
3import (
4 "net/http"
5 "net/http/httptest"
6 "net/url"
7 "strings"
8 "testing"
9)
10
11// createSubscription posts the create form and returns the id of the new row.
12// The test server's worker pool is never started, so a queued run stays queued —
13// which is exactly the state the duplicate-run guard looks for.
14func createSubscription(t *testing.T, router http.Handler) string {
15 t.Helper()
16 w := postForm(router, "/subscriptions", url.Values{
17 "name": {"My Sub"},
18 "url": {"https://example.com/playlist"},
19 "output_dir": {"subs/mine"},
20 "refresh_mode": {"overwrite"},
21 "schedule_kind": {"daily"},
22 })
23 if w.Code != http.StatusSeeOther {
24 t.Fatalf("create subscription: expected 303, got %d", w.Code)
25 }
26
27 // The delete form on the listing carries the id.
28 req := httptest.NewRequest("GET", "/subscriptions", nil)
29 lw := httptest.NewRecorder()
30 router.ServeHTTP(lw, req)
31 body := lw.Body.String()
32 const marker = `action="/subscriptions/`
33 i := strings.Index(body, marker)
34 if i < 0 {
35 t.Fatal("no subscription id found on the listing")
36 }
37 rest := body[i+len(marker):]
38 id := rest[:strings.IndexAny(rest, `/"`)]
39 if id == "" {
40 t.Fatal("empty subscription id")
41 }
42 return id
43}
44
45// Running a subscription by hand queues one run and records it.
46func TestRunSubscriptionQueuesOnce(t *testing.T) {
47 srv, _, cleanup := setupTestServer(t)
48 defer cleanup()
49 router := srv.Router()
50 id := createSubscription(t, router)
51
52 w := postForm(router, "/subscriptions/"+id+"/run", nil)
53 if w.Code != http.StatusSeeOther {
54 t.Fatalf("run: expected 303, got %d", w.Code)
55 }
56 if hasErrorFlash(w) {
57 t.Error("first run reported an error")
58 }
59
60 // The queue now holds the run, and the subscription reports it.
61 req := httptest.NewRequest("GET", "/queue", nil)
62 qw := httptest.NewRecorder()
63 router.ServeHTTP(qw, req)
64 if !strings.Contains(qw.Body.String(), "https://example.com/playlist") {
65 t.Error("queue page does not show the subscription run")
66 }
67
68 req = httptest.NewRequest("GET", "/subscriptions", nil)
69 sw := httptest.NewRecorder()
70 router.ServeHTTP(sw, req)
71 if !strings.Contains(sw.Body.String(), "queued") {
72 t.Error("subscriptions page does not show the run status")
73 }
74}
75
76// A second "Run now" while the first is still queued must be refused. Both runs
77// share the subscription's output directory, so in overwrite mode they would
78// race: one deletes the item the other just imported.
79func TestRunSubscriptionRefusesConcurrentRun(t *testing.T) {
80 srv, _, cleanup := setupTestServer(t)
81 defer cleanup()
82 router := srv.Router()
83 id := createSubscription(t, router)
84
85 if w := postForm(router, "/subscriptions/"+id+"/run", nil); hasErrorFlash(w) {
86 t.Fatal("first run reported an error")
87 }
88
89 second := postForm(router, "/subscriptions/"+id+"/run", nil)
90 if second.Code != http.StatusSeeOther {
91 t.Fatalf("second run: expected 303, got %d", second.Code)
92 }
93 if !hasErrorFlash(second) {
94 t.Error("second run was accepted while the first was still queued")
95 }
96
97 // Still exactly one queued download for that URL.
98 req := httptest.NewRequest("GET", "/queue", nil)
99 qw := httptest.NewRecorder()
100 router.ServeHTTP(qw, req)
101 if n := strings.Count(qw.Body.String(), "https://example.com/playlist"); n != 1 {
102 t.Errorf("queue shows %d runs, want 1", n)
103 }
104}
105
106func TestRunUnknownSubscriptionIsNotFound(t *testing.T) {
107 srv, _, cleanup := setupTestServer(t)
108 defer cleanup()
109
110 w := postForm(srv.Router(), "/subscriptions/4242/run", nil)
111 if w.Code != http.StatusNotFound {
112 t.Errorf("expected 404 for an unknown subscription, got %d", w.Code)
113 }
114}
115