videos_test.go
10932 bytes
1package ytrssil_test
2
3import (
4 "context"
5 "encoding/json"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "testing"
10 "time"
11
12 "github.com/stretchr/testify/suite"
13
14 "github.com/TheEdgeOfRage/ytrssil-api/models"
15)
16
17type VideosTestSuite struct {
18 EndpointsTestSuite
19}
20
21func TestVideosTestSuite(t *testing.T) {
22 suite.Run(t, new(VideosTestSuite))
23}
24
25func (s *VideosTestSuite) TestGetNewVideosJSON() {
26 ctx := context.Background()
27 channelID := "test-channel-789"
28
29 err := s.db.SubscribeToChannel(ctx, models.Channel{
30 ID: channelID,
31 Name: "Test Channel",
32 Subscribed: true,
33 })
34 s.Require().NoError(err)
35
36 err = s.db.AddVideo(ctx, models.Video{
37 ID: "video123",
38 Title: "Test Video",
39 PublishedTime: time.Now().Add(-1 * time.Hour),
40 DurationSeconds: 300,
41 IsShort: false,
42 }, channelID, false)
43 s.Require().NoError(err)
44
45 w := httptest.NewRecorder()
46 req, _ := http.NewRequest("GET", "/api/videos/new", nil)
47 req.Header.Set("Authorization", s.cfg.AuthToken)
48 s.server.Handler.ServeHTTP(w, req)
49
50 s.Equal(http.StatusOK, w.Code)
51
52 var response map[string][]models.Video
53 err = json.Unmarshal(w.Body.Bytes(), &response)
54 s.Require().NoError(err)
55 s.Require().Contains(response, "videos")
56 s.Require().Len(response["videos"], 1)
57 s.Equal("video123", response["videos"][0].ID)
58}
59
60func (s *VideosTestSuite) TestGetWatchedVideosJSON() {
61 ctx := context.Background()
62 channelID := "test-channel-101"
63
64 err := s.db.SubscribeToChannel(ctx, models.Channel{
65 ID: channelID,
66 Name: "Test Channel",
67 Subscribed: true,
68 })
69 s.Require().NoError(err)
70
71 err = s.db.AddVideo(ctx, models.Video{
72 ID: "video456",
73 Title: "Watched Video",
74 PublishedTime: time.Now().Add(-1 * time.Hour),
75 DurationSeconds: 300,
76 IsShort: false,
77 }, channelID, false)
78 s.Require().NoError(err)
79
80 watchTime := time.Now()
81 err = s.db.SetVideoWatchTime(ctx, "video456", &watchTime)
82 s.Require().NoError(err)
83
84 w := httptest.NewRecorder()
85 req, _ := http.NewRequest("GET", "/api/videos/watched", nil)
86 req.Header.Set("Authorization", s.cfg.AuthToken)
87 s.server.Handler.ServeHTTP(w, req)
88
89 s.Equal(http.StatusOK, w.Code)
90
91 var response map[string][]models.Video
92 err = json.Unmarshal(w.Body.Bytes(), &response)
93 s.Require().NoError(err)
94 s.Require().Contains(response, "videos")
95 s.Require().Len(response["videos"], 1)
96 s.Equal("video456", response["videos"][0].ID)
97}
98
99func (s *VideosTestSuite) TestMarkVideoAsWatchedJSON() {
100 ctx := context.Background()
101 channelID := "test-channel-202"
102
103 err := s.db.SubscribeToChannel(ctx, models.Channel{
104 ID: channelID,
105 Name: "Test Channel",
106 Subscribed: true,
107 })
108 s.Require().NoError(err)
109
110 err = s.db.AddVideo(ctx, models.Video{
111 ID: "video789",
112 Title: "Test Video",
113 PublishedTime: time.Now().Add(-1 * time.Hour),
114 DurationSeconds: 300,
115 IsShort: false,
116 }, channelID, false)
117 s.Require().NoError(err)
118
119 w := httptest.NewRecorder()
120 req, _ := http.NewRequest("POST", "/api/videos/video789/watch", nil)
121 req.Header.Set("Authorization", s.cfg.AuthToken)
122 s.server.Handler.ServeHTTP(w, req)
123
124 s.Equal(http.StatusOK, w.Code)
125
126 var response map[string]string
127 err = json.Unmarshal(w.Body.Bytes(), &response)
128 s.Require().NoError(err)
129 s.Require().Contains(response, "msg")
130 s.Equal("marked video as watched", response["msg"])
131}
132
133func (s *VideosTestSuite) TestMarkVideoAsUnwatchedJSON() {
134 ctx := context.Background()
135 channelID := "test-channel-303"
136
137 err := s.db.SubscribeToChannel(ctx, models.Channel{
138 ID: channelID,
139 Name: "Test Channel",
140 Subscribed: true,
141 })
142 s.Require().NoError(err)
143
144 err = s.db.AddVideo(ctx, models.Video{
145 ID: "video101",
146 Title: "Test Video",
147 PublishedTime: time.Now().Add(-1 * time.Hour),
148 DurationSeconds: 300,
149 IsShort: false,
150 }, channelID, false)
151 s.Require().NoError(err)
152
153 watchTime := time.Now()
154 err = s.db.SetVideoWatchTime(ctx, "video101", &watchTime)
155 s.Require().NoError(err)
156
157 w := httptest.NewRecorder()
158 req, _ := http.NewRequest("POST", "/api/videos/video101/unwatch", nil)
159 req.Header.Set("Authorization", s.cfg.AuthToken)
160 s.server.Handler.ServeHTTP(w, req)
161
162 s.Equal(http.StatusOK, w.Code)
163
164 var response map[string]string
165 err = json.Unmarshal(w.Body.Bytes(), &response)
166 s.Require().NoError(err)
167 s.Require().Contains(response, "msg")
168 s.Equal("cleared video from watch history", response["msg"])
169}
170
171func (s *VideosTestSuite) TestNewVideosPage() {
172 ctx := context.Background()
173 channelID := "test-channel-404"
174
175 err := s.db.SubscribeToChannel(ctx, models.Channel{
176 ID: channelID,
177 Name: "Test Channel",
178 Subscribed: true,
179 })
180 s.Require().NoError(err)
181
182 err = s.db.AddVideo(ctx, models.Video{
183 ID: "video202",
184 Title: "Test Video",
185 PublishedTime: time.Now().Add(-1 * time.Hour),
186 DurationSeconds: 300,
187 IsShort: false,
188 }, channelID, false)
189 s.Require().NoError(err)
190
191 w := httptest.NewRecorder()
192 req, _ := http.NewRequest("GET", "/", nil)
193 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
194 s.server.Handler.ServeHTTP(w, req)
195
196 s.Equal(http.StatusOK, w.Code)
197 s.Contains(w.Body.String(), "Test Video")
198}
199
200func (s *VideosTestSuite) TestWatchedVideosPage() {
201 ctx := context.Background()
202 channelID := "test-channel-505"
203
204 err := s.db.SubscribeToChannel(ctx, models.Channel{
205 ID: channelID,
206 Name: "Test Channel",
207 Subscribed: true,
208 })
209 s.Require().NoError(err)
210
211 err = s.db.AddVideo(ctx, models.Video{
212 ID: "video303",
213 Title: "Watched Video",
214 PublishedTime: time.Now().Add(-1 * time.Hour),
215 DurationSeconds: 300,
216 IsShort: false,
217 }, channelID, false)
218 s.Require().NoError(err)
219
220 watchTime := time.Now()
221 err = s.db.SetVideoWatchTime(ctx, "video303", &watchTime)
222 s.Require().NoError(err)
223
224 w := httptest.NewRecorder()
225 req, _ := http.NewRequest("GET", "/watched", nil)
226 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
227 s.server.Handler.ServeHTTP(w, req)
228
229 s.Equal(http.StatusOK, w.Code)
230 s.Contains(w.Body.String(), "Watched Video")
231}
232
233func (s *VideosTestSuite) TestAddVideoPage() {
234 w := httptest.NewRecorder()
235 req, _ := http.NewRequest("POST", "/videos", strings.NewReader(`{"videoID":"custom-video-123"}`))
236 req.Header.Set("Content-Type", "application/json")
237 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
238 s.server.Handler.ServeHTTP(w, req)
239
240 s.Equal(http.StatusOK, w.Code)
241 s.Contains(w.Header().Get("Content-Type"), "text/event-stream")
242}
243
244func (s *VideosTestSuite) TestMarkVideoAsWatchedPage() {
245 ctx := context.Background()
246 channelID := "test-channel-909"
247
248 err := s.db.SubscribeToChannel(ctx, models.Channel{
249 ID: channelID,
250 Name: "Test Channel",
251 Subscribed: true,
252 })
253 s.Require().NoError(err)
254
255 err = s.db.AddVideo(ctx, models.Video{
256 ID: "video404",
257 Title: "Test Video",
258 PublishedTime: time.Now().Add(-1 * time.Hour),
259 DurationSeconds: 300,
260 IsShort: false,
261 }, channelID, false)
262 s.Require().NoError(err)
263
264 w := httptest.NewRecorder()
265 req, _ := http.NewRequest("PATCH", "/videos/video404/watch", nil)
266 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
267 s.server.Handler.ServeHTTP(w, req)
268
269 s.Equal(http.StatusOK, w.Code)
270}
271
272func (s *VideosTestSuite) TestMarkVideoAsUnwatchedPage() {
273 ctx := context.Background()
274 channelID := "test-channel-1010"
275
276 err := s.db.SubscribeToChannel(ctx, models.Channel{
277 ID: channelID,
278 Name: "Test Channel",
279 Subscribed: true,
280 })
281 s.Require().NoError(err)
282
283 err = s.db.AddVideo(ctx, models.Video{
284 ID: "video505",
285 Title: "Test Video",
286 PublishedTime: time.Now().Add(-1 * time.Hour),
287 DurationSeconds: 300,
288 IsShort: false,
289 }, channelID, false)
290 s.Require().NoError(err)
291
292 watchTime := time.Now()
293 err = s.db.SetVideoWatchTime(ctx, "video505", &watchTime)
294 s.Require().NoError(err)
295
296 w := httptest.NewRecorder()
297 req, _ := http.NewRequest("PATCH", "/videos/video505/unwatch", nil)
298 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
299 s.server.Handler.ServeHTTP(w, req)
300
301 s.Equal(http.StatusOK, w.Code)
302}
303
304func (s *VideosTestSuite) TestSetVideoProgressPage() {
305 ctx := context.Background()
306 channelID := "test-channel-1111"
307
308 err := s.db.SubscribeToChannel(ctx, models.Channel{
309 ID: channelID,
310 Name: "Test Channel",
311 Subscribed: true,
312 })
313 s.Require().NoError(err)
314
315 err = s.db.AddVideo(ctx, models.Video{
316 ID: "video606",
317 Title: "Test Video",
318 PublishedTime: time.Now().Add(-1 * time.Hour),
319 DurationSeconds: 300,
320 IsShort: false,
321 }, channelID, false)
322 s.Require().NoError(err)
323
324 w := httptest.NewRecorder()
325 req, _ := http.NewRequest("PATCH", "/videos/video606/progress", strings.NewReader(`{"progress":"2:30"}`))
326 req.Header.Set("Content-Type", "application/json")
327 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
328 s.server.Handler.ServeHTTP(w, req)
329
330 s.Equal(http.StatusOK, w.Code)
331 s.Contains(w.Header().Get("Content-Type"), "text/event-stream")
332}
333
334func (s *VideosTestSuite) TestFetchVideosJSON() {
335 ctx := context.Background()
336
337 err := s.db.SubscribeToChannel(ctx, models.Channel{
338 ID: "channel-1212",
339 Name: "Test Channel",
340 Subscribed: true,
341 })
342 s.Require().NoError(err)
343
344 w := httptest.NewRecorder()
345 req, _ := http.NewRequest("POST", "/api/fetch", nil)
346 req.Header.Set("Authorization", s.cfg.AuthToken)
347 s.server.Handler.ServeHTTP(w, req)
348
349 s.Equal(http.StatusOK, w.Code)
350
351 var response map[string]string
352 err = json.Unmarshal(w.Body.Bytes(), &response)
353 s.Require().NoError(err)
354 s.Require().Contains(response, "msg")
355 s.Equal("videos fetched successfully", response["msg"])
356}
357
358func (s *VideosTestSuite) TestFetchVideosPage() {
359 w := httptest.NewRecorder()
360 req, _ := http.NewRequest("POST", "/fetch", nil)
361 req.AddCookie(&http.Cookie{Name: "token", Value: s.cfg.AuthToken})
362 s.server.Handler.ServeHTTP(w, req)
363
364 s.Equal(http.StatusOK, w.Code)
365 s.Contains(w.Header().Get("Content-Type"), "text/event-stream")
366}
367
368func (s *VideosTestSuite) TestVideosRequireAuth() {
369 testCases := []struct {
370 name string
371 method string
372 path string
373 is401 bool
374 }{
375 {"API new videos", "GET", "/api/videos/new", true},
376 {"API watched videos", "GET", "/api/videos/watched", true},
377 {"API mark watched", "POST", "/api/videos/test/watch", true},
378 {"API mark unwatched", "POST", "/api/videos/test/unwatch", true},
379 {"Page home", "GET", "/", false},
380 {"Page watched", "GET", "/watched", false},
381 }
382
383 for _, tc := range testCases {
384 s.Run(tc.name, func() {
385 w := httptest.NewRecorder()
386 req, _ := http.NewRequest(tc.method, tc.path, nil)
387 s.server.Handler.ServeHTTP(w, req)
388
389 if tc.is401 {
390 s.Equal(http.StatusUnauthorized, w.Code)
391 } else {
392 s.Equal(http.StatusFound, w.Code)
393 }
394 })
395 }
396}