mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Add feed caching
This commit is contained in:
committed by
Maksym Pavlenko
parent
f288c22b53
commit
b7a0f10a5d
@ -8,6 +8,8 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/mxpv/podsync/pkg/cache"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
|
||||
@ -57,6 +59,13 @@ func main() {
|
||||
|
||||
patreon := support.NewPatreon(database)
|
||||
|
||||
// Cache
|
||||
|
||||
redisCache, err := cache.NewRedisCache(cfg.RedisURL)
|
||||
if err != nil {
|
||||
log.WithError(err).Fatal("failed to initialize Redis cache")
|
||||
}
|
||||
|
||||
// Builders
|
||||
|
||||
youtube, err := builders.NewYouTubeBuilder(cfg.YouTubeAPIKey)
|
||||
@ -81,7 +90,7 @@ func main() {
|
||||
|
||||
srv := http.Server{
|
||||
Addr: fmt.Sprintf(":%d", 5001),
|
||||
Handler: handler.New(feed, patreon, cfg),
|
||||
Handler: handler.New(feed, patreon, redisCache, cfg),
|
||||
}
|
||||
|
||||
go func() {
|
||||
@ -99,6 +108,10 @@ func main() {
|
||||
log.WithError(err).Error("server shutdown failed")
|
||||
}
|
||||
|
||||
if err := redisCache.Close(); err != nil {
|
||||
log.WithError(err).Error("failed to close redis cache")
|
||||
}
|
||||
|
||||
if err := database.Close(); err != nil {
|
||||
log.WithError(err).Error("failed to close database")
|
||||
}
|
||||
|
7
go.mod
7
go.mod
@ -15,7 +15,8 @@ require (
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
|
||||
github.com/gin-gonic/gin v0.0.0-20170702092826-d459835d2b07
|
||||
github.com/go-pg/pg v6.14.2+incompatible
|
||||
github.com/golang/mock v1.1.1
|
||||
github.com/go-redis/redis v6.15.2+incompatible
|
||||
github.com/golang/mock v1.2.0
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
|
||||
github.com/gorilla/sessions v1.1.1 // indirect
|
||||
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce // indirect
|
||||
@ -42,9 +43,11 @@ require (
|
||||
github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf // indirect
|
||||
github.com/ugorji/go v1.1.1 // indirect
|
||||
github.com/ventu-io/go-shortid v0.0.0-20171029131806-771a37caa5cf
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a
|
||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
|
||||
golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1 // indirect
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5 // indirect
|
||||
google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56
|
||||
google.golang.org/appengine v1.1.0 // indirect
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
|
15
go.sum
15
go.sum
@ -30,8 +30,12 @@ github.com/gin-gonic/gin v0.0.0-20170702092826-d459835d2b07 h1:cZPJWzd2oNeoS0oJM
|
||||
github.com/gin-gonic/gin v0.0.0-20170702092826-d459835d2b07/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/go-pg/pg v6.14.2+incompatible h1:FrOgsHDUhC3V3wkBGAIN5LVj4nJczFPyy1YNFnetfIQ=
|
||||
github.com/go-pg/pg v6.14.2+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA=
|
||||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
|
||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
|
||||
@ -62,8 +66,6 @@ github.com/memcachier/mc v2.0.1+incompatible h1:s8EDz0xrJLP8goitwZOoq1vA/sm0fPS4
|
||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699 h1:KXZJFdun9knAVAR8tg/aHJEr5DgtcbqyvzacK+CDCaI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180715050151-f15292f7a699/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mxpv/patreon-go v0.0.0-20171031001022-1d2f253ac700 h1:39PjdU78pNilVLU9tjWVDGt/rziIKKkKHuzWbH1kBbw=
|
||||
github.com/mxpv/patreon-go v0.0.0-20171031001022-1d2f253ac700/go.mod h1:ksYjm2GAbGlgIP7jO9Q5/AdyE4MwwEbgQ+lFMx3hyiM=
|
||||
github.com/mxpv/patreon-go v0.0.0-20180807002359-67dbab1ad14c h1:glRDvmNgmckYjQHMQ17XFlci6RehtmGmRQV+Cq6FusI=
|
||||
github.com/mxpv/patreon-go v0.0.0-20180807002359-67dbab1ad14c/go.mod h1:ksYjm2GAbGlgIP7jO9Q5/AdyE4MwwEbgQ+lFMx3hyiM=
|
||||
github.com/mxpv/podcast v0.0.0-20170823220358-fe328ad87d18 h1:YYsu49Y42JA+CSs9+z2MGBdGxb5jklpagLp5QPJ6BwQ=
|
||||
@ -104,8 +106,12 @@ github.com/ventu-io/go-shortid v0.0.0-20171029131806-771a37caa5cf h1:cgAKVljim9R
|
||||
github.com/ventu-io/go-shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:6rZqAOk/eYX5FJyjQJ6Z3RBSN389IXX2ijwW4FcggaM=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd h1:QQhib242ErYDSMitlBm8V7wYCm/1a25hV8qMadIKLPA=
|
||||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -114,8 +120,13 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1 h1:FQNj2xvjQ1lgFyzbSybGZr792Y8Dy95D7uuqnZAzNaA=
|
||||
golang.org/x/sys v0.0.0-20190311152110-c8c8c57fd1e1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5 h1:ZcPpqKMdoZeNQ/4GHlyY4COf8n8SmpPv6mcqF1+VPSM=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56 h1:iDRbkenn0VZEo05mHiCtN6/EfbZj7x1Rg+tPjB5HiQc=
|
||||
google.golang.org/api v0.0.0-20180718221112-efcb5f25ac56/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
|
46
pkg/cache/redis.go
vendored
Normal file
46
pkg/cache/redis.go
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("not found")
|
||||
|
||||
// RedisCache implements caching layer for feeds using Redis
|
||||
type RedisCache struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func NewRedisCache(redisURL string) (RedisCache, error) {
|
||||
opts, err := redis.ParseURL(redisURL)
|
||||
if err != nil {
|
||||
return RedisCache{}, err
|
||||
}
|
||||
|
||||
client := redis.NewClient(opts)
|
||||
if err := client.Ping().Err(); err != nil {
|
||||
return RedisCache{}, err
|
||||
}
|
||||
|
||||
return RedisCache{client: client}, nil
|
||||
}
|
||||
|
||||
func (c RedisCache) Set(key, value string, ttl time.Duration) error {
|
||||
return c.client.Set(key, value, ttl).Err()
|
||||
}
|
||||
|
||||
func (c RedisCache) Get(key string) (string, error) {
|
||||
val, err := c.client.Get(key).Result()
|
||||
if err == redis.Nil {
|
||||
return "", ErrNotFound
|
||||
} else {
|
||||
return val, err
|
||||
}
|
||||
}
|
||||
|
||||
func (c RedisCache) Close() error {
|
||||
return c.client.Close()
|
||||
}
|
67
pkg/cache/redis_test.go
vendored
Normal file
67
pkg/cache/redis_test.go
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRedisCache_Get(t *testing.T) {
|
||||
s := createRedisClient(t)
|
||||
defer s.Close()
|
||||
|
||||
err := s.Set("1", "value", 1*time.Minute)
|
||||
assert.NoError(t, err)
|
||||
|
||||
val, err := s.Get("1")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value", val)
|
||||
}
|
||||
|
||||
func TestRedisCache_GetInvalidKey(t *testing.T) {
|
||||
s := createRedisClient(t)
|
||||
defer s.Close()
|
||||
|
||||
val, err := s.Get("1")
|
||||
assert.Equal(t, ErrNotFound, err)
|
||||
assert.Empty(t, val)
|
||||
}
|
||||
|
||||
func TestNewRedisCache_TTL(t *testing.T) {
|
||||
s := createRedisClient(t)
|
||||
defer s.Close()
|
||||
|
||||
err := s.Set("1", "value", 500*time.Millisecond)
|
||||
assert.NoError(t, err)
|
||||
|
||||
val, err := s.Get("1")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value", val)
|
||||
|
||||
time.Sleep(501 * time.Millisecond)
|
||||
|
||||
_, err = s.Get("1")
|
||||
assert.Equal(t, ErrNotFound, err)
|
||||
}
|
||||
|
||||
// docker run -it --rm -p 6379:6379 redis
|
||||
func createRedisClient(t *testing.T) RedisCache {
|
||||
if testing.Short() {
|
||||
t.Skip("run redis tests manually")
|
||||
}
|
||||
|
||||
client, err := NewRedisCache("redis://localhost")
|
||||
require.NoError(t, err)
|
||||
|
||||
keys, err := client.client.Keys("*").Result()
|
||||
assert.NoError(t, err)
|
||||
|
||||
if len(keys) > 0 {
|
||||
err = client.client.Del(keys...).Err()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
@ -21,6 +21,7 @@ type AppConfig struct {
|
||||
AWSAccessSecret string `yaml:"awsAccessSecret"`
|
||||
DynamoFeedsTableName string `yaml:"dynamoFeedsTableName"`
|
||||
DynamoPledgesTableName string `yaml:"dynamoPledgesTableName"`
|
||||
RedisURL string `yaml:"redisUrl"`
|
||||
}
|
||||
|
||||
func ReadConfiguration() (*AppConfig, error) {
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -36,14 +37,20 @@ type patreonService interface {
|
||||
GetFeatureLevelFromAmount(amount int) int
|
||||
}
|
||||
|
||||
type cacheService interface {
|
||||
Set(key, value string, ttl time.Duration) error
|
||||
Get(key string) (string, error)
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
feed feedService
|
||||
cfg *config.AppConfig
|
||||
oauth2 oauth2.Config
|
||||
patreon patreonService
|
||||
cache cacheService
|
||||
}
|
||||
|
||||
func New(feed feedService, support patreonService, cfg *config.AppConfig) http.Handler {
|
||||
func New(feed feedService, support patreonService, cache cacheService, cfg *config.AppConfig) http.Handler {
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
@ -53,6 +60,7 @@ func New(feed feedService, support patreonService, cfg *config.AppConfig) http.H
|
||||
h := handler{
|
||||
feed: feed,
|
||||
patreon: support,
|
||||
cache: cache,
|
||||
cfg: cfg,
|
||||
}
|
||||
|
||||
@ -214,6 +222,14 @@ func (h handler) getFeed(c *gin.Context) {
|
||||
hashID = strings.TrimSuffix(hashID, ".xml")
|
||||
}
|
||||
|
||||
const feedContentType = "application/rss+xml; charset=UTF-8"
|
||||
|
||||
cached, err := h.cache.Get(hashID)
|
||||
if err == nil {
|
||||
c.Data(http.StatusOK, feedContentType, []byte(cached))
|
||||
return
|
||||
}
|
||||
|
||||
podcast, err := h.feed.BuildFeed(hashID)
|
||||
if err != nil {
|
||||
code := http.StatusInternalServerError
|
||||
@ -232,7 +248,13 @@ func (h handler) getFeed(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data(http.StatusOK, "application/rss+xml; charset=UTF-8", podcast.Bytes())
|
||||
data := podcast.String()
|
||||
|
||||
if err := h.cache.Set(hashID, data, 10*time.Minute); err != nil {
|
||||
log.WithError(err).Warnf("failed to cache feed %q", hashID)
|
||||
}
|
||||
|
||||
c.Data(http.StatusOK, feedContentType, []byte(data))
|
||||
}
|
||||
|
||||
func (h handler) metadata(c *gin.Context) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
podcast "github.com/mxpv/podcast"
|
||||
api "github.com/mxpv/podsync/pkg/api"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// MockfeedService is a mock of feedService interface
|
||||
@ -37,6 +38,7 @@ func (m *MockfeedService) EXPECT() *MockfeedServiceMockRecorder {
|
||||
|
||||
// CreateFeed mocks base method
|
||||
func (m *MockfeedService) CreateFeed(req *api.CreateFeedRequest, identity *api.Identity) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateFeed", req, identity)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
@ -45,11 +47,13 @@ func (m *MockfeedService) CreateFeed(req *api.CreateFeedRequest, identity *api.I
|
||||
|
||||
// CreateFeed indicates an expected call of CreateFeed
|
||||
func (mr *MockfeedServiceMockRecorder) CreateFeed(req, identity interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateFeed", reflect.TypeOf((*MockfeedService)(nil).CreateFeed), req, identity)
|
||||
}
|
||||
|
||||
// BuildFeed mocks base method
|
||||
func (m *MockfeedService) BuildFeed(hashID string) (*podcast.Podcast, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BuildFeed", hashID)
|
||||
ret0, _ := ret[0].(*podcast.Podcast)
|
||||
ret1, _ := ret[1].(error)
|
||||
@ -58,24 +62,28 @@ func (m *MockfeedService) BuildFeed(hashID string) (*podcast.Podcast, error) {
|
||||
|
||||
// BuildFeed indicates an expected call of BuildFeed
|
||||
func (mr *MockfeedServiceMockRecorder) BuildFeed(hashID interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildFeed", reflect.TypeOf((*MockfeedService)(nil).BuildFeed), hashID)
|
||||
}
|
||||
|
||||
// GetMetadata mocks base method
|
||||
func (m *MockfeedService) GetMetadata(hashId string) (*api.Metadata, error) {
|
||||
ret := m.ctrl.Call(m, "GetMetadata", hashId)
|
||||
func (m *MockfeedService) GetMetadata(hashID string) (*api.Metadata, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetMetadata", hashID)
|
||||
ret0, _ := ret[0].(*api.Metadata)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetMetadata indicates an expected call of GetMetadata
|
||||
func (mr *MockfeedServiceMockRecorder) GetMetadata(hashId interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadata", reflect.TypeOf((*MockfeedService)(nil).GetMetadata), hashId)
|
||||
func (mr *MockfeedServiceMockRecorder) GetMetadata(hashID interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMetadata", reflect.TypeOf((*MockfeedService)(nil).GetMetadata), hashID)
|
||||
}
|
||||
|
||||
// Downgrade mocks base method
|
||||
func (m *MockfeedService) Downgrade(patronID string, featureLevel int) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Downgrade", patronID, featureLevel)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
@ -83,6 +91,7 @@ func (m *MockfeedService) Downgrade(patronID string, featureLevel int) error {
|
||||
|
||||
// Downgrade indicates an expected call of Downgrade
|
||||
func (mr *MockfeedServiceMockRecorder) Downgrade(patronID, featureLevel interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Downgrade", reflect.TypeOf((*MockfeedService)(nil).Downgrade), patronID, featureLevel)
|
||||
}
|
||||
|
||||
@ -111,6 +120,7 @@ func (m *MockpatreonService) EXPECT() *MockpatreonServiceMockRecorder {
|
||||
|
||||
// Hook mocks base method
|
||||
func (m *MockpatreonService) Hook(pledge *patreon_go.Pledge, event string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Hook", pledge, event)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
@ -118,11 +128,13 @@ func (m *MockpatreonService) Hook(pledge *patreon_go.Pledge, event string) error
|
||||
|
||||
// Hook indicates an expected call of Hook
|
||||
func (mr *MockpatreonServiceMockRecorder) Hook(pledge, event interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Hook", reflect.TypeOf((*MockpatreonService)(nil).Hook), pledge, event)
|
||||
}
|
||||
|
||||
// GetFeatureLevelByID mocks base method
|
||||
func (m *MockpatreonService) GetFeatureLevelByID(patronID string) int {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFeatureLevelByID", patronID)
|
||||
ret0, _ := ret[0].(int)
|
||||
return ret0
|
||||
@ -130,11 +142,13 @@ func (m *MockpatreonService) GetFeatureLevelByID(patronID string) int {
|
||||
|
||||
// GetFeatureLevelByID indicates an expected call of GetFeatureLevelByID
|
||||
func (mr *MockpatreonServiceMockRecorder) GetFeatureLevelByID(patronID interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeatureLevelByID", reflect.TypeOf((*MockpatreonService)(nil).GetFeatureLevelByID), patronID)
|
||||
}
|
||||
|
||||
// GetFeatureLevelFromAmount mocks base method
|
||||
func (m *MockpatreonService) GetFeatureLevelFromAmount(amount int) int {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetFeatureLevelFromAmount", amount)
|
||||
ret0, _ := ret[0].(int)
|
||||
return ret0
|
||||
@ -142,5 +156,58 @@ func (m *MockpatreonService) GetFeatureLevelFromAmount(amount int) int {
|
||||
|
||||
// GetFeatureLevelFromAmount indicates an expected call of GetFeatureLevelFromAmount
|
||||
func (mr *MockpatreonServiceMockRecorder) GetFeatureLevelFromAmount(amount interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeatureLevelFromAmount", reflect.TypeOf((*MockpatreonService)(nil).GetFeatureLevelFromAmount), amount)
|
||||
}
|
||||
|
||||
// MockcacheService is a mock of cacheService interface
|
||||
type MockcacheService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockcacheServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockcacheServiceMockRecorder is the mock recorder for MockcacheService
|
||||
type MockcacheServiceMockRecorder struct {
|
||||
mock *MockcacheService
|
||||
}
|
||||
|
||||
// NewMockcacheService creates a new mock instance
|
||||
func NewMockcacheService(ctrl *gomock.Controller) *MockcacheService {
|
||||
mock := &MockcacheService{ctrl: ctrl}
|
||||
mock.recorder = &MockcacheServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockcacheService) EXPECT() *MockcacheServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Set mocks base method
|
||||
func (m *MockcacheService) Set(key, value string, ttl time.Duration) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Set", key, value, ttl)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Set indicates an expected call of Set
|
||||
func (mr *MockcacheServiceMockRecorder) Set(key, value, ttl interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockcacheService)(nil).Set), key, value, ttl)
|
||||
}
|
||||
|
||||
// Get mocks base method
|
||||
func (m *MockcacheService) Get(key string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Get", key)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Get indicates an expected call of Get
|
||||
func (mr *MockcacheServiceMockRecorder) Get(key interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockcacheService)(nil).Get), key)
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
itunes "github.com/mxpv/podcast"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -36,7 +38,7 @@ func TestCreateFeed(t *testing.T) {
|
||||
patreon := NewMockpatreonService(ctrl)
|
||||
patreon.EXPECT().GetFeatureLevelByID(gomock.Any()).Return(api.DefaultFeatures)
|
||||
|
||||
srv := httptest.NewServer(New(feed, patreon, cfg))
|
||||
srv := httptest.NewServer(New(feed, patreon, nil, cfg))
|
||||
defer srv.Close()
|
||||
|
||||
query := `{"url": "https://youtube.com/channel/123", "page_size": 55, "quality": "low", "format": "audio"}`
|
||||
@ -51,7 +53,7 @@ func TestCreateInvalidFeed(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
srv := httptest.NewServer(New(NewMockfeedService(ctrl), nil, cfg))
|
||||
srv := httptest.NewServer(New(NewMockfeedService(ctrl), nil, nil, cfg))
|
||||
defer srv.Close()
|
||||
|
||||
query := `{}`
|
||||
@ -104,7 +106,11 @@ func TestGetFeed(t *testing.T) {
|
||||
feed := NewMockfeedService(ctrl)
|
||||
feed.EXPECT().BuildFeed("123").Return(&podcast, nil)
|
||||
|
||||
srv := httptest.NewServer(New(feed, nil, cfg))
|
||||
cache := NewMockcacheService(ctrl)
|
||||
cache.EXPECT().Get("123").Times(1).Return("", errors.New("not found"))
|
||||
cache.EXPECT().Set("123", podcast.String(), gomock.Any()).Return(nil).Times(1)
|
||||
|
||||
srv := httptest.NewServer(New(feed, nil, cache, cfg))
|
||||
defer srv.Close()
|
||||
|
||||
resp, err := http.Get(srv.URL + "/123")
|
||||
@ -119,7 +125,7 @@ func TestGetMetadata(t *testing.T) {
|
||||
feed := NewMockfeedService(ctrl)
|
||||
feed.EXPECT().GetMetadata("123").Times(1).Return(&api.Metadata{}, nil)
|
||||
|
||||
srv := httptest.NewServer(New(feed, nil, cfg))
|
||||
srv := httptest.NewServer(New(feed, nil, nil, cfg))
|
||||
defer srv.Close()
|
||||
|
||||
resp, err := http.Get(srv.URL + "/api/metadata/123")
|
||||
|
Reference in New Issue
Block a user