github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/client/charms/services/storage_test.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package services_test 5 6 import ( 7 "errors" 8 "fmt" 9 "strings" 10 11 "github.com/juju/loggo" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils/v3" 15 "go.uber.org/mock/gomock" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/apiserver/facades/client/charms/services" 19 "github.com/juju/juju/apiserver/facades/client/charms/services/mocks" 20 "github.com/juju/juju/core/charm/downloader" 21 "github.com/juju/juju/state" 22 stateerrors "github.com/juju/juju/state/errors" 23 ) 24 25 var _ = gc.Suite(&storageTestSuite{}) 26 27 type storageTestSuite struct { 28 testing.IsolationSuite 29 30 stateBackend *mocks.MockStateBackend 31 uploadedCharm *mocks.MockUploadedCharm 32 storageBackend *mocks.MockStorage 33 storage *services.CharmStorage 34 uuid utils.UUID 35 } 36 37 func (s *storageTestSuite) TestPrepareToStoreNotYetUploadedCharm(c *gc.C) { 38 defer s.setupMocks(c).Finish() 39 40 curl := "ch:ubuntu-lite" 41 42 s.stateBackend.EXPECT().PrepareCharmUpload(curl).Return(s.uploadedCharm, nil) 43 s.uploadedCharm.EXPECT().IsUploaded().Return(false) 44 45 err := s.storage.PrepareToStoreCharm(curl) 46 c.Assert(err, jc.ErrorIsNil) 47 } 48 49 func (s *storageTestSuite) TestPrepareToStoreAlreadyUploadedCharm(c *gc.C) { 50 defer s.setupMocks(c).Finish() 51 52 curl := "ch:ubuntu-lite" 53 54 s.stateBackend.EXPECT().PrepareCharmUpload(curl).Return(s.uploadedCharm, nil) 55 s.uploadedCharm.EXPECT().IsUploaded().Return(true) 56 57 err := s.storage.PrepareToStoreCharm(curl) 58 59 expErr := downloader.NewCharmAlreadyStoredError(curl) 60 c.Assert(err, gc.Equals, expErr) 61 } 62 63 func (s *storageTestSuite) TestStoreBlobFails(c *gc.C) { 64 defer s.setupMocks(c).Finish() 65 66 curl := "ch:ubuntu-lite" 67 expStoreCharmPath := fmt.Sprintf("charms/%s-%s", curl, s.uuid) 68 dlCharm := downloader.DownloadedCharm{ 69 CharmData: strings.NewReader("the-blob"), 70 Size: 7337, 71 } 72 73 s.stateBackend.EXPECT().ModelUUID().Return("the-model-uuid") 74 s.storageBackend.EXPECT().Put(expStoreCharmPath, gomock.AssignableToTypeOf(dlCharm.CharmData), int64(7337)).Return(errors.New("failed")) 75 76 err := s.storage.Store(curl, dlCharm) 77 c.Assert(err, gc.ErrorMatches, "cannot add charm to storage.*") 78 } 79 80 func (s *storageTestSuite) TestStoreBlobAlreadyStored(c *gc.C) { 81 defer s.setupMocks(c).Finish() 82 83 curl := "ch:ubuntu-lite" 84 expStoreCharmPath := fmt.Sprintf("charms/%s-%s", curl, s.uuid) 85 dlCharm := downloader.DownloadedCharm{ 86 CharmData: strings.NewReader("the-blob"), 87 Size: 7337, 88 SHA256: "d357", 89 CharmVersion: "the-version", 90 } 91 92 s.stateBackend.EXPECT().ModelUUID().Return("the-model-uuid") 93 s.storageBackend.EXPECT().Put(expStoreCharmPath, gomock.AssignableToTypeOf(dlCharm.CharmData), int64(7337)).Return(nil) 94 s.stateBackend.EXPECT().UpdateUploadedCharm(state.CharmInfo{ 95 StoragePath: expStoreCharmPath, 96 ID: curl, 97 SHA256: "d357", 98 Version: "the-version", 99 }).Return(nil, stateerrors.NewErrCharmAlreadyUploaded(curl)) 100 101 // As the blob is already uploaded (to another path), we need to remove 102 // the duplicate we just uploaded from the store. 103 s.storageBackend.EXPECT().Remove(expStoreCharmPath).Return(nil) 104 105 err := s.storage.Store(curl, dlCharm) 106 c.Assert(err, jc.ErrorIsNil) // charm already uploaded by someone; no error 107 } 108 109 func (s *storageTestSuite) setupMocks(c *gc.C) *gomock.Controller { 110 ctrl := gomock.NewController(c) 111 s.stateBackend = mocks.NewMockStateBackend(ctrl) 112 s.uploadedCharm = mocks.NewMockUploadedCharm(ctrl) 113 s.storageBackend = mocks.NewMockStorage(ctrl) 114 115 var err error 116 s.uuid, err = utils.NewUUID() 117 c.Assert(err, jc.ErrorIsNil) 118 119 s.storage = services.NewCharmStorage(services.CharmStorageConfig{ 120 Logger: loggo.GetLogger("test"), 121 StateBackend: s.stateBackend, 122 StorageFactory: func(_ string) services.Storage { 123 return s.storageBackend 124 }, 125 }) 126 s.storage.SetUUIDGenerator(func() (utils.UUID, error) { 127 return s.uuid, nil 128 }) 129 130 return ctrl 131 }