github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/storage/base_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storage_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/facades/client/storage"
    15  	"github.com/juju/juju/apiserver/params"
    16  	apiservertesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/environs/context"
    18  	"github.com/juju/juju/state"
    19  	jujustorage "github.com/juju/juju/storage"
    20  	coretesting "github.com/juju/juju/testing"
    21  )
    22  
    23  type baseStorageSuite struct {
    24  	coretesting.BaseSuite
    25  
    26  	resources  *common.Resources
    27  	authorizer apiservertesting.FakeAuthorizer
    28  
    29  	api             *storage.StorageAPI
    30  	apiCaas         *storage.StorageAPI
    31  	apiv3           *storage.StorageAPIv3
    32  	storageAccessor *mockStorageAccessor
    33  	state           *mockState
    34  
    35  	storageTag      names.StorageTag
    36  	storageInstance *mockStorageInstance
    37  	unitTag         names.UnitTag
    38  	machineTag      names.MachineTag
    39  
    40  	volumeTag            names.VolumeTag
    41  	volume               *mockVolume
    42  	volumeAttachment     *mockVolumeAttachment
    43  	volumeAttachmentPlan *mockVolumeAttachmentPlan
    44  	filesystemTag        names.FilesystemTag
    45  	filesystem           *mockFilesystem
    46  	filesystemAttachment *mockFilesystemAttachment
    47  	stub                 testing.Stub
    48  
    49  	registry    jujustorage.StaticProviderRegistry
    50  	poolManager *mockPoolManager
    51  	pools       map[string]*jujustorage.Config
    52  
    53  	blocks      map[state.BlockType]state.Block
    54  	callContext context.ProviderCallContext
    55  }
    56  
    57  func (s *baseStorageSuite) SetUpTest(c *gc.C) {
    58  	s.BaseSuite.SetUpTest(c)
    59  	s.resources = common.NewResources()
    60  	s.authorizer = apiservertesting.FakeAuthorizer{Tag: names.NewUserTag("admin"), Controller: true}
    61  	s.stub.ResetCalls()
    62  	s.state = s.constructState()
    63  	s.storageAccessor = s.constructStorageAccessor()
    64  
    65  	s.registry = jujustorage.StaticProviderRegistry{map[jujustorage.ProviderType]jujustorage.Provider{}}
    66  	s.pools = make(map[string]*jujustorage.Config)
    67  	s.poolManager = s.constructPoolManager()
    68  
    69  	s.callContext = context.NewCloudCallContext()
    70  	s.api = storage.NewStorageAPIForTest(s.state, state.ModelTypeIAAS, s.storageAccessor, s.registry, s.poolManager, s.authorizer, s.callContext)
    71  	s.apiCaas = storage.NewStorageAPIForTest(s.state, state.ModelTypeCAAS, s.storageAccessor, s.registry, s.poolManager, s.authorizer, s.callContext)
    72  	newAPI := storage.NewStorageAPIForTest(s.state, state.ModelTypeIAAS, s.storageAccessor, s.registry, s.poolManager, s.authorizer, s.callContext)
    73  	s.apiv3 = &storage.StorageAPIv3{
    74  		StorageAPIv4: storage.StorageAPIv4{
    75  			StorageAPI: *newAPI,
    76  		},
    77  	}
    78  }
    79  
    80  // TODO(axw) get rid of assertCalls, use stub directly everywhere.
    81  func (s *baseStorageSuite) assertCalls(c *gc.C, expectedCalls []string) {
    82  	s.stub.CheckCallNames(c, expectedCalls...)
    83  }
    84  
    85  const (
    86  	allStorageInstancesCall                 = "allStorageInstances"
    87  	storageInstanceAttachmentsCall          = "storageInstanceAttachments"
    88  	storageInstanceCall                     = "StorageInstance"
    89  	storageInstanceFilesystemCall           = "StorageInstanceFilesystem"
    90  	storageInstanceFilesystemAttachmentCall = "storageInstanceFilesystemAttachment"
    91  	storageInstanceVolumeCall               = "storageInstanceVolume"
    92  	volumeCall                              = "volumeCall"
    93  	machineVolumeAttachmentsCall            = "machineVolumeAttachments"
    94  	volumeAttachmentsCall                   = "volumeAttachments"
    95  	allVolumesCall                          = "allVolumes"
    96  	filesystemCall                          = "filesystemCall"
    97  	machineFilesystemAttachmentsCall        = "machineFilesystemAttachments"
    98  	filesystemAttachmentsCall               = "filesystemAttachments"
    99  	allFilesystemsCall                      = "allFilesystems"
   100  	addStorageForUnitCall                   = "addStorageForUnit"
   101  	getBlockForTypeCall                     = "getBlockForType"
   102  	volumeAttachmentCall                    = "volumeAttachment"
   103  	volumeAttachmentPlanCall                = "volumeAttachmentPlan"
   104  	volumeAttachmentPlansCall               = "volumeAttachmentPlans"
   105  	attachStorageCall                       = "attachStorage"
   106  	detachStorageCall                       = "detachStorage"
   107  	destroyStorageInstanceCall              = "destroyStorageInstance"
   108  	releaseStorageInstanceCall              = "releaseStorageInstance"
   109  	addExistingFilesystemCall               = "addExistingFilesystem"
   110  )
   111  
   112  func (s *baseStorageSuite) constructState() *mockState {
   113  	s.unitTag = names.NewUnitTag("mysql/0")
   114  	s.blocks = make(map[state.BlockType]state.Block)
   115  	return &mockState{
   116  		unitName:        s.unitTag.Id(),
   117  		assignedMachine: s.machineTag.Id(),
   118  		getBlockForType: func(t state.BlockType) (state.Block, bool, error) {
   119  			s.stub.AddCall(getBlockForTypeCall, t)
   120  			val, found := s.blocks[t]
   121  			return val, found, nil
   122  		},
   123  	}
   124  }
   125  
   126  func (s *baseStorageSuite) constructStorageAccessor() *mockStorageAccessor {
   127  	s.storageTag = names.NewStorageTag("data/0")
   128  
   129  	s.storageInstance = &mockStorageInstance{
   130  		kind:       state.StorageKindFilesystem,
   131  		owner:      s.unitTag,
   132  		storageTag: s.storageTag,
   133  		life:       state.Dying,
   134  	}
   135  
   136  	storageInstanceAttachment := &mockStorageAttachment{
   137  		storage: s.storageInstance,
   138  		life:    state.Alive,
   139  	}
   140  
   141  	s.machineTag = names.NewMachineTag("66")
   142  	s.filesystemTag = names.NewFilesystemTag("104")
   143  	s.volumeTag = names.NewVolumeTag("22")
   144  	s.filesystem = &mockFilesystem{
   145  		tag:     s.filesystemTag,
   146  		storage: &s.storageTag,
   147  		life:    state.Alive,
   148  	}
   149  	s.filesystemAttachment = &mockFilesystemAttachment{
   150  		filesystem: s.filesystemTag,
   151  		machine:    s.machineTag,
   152  		life:       state.Dead,
   153  	}
   154  	s.volume = &mockVolume{tag: s.volumeTag, storage: &s.storageTag}
   155  	s.volumeAttachment = &mockVolumeAttachment{
   156  		VolumeTag: s.volumeTag,
   157  		HostTag:   s.machineTag,
   158  		life:      state.Alive,
   159  	}
   160  
   161  	s.volumeAttachmentPlan = &mockVolumeAttachmentPlan{
   162  		VolumeTag: s.volumeTag,
   163  		HostTag:   s.machineTag,
   164  		life:      state.Alive,
   165  		info:      &state.VolumeAttachmentPlanInfo{},
   166  		blk:       &state.BlockDeviceInfo{},
   167  	}
   168  
   169  	return &mockStorageAccessor{
   170  		allStorageInstances: func() ([]state.StorageInstance, error) {
   171  			s.stub.AddCall(allStorageInstancesCall)
   172  			return []state.StorageInstance{s.storageInstance}, nil
   173  		},
   174  		storageInstance: func(sTag names.StorageTag) (state.StorageInstance, error) {
   175  			s.stub.AddCall(storageInstanceCall, sTag)
   176  			if sTag == s.storageTag {
   177  				return s.storageInstance, nil
   178  			}
   179  			return nil, errors.NotFoundf("%s", names.ReadableString(sTag))
   180  		},
   181  		storageInstanceAttachments: func(tag names.StorageTag) ([]state.StorageAttachment, error) {
   182  			s.stub.AddCall(storageInstanceAttachmentsCall, tag)
   183  			if tag == s.storageTag {
   184  				return []state.StorageAttachment{storageInstanceAttachment}, nil
   185  			}
   186  			return []state.StorageAttachment{}, nil
   187  		},
   188  		storageInstanceFilesystem: func(sTag names.StorageTag) (state.Filesystem, error) {
   189  			s.stub.AddCall(storageInstanceFilesystemCall)
   190  			if sTag == s.storageTag {
   191  				return s.filesystem, nil
   192  			}
   193  			return nil, errors.NotFoundf("%s", names.ReadableString(sTag))
   194  		},
   195  		storageInstanceFilesystemAttachment: func(m names.Tag, f names.FilesystemTag) (state.FilesystemAttachment, error) {
   196  			s.stub.AddCall(storageInstanceFilesystemAttachmentCall)
   197  			if m == s.machineTag && f == s.filesystemTag {
   198  				return s.filesystemAttachment, nil
   199  			}
   200  			return nil, errors.NotFoundf("filesystem attachment %s:%s", m, f)
   201  		},
   202  		storageInstanceVolume: func(t names.StorageTag) (state.Volume, error) {
   203  			s.stub.AddCall(storageInstanceVolumeCall)
   204  			if t == s.storageTag {
   205  				return s.volume, nil
   206  			}
   207  			return nil, errors.NotFoundf("%s", names.ReadableString(t))
   208  		},
   209  		volumeAttachment: func(names.Tag, names.VolumeTag) (state.VolumeAttachment, error) {
   210  			s.stub.AddCall(volumeAttachmentCall)
   211  			return s.volumeAttachment, nil
   212  		},
   213  		volumeAttachmentPlan: func(names.Tag, names.VolumeTag) (state.VolumeAttachmentPlan, error) {
   214  			s.stub.AddCall(volumeAttachmentPlanCall)
   215  			return s.volumeAttachmentPlan, nil
   216  		},
   217  		volumeAttachmentPlans: func(names.VolumeTag) ([]state.VolumeAttachmentPlan, error) {
   218  			s.stub.AddCall(volumeAttachmentPlansCall)
   219  			return []state.VolumeAttachmentPlan{s.volumeAttachmentPlan}, nil
   220  		},
   221  		volume: func(tag names.VolumeTag) (state.Volume, error) {
   222  			s.stub.AddCall(volumeCall)
   223  			if tag == s.volumeTag {
   224  				return s.volume, nil
   225  			}
   226  			return nil, errors.NotFoundf("%s", names.ReadableString(tag))
   227  		},
   228  		machineVolumeAttachments: func(machine names.MachineTag) ([]state.VolumeAttachment, error) {
   229  			s.stub.AddCall(machineVolumeAttachmentsCall)
   230  			if machine == s.machineTag {
   231  				return []state.VolumeAttachment{s.volumeAttachment}, nil
   232  			}
   233  			return nil, nil
   234  		},
   235  		volumeAttachments: func(volume names.VolumeTag) ([]state.VolumeAttachment, error) {
   236  			s.stub.AddCall(volumeAttachmentsCall)
   237  			if volume == s.volumeTag {
   238  				return []state.VolumeAttachment{s.volumeAttachment}, nil
   239  			}
   240  			return nil, nil
   241  		},
   242  		allVolumes: func() ([]state.Volume, error) {
   243  			s.stub.AddCall(allVolumesCall)
   244  			return []state.Volume{s.volume}, nil
   245  		},
   246  		filesystem: func(tag names.FilesystemTag) (state.Filesystem, error) {
   247  			s.stub.AddCall(filesystemCall)
   248  			if tag == s.filesystemTag {
   249  				return s.filesystem, nil
   250  			}
   251  			return nil, errors.NotFoundf("%s", names.ReadableString(tag))
   252  		},
   253  		machineFilesystemAttachments: func(machine names.MachineTag) ([]state.FilesystemAttachment, error) {
   254  			s.stub.AddCall(machineFilesystemAttachmentsCall)
   255  			if machine == s.machineTag {
   256  				return []state.FilesystemAttachment{s.filesystemAttachment}, nil
   257  			}
   258  			return nil, nil
   259  		},
   260  		filesystemAttachments: func(filesystem names.FilesystemTag) ([]state.FilesystemAttachment, error) {
   261  			s.stub.AddCall(filesystemAttachmentsCall)
   262  			if filesystem == s.filesystemTag {
   263  				return []state.FilesystemAttachment{s.filesystemAttachment}, nil
   264  			}
   265  			return nil, nil
   266  		},
   267  		allFilesystems: func() ([]state.Filesystem, error) {
   268  			s.stub.AddCall(allFilesystemsCall)
   269  			return []state.Filesystem{s.filesystem}, nil
   270  		},
   271  		addStorageForUnit: func(u names.UnitTag, name string, cons state.StorageConstraints) ([]names.StorageTag, error) {
   272  			s.stub.AddCall(addStorageForUnitCall)
   273  			return nil, nil
   274  		},
   275  		detachStorage: func(storage names.StorageTag, unit names.UnitTag) error {
   276  			s.stub.AddCall(detachStorageCall, storage, unit)
   277  			if storage == s.storageTag && unit == s.unitTag {
   278  				return nil
   279  			}
   280  			return errors.NotFoundf(
   281  				"attachment of %s to %s",
   282  				names.ReadableString(storage),
   283  				names.ReadableString(unit),
   284  			)
   285  		},
   286  		attachStorage: func(storage names.StorageTag, unit names.UnitTag) error {
   287  			s.stub.AddCall(attachStorageCall, storage, unit)
   288  			if storage == s.storageTag && unit == s.unitTag {
   289  				return nil
   290  			}
   291  			return errors.Errorf(
   292  				"cannot attach %s to %s",
   293  				names.ReadableString(storage),
   294  				names.ReadableString(unit),
   295  			)
   296  		},
   297  		destroyStorageInstance: func(tag names.StorageTag, destroyAttached bool) error {
   298  			s.stub.AddCall(destroyStorageInstanceCall, tag, destroyAttached)
   299  			return errors.New("cannae do it")
   300  		},
   301  		releaseStorageInstance: func(tag names.StorageTag, destroyAttached bool) error {
   302  			s.stub.AddCall(releaseStorageInstanceCall, tag, destroyAttached)
   303  			return errors.New("cannae do it")
   304  		},
   305  		addExistingFilesystem: func(f state.FilesystemInfo, v *state.VolumeInfo, storageName string) (names.StorageTag, error) {
   306  			s.stub.AddCall(addExistingFilesystemCall, f, v, storageName)
   307  			return s.storageTag, s.stub.NextErr()
   308  		},
   309  	}
   310  }
   311  
   312  func (s *baseStorageSuite) addBlock(c *gc.C, t state.BlockType, msg string) {
   313  	s.blocks[t] = mockBlock{
   314  		t:   t,
   315  		msg: msg,
   316  	}
   317  }
   318  
   319  func (s *baseStorageSuite) blockAllChanges(c *gc.C, msg string) {
   320  	s.addBlock(c, state.ChangeBlock, msg)
   321  }
   322  
   323  func (s *baseStorageSuite) blockDestroyModel(c *gc.C, msg string) {
   324  	s.addBlock(c, state.DestroyBlock, msg)
   325  }
   326  
   327  func (s *baseStorageSuite) blockRemoveObject(c *gc.C, msg string) {
   328  	s.addBlock(c, state.RemoveBlock, msg)
   329  }
   330  
   331  func (s *baseStorageSuite) assertBlocked(c *gc.C, err error, msg string) {
   332  	c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue)
   333  	c.Assert(err, gc.ErrorMatches, msg)
   334  }
   335  
   336  func (s *baseStorageSuite) constructPoolManager() *mockPoolManager {
   337  	return &mockPoolManager{
   338  		getPool: func(name string) (*jujustorage.Config, error) {
   339  			if one, ok := s.pools[name]; ok {
   340  				return one, nil
   341  			}
   342  			return nil, errors.NotFoundf("mock pool manager: get pool %v", name)
   343  		},
   344  		createPool: func(name string, providerType jujustorage.ProviderType, attrs map[string]interface{}) (*jujustorage.Config, error) {
   345  			pool, err := jujustorage.NewConfig(name, providerType, attrs)
   346  			s.pools[name] = pool
   347  			return pool, err
   348  		},
   349  		removePool: func(name string) error {
   350  			delete(s.pools, name)
   351  			return nil
   352  		},
   353  		listPools: func() ([]*jujustorage.Config, error) {
   354  			result := make([]*jujustorage.Config, len(s.pools))
   355  			i := 0
   356  			for _, v := range s.pools {
   357  				result[i] = v
   358  				i++
   359  			}
   360  			return result, nil
   361  		},
   362  		replacePool: func(name, provider string, attrs map[string]interface{}) error {
   363  			if p, ok := s.pools[name]; ok {
   364  				providerType := p.Provider()
   365  				if provider != "" {
   366  					providerType = jujustorage.ProviderType(provider)
   367  				}
   368  				newPool, err := jujustorage.NewConfig(name, providerType, attrs)
   369  				s.pools[name] = newPool
   370  				return err
   371  			}
   372  			return errors.NotFoundf("mock pool manager: get pool %v", name)
   373  		},
   374  	}
   375  }