From 0df4e2360842fe1baac319d3358ae954fc1542e6 Mon Sep 17 00:00:00 2001 From: Igor Shishkin Date: Wed, 10 Jul 2024 22:48:49 +0300 Subject: [PATCH] Implement access service (#40) --- service/service.go | 45 +++++++++--- service/service_test.go | 154 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 service/service_test.go diff --git a/service/service.go b/service/service.go index 4194cc5..6daf48e 100644 --- a/service/service.go +++ b/service/service.go @@ -41,23 +41,36 @@ type service struct { } func NewManageService(mdRepo metadata.Repository, blobRepo blob.Repository) ManageService { - return &service{} + return newSvc(mdRepo, blobRepo) } func NewAccessService(mdRepo metadata.Repository, blobRepo blob.Repository) AccessService { - return &service{} + return newSvc(mdRepo, blobRepo) +} + +func newSvc(mdRepo metadata.Repository, blobRepo blob.Repository) *service { + return &service{ + mdRepo: mdRepo, + blobRepo: blobRepo, + } } func (s *service) CreateContainer(ctx context.Context, name string) error { - return s.mdRepo.CreateContainer(ctx, name) + err := s.mdRepo.CreateContainer(ctx, name) + if err != nil { + return errors.Wrap(err, "error creating container") + } + return err } func (s *service) ListContainers(ctx context.Context) ([]string, error) { - return s.mdRepo.ListContainers(ctx) + containers, err := s.mdRepo.ListContainers(ctx) + return containers, mapMetadataErrors(err) } func (s *service) DeleteContainer(ctx context.Context, name string) error { - return s.mdRepo.DeleteContainer(ctx, name) + err := s.mdRepo.DeleteContainer(ctx, name) + return mapMetadataErrors(err) } func (s *service) CreateVersion(ctx context.Context, container string) (id string, err error) { @@ -65,7 +78,8 @@ func (s *service) CreateVersion(ctx context.Context, container string) (id strin } func (s *service) ListVersions(ctx context.Context, container string) ([]string, error) { - panic("not implemented") + versions, err := s.mdRepo.ListPublishedVersionsByContainer(ctx, container) + return versions, mapMetadataErrors(err) } func (s *service) PublishVersion(ctx context.Context, container, id string) error { @@ -81,13 +95,28 @@ func (s *service) AddObject(ctx context.Context, container, versionID, key strin } func (s *service) ListObjects(ctx context.Context, container, versionID string) ([]string, error) { - panic("not implemented") + objects, err := s.mdRepo.ListObjects(ctx, container, versionID, 0, 1000) + return objects, mapMetadataErrors(err) } func (s *service) GetObjectURL(ctx context.Context, container, versionID, key string) (string, error) { - panic("not implemented") + key, err := s.mdRepo.GetBlobKeyByObject(ctx, container, versionID, key) + if err != nil { + return "", mapMetadataErrors(err) + } + + return s.blobRepo.GetBlobURL(ctx, key) } func (s *service) DeleteObject(ctx context.Context, container, versionID, key string) error { panic("not implemented") } + +func mapMetadataErrors(err error) error { + switch err { + case metadata.ErrNotFound: + return ErrNotFound + default: + return err + } +} diff --git a/service/service_test.go b/service/service_test.go new file mode 100644 index 0000000..d683325 --- /dev/null +++ b/service/service_test.go @@ -0,0 +1,154 @@ +package service + +import ( + "context" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/suite" + + blobRepoMock "github.com/teran/archived/repositories/blob/mock" + mdRepoMock "github.com/teran/archived/repositories/metadata/mock" +) + +func (s *serviceTestSuite) TestCreateContainer() { + // Happy path + s.mdRepoMock.On("CreateContainer", "container").Return(nil).Once() + + err := s.svc.CreateContainer(s.ctx, "container") + s.Require().NoError(err) + + // return error + s.mdRepoMock.On("CreateContainer", "container").Return(errors.New("test error")).Once() + + err = s.svc.CreateContainer(s.ctx, "container") + s.Require().Error(err) + s.Require().Equal("error creating container: test error", err.Error()) +} + +func (s *serviceTestSuite) TestDeleteContainer() { + s.mdRepoMock.On("DeleteContainer", "container").Return(nil).Once() + + err := s.svc.DeleteContainer(s.ctx, "container") + s.Require().NoError(err) +} + +func (s *serviceTestSuite) TestCreateVersion() { + s.Require().PanicsWithValue("not implemented", func() { + s.svc.CreateVersion(s.ctx, "container") + }) +} + +func (s *serviceTestSuite) TestPublishVersion() { + s.Require().PanicsWithValue("not implemented", func() { + s.svc.PublishVersion(s.ctx, "container", "version") + }) +} + +func (s *serviceTestSuite) TestDeleteVersion() { + s.Require().PanicsWithValue("not implemented", func() { + s.svc.DeleteVersion(s.ctx, "container", "version") + }) +} + +func (s *serviceTestSuite) TestAddObject() { + s.Require().PanicsWithValue("not implemented", func() { + s.svc.AddObject(s.ctx, "container", "versionID", "key", nil) + }) +} + +func (s *serviceTestSuite) TestDeleteObject() { + s.Require().PanicsWithValue("not implemented", func() { + s.svc.DeleteObject(s.ctx, "container", "version", "key") + }) +} + +func (s *serviceTestSuite) TestListContainers() { + // Happy path + s.mdRepoMock.On("ListContainers").Return([]string{ + "container1", "container2", + }, nil).Once() + + containers, err := s.svc.ListContainers(s.ctx) + s.Require().NoError(err) + s.Require().Equal([]string{ + "container1", "container2", + }, containers) + + // return error + s.mdRepoMock.On("ListContainers").Return([]string(nil), errors.New("test error")).Once() + + _, err = s.svc.ListContainers(s.ctx) + s.Require().Error(err) + s.Require().Equal("test error", err.Error()) +} + +func (s *serviceTestSuite) TestListVersions() { + s.mdRepoMock.On("ListPublishedVersionsByContainer", "container").Return([]string{ + "version1", "version2", + }, nil).Once() + + versions, err := s.svc.ListVersions(s.ctx, "container") + s.Require().NoError(err) + s.Require().Equal([]string{ + "version1", "version2", + }, versions) +} + +func (s *serviceTestSuite) TestListObjects() { + // Happy path + s.mdRepoMock.On("ListObjects", "container", "versionID", uint64(0), uint64(1000)).Return([]string{ + "object1", "object2", + }, nil).Once() + + objects, err := s.svc.ListObjects(s.ctx, "container", "versionID") + s.Require().NoError(err) + s.Require().Equal([]string{ + "object1", "object2", + }, objects) + + // return error + s.mdRepoMock.On("ListObjects", "container", "versionID", uint64(0), uint64(1000)).Return([]string(nil), errors.New("test error")).Once() + + _, err = s.svc.ListObjects(s.ctx, "container", "versionID") + s.Require().Error(err) + s.Require().Equal("test error", err.Error()) +} + +func (s *serviceTestSuite) TestGetObjectURL() { + // Happy path + s.mdRepoMock.On("GetBlobKeyByObject", "container", "versionID", "key").Return("deadbeef", nil).Once() + s.blobRepoMock.On("GetBlobURL", "deadbeef").Return("url", nil).Once() + + url, err := s.svc.GetObjectURL(s.ctx, "container", "versionID", "key") + s.Require().NoError(err) + s.Require().Equal("url", url) +} + +// Definitions +type serviceTestSuite struct { + suite.Suite + + ctx context.Context + svc *service + mdRepoMock *mdRepoMock.Mock + blobRepoMock *blobRepoMock.Mock +} + +func (s *serviceTestSuite) SetupTest() { + s.ctx = context.Background() + + s.mdRepoMock = mdRepoMock.New() + s.blobRepoMock = blobRepoMock.New() + + s.svc = newSvc(s.mdRepoMock, s.blobRepoMock) +} + +func (s *serviceTestSuite) TearDownTest() { + s.mdRepoMock.AssertExpectations(s.T()) + s.blobRepoMock.AssertExpectations(s.T()) +} + +func TestServiceTestSuite(t *testing.T) { + suite.Run(t, &serviceTestSuite{}) +}