Skip to content

Commit

Permalink
feat: Accept interface while injecting storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mauricioabreu committed Jan 15, 2024
1 parent 82b1c33 commit de8fdd1
Show file tree
Hide file tree
Showing 18 changed files with 4,341 additions and 10 deletions.
6 changes: 5 additions & 1 deletion cmd/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/joho/godotenv"
"github.com/mauricioabreu/mosaic-video/internal/config"
"github.com/mauricioabreu/mosaic-video/internal/logging"
"github.com/mauricioabreu/mosaic-video/internal/storage"
"github.com/mauricioabreu/mosaic-video/internal/storage/s3"
"github.com/mauricioabreu/mosaic-video/internal/uploader"
"github.com/spf13/cobra"
Expand All @@ -26,7 +27,10 @@ func Store() *cobra.Command {
config.NewConfig,
logging.NewLogger,
uploader.NewHandler,
s3.NewClient,
fx.Annotate(
s3.NewClient,
fx.As(new(storage.Storage)),
),
),
fx.Invoke(uploader.Run),
)
Expand Down
82 changes: 82 additions & 0 deletions internal/mocks/storage.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion internal/storage/storage.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package storage

import "io"

type Storage interface {
CreateBucket(bucketName string) error
Upload(path string, data []byte) error
Get(path string) ([]byte, error)
Get(path string) (io.Reader, error)
}
15 changes: 8 additions & 7 deletions internal/uploader/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import (
"net/http"

"github.com/gorilla/mux"
"github.com/mauricioabreu/mosaic-video/internal/storage/s3"
"github.com/mauricioabreu/mosaic-video/internal/storage"
"go.uber.org/zap"
)

type FileUploadHandler struct {
s3Client *s3.Client
logger *zap.SugaredLogger
storageHandler storage.Storage
logger *zap.SugaredLogger
}

func NewHandler(s3c *s3.Client, logger *zap.SugaredLogger) *FileUploadHandler {
func NewHandler(s storage.Storage, logger *zap.SugaredLogger) *FileUploadHandler {
return &FileUploadHandler{
s3Client: s3c,
logger: logger,
storageHandler: s,
logger: logger,
}
}

Expand All @@ -42,12 +42,13 @@ func (fu *FileUploadHandler) serveHTTPImpl(folder, filename string, w http.Respo

filepath := fmt.Sprintf("%s/%s", folder, filename)

if err := fu.s3Client.Upload(filepath, data); err != nil {
if err := fu.storageHandler.Upload(filepath, data); err != nil {
fu.logger.Errorf("failed to upload file to storage: %v", err)
w.WriteHeader(http.StatusInternalServerError)

return
}

w.WriteHeader(http.StatusOK)
fu.logger.Infof("file %s uploaded to folder %s", filename, folder)
}
95 changes: 95 additions & 0 deletions internal/uploader/server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package uploader_test

import (
"bytes"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"github.com/gorilla/mux"
"github.com/mauricioabreu/mosaic-video/internal/mocks"
"github.com/mauricioabreu/mosaic-video/internal/uploader"
"github.com/stretchr/testify/suite"
"go.uber.org/mock/gomock"
"go.uber.org/zap"
)

type errorReader struct{}

func (errorReader) Read(p []byte) (n int, err error) {
return 0, fmt.Errorf("error reading")
}

type FileUploadHandlerTestSuite struct {
suite.Suite
ctrl *gomock.Controller
storageClient *mocks.MockStorage
handler *uploader.FileUploadHandler
logger *zap.SugaredLogger
}

func (suite *FileUploadHandlerTestSuite) SetupTest() {
suite.ctrl = gomock.NewController(suite.T())
suite.storageClient = mocks.NewMockStorage(suite.ctrl)
suite.logger = zap.NewNop().Sugar()
suite.handler = uploader.NewHandler(suite.storageClient, suite.logger)
}

func (suite *FileUploadHandlerTestSuite) TearDownTest() {
suite.ctrl.Finish()
}

func TestFileUploadHandlerTestSuite(t *testing.T) {
suite.Run(t, new(FileUploadHandlerTestSuite))
}

func (suite *FileUploadHandlerTestSuite) TestSuccessfulUpload() {
expectedPath := "test_folder/test_file.txt"
suite.storageClient.EXPECT().Upload(expectedPath, gomock.Any()).Return(nil)

r := mux.NewRouter()
r.Handle("/upload/{folder}/{filename}", suite.handler)

req := httptest.NewRequest("PUT", "/upload/test_folder/test_file.txt", bytes.NewReader([]byte("test content")))
w := httptest.NewRecorder()
r.ServeHTTP(w, req)

resp := w.Result()
defer resp.Body.Close()

suite.Assert().Equal(http.StatusOK, resp.StatusCode)
}

func (suite *FileUploadHandlerTestSuite) TestReadError() {
r := mux.NewRouter()
r.Handle("/upload/{folder}/{filename}", suite.handler)

req := httptest.NewRequest("PUT", "/upload/test_folder/test_file.txt", errorReader{})
w := httptest.NewRecorder()
r.ServeHTTP(w, req)

resp := w.Result()
defer resp.Body.Close()

suite.Assert().Equal(http.StatusInternalServerError, resp.StatusCode)
}

func (suite *FileUploadHandlerTestSuite) TestUploadError() {
expectedPath := "test_folder/test_file.txt"
uploadErr := errors.New("upload failed")
suite.storageClient.EXPECT().Upload(expectedPath, gomock.Any()).Return(uploadErr)

r := mux.NewRouter()
r.Handle("/upload/{folder}/{filename}", suite.handler)

req := httptest.NewRequest("PUT", "/upload/test_folder/test_file.txt", bytes.NewReader([]byte("test content")))
w := httptest.NewRecorder()
r.ServeHTTP(w, req)

resp := w.Result()
defer resp.Body.Close()

suite.Assert().Equal(http.StatusInternalServerError, resp.StatusCode)
}
6 changes: 5 additions & 1 deletion internal/worker/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (

func TestGenerateMosaicWhenLockingFails(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

locker := mocks.NewMockLocker(ctrl)
mosaic := mosaic.Mosaic{
Name: "mosaicvideo",
Expand All @@ -38,8 +40,10 @@ func TestGenerateMosaicWhenLockingFails(t *testing.T) {
}

func TestGenerateMosaicWhenExecutingCommandFails(t *testing.T) {
cfg := &config.Config{}
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cfg := &config.Config{}
locker := mocks.NewMockLocker(ctrl)
mosaic := mosaic.Mosaic{
Name: "mosaicvideo",
Expand Down
29 changes: 29 additions & 0 deletions vendor/github.com/stretchr/testify/require/doc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions vendor/github.com/stretchr/testify/require/forward_requirements.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit de8fdd1

Please sign in to comment.