Parent directory

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}