From 5053f6ef3265f9476a62895f9254ac37ca1c12c0 Mon Sep 17 00:00:00 2001 From: Jesse Michael Date: Tue, 13 Dec 2022 13:50:55 -0700 Subject: [PATCH] fix: update fetcher interface --- client/ts/.openapi-generator/VERSION | 2 +- go.mod | 2 +- go.sum | 16 ------- internal/server/feed.go | 21 ++------- internal/server/feed_test.go | 64 ++++++++++++++------------- internal/server/server.go | 19 +++++--- internal/server/servicer.go | 6 --- internal/server/servicer_test.go | 65 ---------------------------- internal/service/fetcher.go | 26 ++++++++--- 9 files changed, 69 insertions(+), 152 deletions(-) delete mode 100644 internal/server/servicer.go delete mode 100644 internal/server/servicer_test.go diff --git a/client/ts/.openapi-generator/VERSION b/client/ts/.openapi-generator/VERSION index 89648de..d6b4ec4 100644 --- a/client/ts/.openapi-generator/VERSION +++ b/client/ts/.openapi-generator/VERSION @@ -1 +1 @@ -6.0.1-SNAPSHOT \ No newline at end of file +6.3.0-SNAPSHOT \ No newline at end of file diff --git a/go.mod b/go.mod index 999a43c..ac1b8f2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.19 require ( github.com/Davincible/goinsta v0.0.0-20210922223555-172c4b597032 github.com/dghubble/go-twitter v0.0.0-20190719072343-39e5462e111f - github.com/golang/mock v1.6.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 github.com/jesse0michael/go-request v1.1.0 @@ -32,6 +31,7 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect golang.org/x/text v0.3.3 // indirect google.golang.org/appengine v1.4.0 // indirect diff --git a/go.sum b/go.sum index 09f0cf2..98f3633 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,6 @@ github.com/dghubble/sling v1.3.0 h1:pZHjCJq4zJvc6qVQ5wN1jo5oNZlNE0+8T/h0XeXBUKU= github.com/dghubble/sling v1.3.0/go.mod h1:XXShWaBWKzNLhu2OxikSNFrlsvowtz4kyRuXUG7oQKY= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= 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 v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= @@ -52,27 +50,18 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -83,11 +72,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/server/feed.go b/internal/server/feed.go index 9e92989..23adb0a 100644 --- a/internal/server/feed.go +++ b/internal/server/feed.go @@ -4,35 +4,20 @@ import ( "encoding/json" "net/http" + "github.com/jesse0michael/fetcher/internal/service" "github.com/jesse0michael/go-request" ) -type FeedRequest struct { - TwitterID int64 `query:"twitterID"` - InstagramID int64 `query:"instagramID"` - BloggerID string `query:"bloggerID"` - SoundcloudID string `query:"soundcloudID"` - SwarmID string `query:"swarmID"` - DeviantartID string `query:"deviantartID"` -} - func (s *Server) feed() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var req FeedRequest + var req service.FetcherRequest if err := request.Decode(r, &req); err != nil { s.log.WithError(err).Error("failed to decode request body") writeError(w, http.StatusBadRequest, err) return } - feed, err := s.servicer.GetFeed( - req.TwitterID, - req.InstagramID, - req.BloggerID, - req.SoundcloudID, - req.SwarmID, - req.DeviantartID, - ) + feed, err := s.fetcher.Feeds(req) if err != nil { s.log.WithError(err).Error("failed to get feed") writeError(w, http.StatusInternalServerError, err) diff --git a/internal/server/feed_test.go b/internal/server/feed_test.go index 20652f9..bff02e2 100644 --- a/internal/server/feed_test.go +++ b/internal/server/feed_test.go @@ -2,68 +2,71 @@ package server import ( "errors" + "fmt" "net/http" "net/http/httptest" "testing" - gomock "github.com/golang/mock/gomock" "github.com/gorilla/mux" + "github.com/jesse0michael/fetcher/internal/service" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) +type MockFetcher struct { + expected service.FetcherRequest + items []service.FeedItem + err error +} + +func (m *MockFetcher) Feeds(req service.FetcherRequest) (*service.FeedItems, error) { + if req != m.expected { + return nil, fmt.Errorf("unexpected req") + } + return &service.FeedItems{Items: m.items}, m.err +} + func TestServer_feed(t *testing.T) { tests := []struct { - name string - req *http.Request - stubServicer func(*MockFeedServicer) - wantCode int - wantBody string + name string + req *http.Request + fetcher Fetcher + wantCode int + wantBody string }{ { - name: "empty feed retrieval", - req: httptest.NewRequest("GET", "/feed", nil), - stubServicer: func(m *MockFeedServicer) { - e := map[string]string{"test": "successful"} - m.EXPECT().GetFeed(int64(0), int64(0), "", "", "", "").Return(&e, nil) - }, + name: "empty feed retrieval", + req: httptest.NewRequest("GET", "/feed", nil), + fetcher: &MockFetcher{items: []service.FeedItem{}}, wantCode: 200, - wantBody: `{"test":"successful"}`, + wantBody: `{"items":[]}`, }, { name: "successful feed retrieval", req: httptest.NewRequest("GET", "/feed?twitterID=60887026&instagramID=50957893&bloggerID=2628647666607369284&soundcloudID=20560365&swarmID=jesse&deviantartID=mini-michael/33242408", nil), - stubServicer: func(m *MockFeedServicer) { - e := map[string]string{"test": "successful"} - m.EXPECT().GetFeed(int64(60887026), int64(50957893), "2628647666607369284", "20560365", "jesse", "mini-michael/33242408").Return(&e, nil) + fetcher: &MockFetcher{ + expected: service.FetcherRequest{TwitterID: "60887026", InstagramID: "50957893", BloggerID: "2628647666607369284", SoundcloudID: "20560365", SwarmID: "jesse", DeviantartID: "mini-michael/33242408"}, + items: []service.FeedItem{ + {Id: "test", Source: "testing"}, + }, }, wantCode: 200, - wantBody: `{"test":"successful"}`, + wantBody: `{"items":[{"id":"test","source":"testing","ts":0}]}`, }, { name: "failed feed retrieval", req: httptest.NewRequest("GET", "/feed", nil), - stubServicer: func(m *MockFeedServicer) { - m.EXPECT().GetFeed(int64(0), int64(0), "", "", "", "").Return(nil, errors.New("test-error")) + fetcher: &MockFetcher{ + err: errors.New("test-error"), }, wantCode: 500, wantBody: `{"error":"test-error"}`, }, - { - name: "failed request decode", - req: httptest.NewRequest("GET", "/feed?twitterID=abc", nil), - stubServicer: func(m *MockFeedServicer) {}, - wantCode: 400, - wantBody: `{"error":"strconv.ParseInt: parsing \"abc\": invalid syntax"}`, - }, } for i := range tests { tt := tests[i] t.Run(tt.name, func(t *testing.T) { - ctrl := gomock.NewController(t) - MockServicer := NewMockFeedServicer(ctrl) - tt.stubServicer(MockServicer) - s := New(Config{}, logrus.NewEntry(logrus.New()), MockServicer) + s := New(Config{}, logrus.NewEntry(logrus.New()), tt.fetcher) resp := httptest.NewRecorder() router := mux.NewRouter() @@ -77,7 +80,6 @@ func TestServer_feed(t *testing.T) { } else { assert.Empty(t, resp.Body.String()) } - ctrl.Finish() result.Body.Close() }) } diff --git a/internal/server/server.go b/internal/server/server.go index 1bd07ae..331b799 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -6,21 +6,26 @@ import ( "github.com/gorilla/handlers" "github.com/gorilla/mux" + "github.com/jesse0michael/fetcher/internal/service" "github.com/sirupsen/logrus" ) +type Fetcher interface { + Feeds(service.FetcherRequest) (*service.FeedItems, error) +} + type Config struct { Port int `envconfig:"PORT" default:"8080"` } type Server struct { *http.Server - router *mux.Router - log *logrus.Entry - servicer FeedServicer + router *mux.Router + log *logrus.Entry + fetcher Fetcher } -func New(cfg Config, log *logrus.Entry, servicer FeedServicer) *Server { +func New(cfg Config, log *logrus.Entry, fetcher Fetcher) *Server { router := mux.NewRouter() router.StrictSlash(true) router.NotFoundHandler = http.HandlerFunc(notFound) @@ -32,9 +37,9 @@ func New(cfg Config, log *logrus.Entry, servicer FeedServicer) *Server { Handler: router, Addr: fmt.Sprintf(":%d", cfg.Port), }, - router: router, - log: log, - servicer: servicer, + router: router, + log: log, + fetcher: fetcher, } server.route() diff --git a/internal/server/servicer.go b/internal/server/servicer.go deleted file mode 100644 index 53c858b..0000000 --- a/internal/server/servicer.go +++ /dev/null @@ -1,6 +0,0 @@ -//go:generate mockgen -source=servicer.go -destination=servicer_test.go -package=server -package server - -type FeedServicer interface { - GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, swarmID, deviantartID string) (interface{}, error) -} diff --git a/internal/server/servicer_test.go b/internal/server/servicer_test.go deleted file mode 100644 index b5daee2..0000000 --- a/internal/server/servicer_test.go +++ /dev/null @@ -1,65 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: servicer.go - -// Package server is a generated GoMock package. -package server - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockFeedServicer is a mock of FeedServicer interface. -type MockFeedServicer struct { - ctrl *gomock.Controller - recorder *MockFeedServicerMockRecorder -} - -// MockFeedServicerMockRecorder is the mock recorder for MockFeedServicer. -type MockFeedServicerMockRecorder struct { - mock *MockFeedServicer -} - -// NewMockFeedServicer creates a new mock instance. -func NewMockFeedServicer(ctrl *gomock.Controller) *MockFeedServicer { - mock := &MockFeedServicer{ctrl: ctrl} - mock.recorder = &MockFeedServicerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockFeedServicer) EXPECT() *MockFeedServicerMockRecorder { - return m.recorder -} - -// GetFeed mocks base method. -func (m *MockFeedServicer) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, swarmID, deviantartID string) (interface{}, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetFeed", twitterID, instagramID, bloggerID, soundcloudID, swarmID, deviantartID) - ret0, _ := ret[0].(interface{}) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetFeed indicates an expected call of GetFeed. -func (mr *MockFeedServicerMockRecorder) GetFeed(twitterID, instagramID, bloggerID, soundcloudID, swarmID, deviantartID interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFeed", reflect.TypeOf((*MockFeedServicer)(nil).GetFeed), twitterID, instagramID, bloggerID, soundcloudID, swarmID, deviantartID) -} - -// Proxy mocks base method. -func (m *MockFeedServicer) Proxy(url string) ([]byte, string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Proxy", url) - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(string) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// Proxy indicates an expected call of Proxy. -func (mr *MockFeedServicerMockRecorder) Proxy(url interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Proxy", reflect.TypeOf((*MockFeedServicer)(nil).Proxy), url) -} diff --git a/internal/service/fetcher.go b/internal/service/fetcher.go index a4d2148..1732021 100644 --- a/internal/service/fetcher.go +++ b/internal/service/fetcher.go @@ -3,6 +3,7 @@ package service import ( "fmt" "io" + "strconv" "net/http" "net/url" @@ -19,6 +20,15 @@ import ( "github.com/tidwall/gjson" ) +type FetcherRequest struct { + TwitterID string `query:"twitterID"` + InstagramID string `query:"instagramID"` + BloggerID string `query:"bloggerID"` + SoundcloudID string `query:"soundcloudID"` + SwarmID string `query:"swarmID"` + DeviantartID string `query:"deviantartID"` +} + const ( count = 50 proxyURL = "https://fetcher-ho4joes5va-uw.a.run.app/proxy" @@ -42,14 +52,15 @@ func NewFetcher(log *logrus.Entry, twitterClient *twitter.Client, insta *goinsta } // GetFeed - Get feed -func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, swarmID, deviantartID string) (interface{}, error) { +func (f *Fetcher) Feeds(req FetcherRequest) (*FeedItems, error) { items := []FeedItem{} var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() - twitterItems, err := f.getTwitter(twitterID) + id, _ := strconv.Atoi(req.TwitterID) + twitterItems, err := f.getTwitter(int64(id)) if err != nil { f.log.WithError(err).Error("error retrieving twitter items") } @@ -62,7 +73,8 @@ func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, wg.Add(1) go func() { defer wg.Done() - instagramItems, err := f.getInstagram(instagramID) + id, _ := strconv.Atoi(req.InstagramID) + instagramItems, err := f.getInstagram(int64(id)) if err != nil { f.log.WithError(err).Error("error retrieving instagram items") } @@ -75,7 +87,7 @@ func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, wg.Add(1) go func() { defer wg.Done() - bloggerItems, err := f.getBlogger(bloggerID) + bloggerItems, err := f.getBlogger(req.BloggerID) if err != nil { f.log.WithError(err).Error("error retrieving blogger items") } @@ -88,7 +100,7 @@ func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, wg.Add(1) go func() { defer wg.Done() - soundcloudItems, err := f.getSoundcloud(soundcloudID) + soundcloudItems, err := f.getSoundcloud(req.SoundcloudID) if err != nil { f.log.WithError(err).Error("error retrieving soundcloud items") } @@ -101,7 +113,7 @@ func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, wg.Add(1) go func() { defer wg.Done() - swarmItems, err := f.getSwarm(swarmID) + swarmItems, err := f.getSwarm(req.SwarmID) if err != nil { f.log.WithError(err).Error("error retrieving swarm items") } @@ -114,7 +126,7 @@ func (f *Fetcher) GetFeed(twitterID, instagramID int64, bloggerID, soundcloudID, wg.Add(1) go func() { defer wg.Done() - deviantartItems, err := f.getDeviantart(deviantartID) + deviantartItems, err := f.getDeviantart(req.DeviantartID) if err != nil { f.log.WithError(err).Error("error retrieving deviantart items") }