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  }