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 }