suite_test.go
4237 bytes
1package ytrssil_test
2
3import (
4 "context"
5 "fmt"
6 "log/slog"
7 "net/http"
8 "os"
9 "os/exec"
10 "strings"
11 "time"
12
13 "github.com/gin-gonic/gin"
14 "github.com/jackc/pgx/v5"
15 "github.com/oklog/ulid/v2"
16 "github.com/stretchr/testify/suite"
17
18 "github.com/TheEdgeOfRage/ytrssil-api/config"
19 "github.com/TheEdgeOfRage/ytrssil-api/db"
20 "github.com/TheEdgeOfRage/ytrssil-api/feedparser"
21 "github.com/TheEdgeOfRage/ytrssil-api/handler"
22 "github.com/TheEdgeOfRage/ytrssil-api/httpserver/ytrssil"
23 mockFeedparser "github.com/TheEdgeOfRage/ytrssil-api/mocks/feedparser"
24 mockYouTube "github.com/TheEdgeOfRage/ytrssil-api/mocks/youtube"
25 "github.com/TheEdgeOfRage/ytrssil-api/models"
26)
27
28func init() {
29 time.Local = time.UTC
30}
31
32type EndpointsTestSuite struct {
33 suite.Suite
34 cfg config.Config
35 schema string
36 db db.DB
37 dbConn *pgx.Conn
38 parser *mockFeedparser.ParserMock
39 youtubeClient *mockYouTube.ClientMock
40 server *http.Server
41}
42
43func (s *EndpointsTestSuite) SetupSuite() {
44 var err error
45 l := slog.New(slog.NewTextHandler(os.Stderr, nil))
46 s.cfg = config.TestConfig()
47
48 s.schema = fmt.Sprintf("ytrssil_test_%s", ulid.Make().String())
49 s.dbConn, err = pgx.Connect(context.Background(), s.cfg.DBURI)
50 if err != nil {
51 panic(fmt.Sprintf("failed to connect to database: %v", err))
52 }
53 _, err = s.dbConn.Exec(context.Background(), fmt.Sprintf("CREATE SCHEMA %s", s.schema))
54 if err != nil {
55 panic(fmt.Sprintf("failed to create test schema: %v", err))
56 }
57
58 testDBURI := fmt.Sprintf("%s&search_path=%s", s.cfg.DBURI, s.schema)
59 cmd := exec.Command("./bin/migrate", "-database", testDBURI, "-path", "migrations", "up")
60 cmd.Dir = "../.."
61 output, err := cmd.CombinedOutput()
62 if err != nil {
63 panic(fmt.Sprintf("failed to run migrations: %v\nOutput: %s", err, string(output)))
64 }
65
66 s.db, err = db.NewPostgresDB(l, testDBURI)
67 if err != nil {
68 panic(fmt.Sprintf("failed to connect to test database: %v", err))
69 }
70
71 s.parser = &mockFeedparser.ParserMock{
72 ParseFunc: func(channelID string) (*feedparser.Channel, error) {
73 publishTime := time.Now().Add(-24 * time.Hour).Format(time.RFC3339)
74 return &feedparser.Channel{
75 ID: channelID,
76 Name: fmt.Sprintf("Test Channel %s", channelID),
77 Videos: []*feedparser.Video{
78 {
79 ID: fmt.Sprintf("yt:video:%s-video1", channelID),
80 Title: "Test Video 1",
81 Published: feedparser.Date(publishTime),
82 IsShort: false,
83 },
84 },
85 }, nil
86 },
87 }
88
89 s.youtubeClient = &mockYouTube.ClientMock{
90 GetVideoDurationsFunc: func(ctx context.Context, videos map[string]*models.Video) error {
91 for _, video := range videos {
92 video.DurationSeconds = 300
93 }
94 return nil
95 },
96 GetVideoMetadataFunc: func(ctx context.Context, videoID string) (*models.Video, error) {
97 return &models.Video{
98 ID: videoID,
99 Title: "Test Video",
100 PublishedTime: time.Now().Add(-24 * time.Hour),
101 DurationSeconds: 300,
102 IsShort: false,
103 ChannelID: "test-channel",
104 ChannelName: "Test Channel",
105 }, nil
106 },
107 GetChannelImageURLFunc: func(ctx context.Context, channelID string) (string, error) {
108 return fmt.Sprintf("https://example.com/%s.jpg", channelID), nil
109 },
110 ResolveChannelIDFunc: func(ctx context.Context, handle string) (string, error) {
111 return strings.TrimPrefix(handle, "@"), nil
112 },
113 }
114
115 h := handler.New(l, s.db, s.parser, s.youtubeClient, nil, s.cfg)
116
117 gin.SetMode(gin.TestMode)
118 router, err := ytrssil.SetupGinRouter(l, s.cfg, h)
119 if err != nil {
120 panic(fmt.Sprintf("failed to setup gin router: %v", err))
121 }
122
123 s.server = &http.Server{
124 Addr: fmt.Sprintf(":%v", s.cfg.Port),
125 Handler: router,
126 }
127}
128
129func (s *EndpointsTestSuite) TearDownSuite() {
130 defer s.dbConn.Close(context.Background())
131 _, err := s.dbConn.Exec(context.Background(), fmt.Sprintf("DROP SCHEMA %s CASCADE", s.schema))
132 if err != nil {
133 panic(fmt.Sprintf("failed to drop test schema: %v", err))
134 }
135}
136
137func (s *EndpointsTestSuite) SetupTest() {
138 query := fmt.Sprintf("TRUNCATE TABLE %s.videos, %s.channels CASCADE", s.schema, s.schema)
139 _, err := s.dbConn.Exec(context.Background(), query)
140 if err != nil {
141 panic(fmt.Sprintf("failed to truncate test tables: %v", err))
142 }
143}