github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/storage/client_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 "fmt" 8 9 "github.com/juju/collections/set" 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/names.v2" 14 15 basetesting "github.com/juju/juju/api/base/testing" 16 "github.com/juju/juju/api/storage" 17 "github.com/juju/juju/apiserver/common" 18 "github.com/juju/juju/apiserver/params" 19 jujustorage "github.com/juju/juju/storage" 20 "github.com/juju/juju/testing" 21 ) 22 23 type storageMockSuite struct { 24 testing.BaseSuite 25 } 26 27 var _ = gc.Suite(&storageMockSuite{}) 28 29 func (s *storageMockSuite) TestStorageDetails(c *gc.C) { 30 one := "shared-fs/0" 31 oneTag := names.NewStorageTag(one) 32 two := "db-dir/1000" 33 twoTag := names.NewStorageTag(two) 34 expected := set.NewStrings(oneTag.String(), twoTag.String()) 35 msg := "call failure" 36 37 apiCaller := basetesting.APICallerFunc( 38 func(objType string, 39 version int, 40 id, request string, 41 a, result interface{}, 42 ) error { 43 c.Check(objType, gc.Equals, "Storage") 44 c.Check(id, gc.Equals, "") 45 c.Check(request, gc.Equals, "StorageDetails") 46 47 args, ok := a.(params.Entities) 48 c.Assert(ok, jc.IsTrue) 49 c.Assert(args.Entities, gc.HasLen, 2) 50 51 if results, k := result.(*params.StorageDetailsResults); k { 52 instances := []params.StorageDetailsResult{ 53 { 54 Result: ¶ms.StorageDetails{StorageTag: oneTag.String()}, 55 }, 56 { 57 Result: ¶ms.StorageDetails{ 58 StorageTag: twoTag.String(), 59 Status: params.EntityStatus{ 60 Status: "attached", 61 }, 62 Persistent: true, 63 }, 64 }, 65 { 66 Error: common.ServerError(errors.New(msg)), 67 }, 68 } 69 results.Results = instances 70 } 71 72 return nil 73 }) 74 storageClient := storage.NewClient(apiCaller) 75 tags := []names.StorageTag{oneTag, twoTag} 76 found, err := storageClient.StorageDetails(tags) 77 c.Assert(err, jc.ErrorIsNil) 78 c.Assert(found, gc.HasLen, 3) 79 c.Assert(expected.Contains(found[0].Result.StorageTag), jc.IsTrue) 80 c.Assert(expected.Contains(found[1].Result.StorageTag), jc.IsTrue) 81 c.Assert(found[2].Error, gc.ErrorMatches, msg) 82 } 83 84 func (s *storageMockSuite) TestStorageDetailsFacadeCallError(c *gc.C) { 85 one := "shared-fs/0" 86 oneTag := names.NewStorageTag(one) 87 88 msg := "facade failure" 89 apiCaller := basetesting.APICallerFunc( 90 func(objType string, 91 version int, 92 id, request string, 93 a, result interface{}, 94 ) error { 95 c.Check(objType, gc.Equals, "Storage") 96 c.Check(id, gc.Equals, "") 97 c.Check(request, gc.Equals, "StorageDetails") 98 99 return errors.New(msg) 100 }) 101 storageClient := storage.NewClient(apiCaller) 102 found, err := storageClient.StorageDetails([]names.StorageTag{oneTag}) 103 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 104 c.Assert(found, gc.HasLen, 0) 105 } 106 107 func (s *storageMockSuite) TestListStorageDetails(c *gc.C) { 108 storageTag := names.NewStorageTag("db-dir/1000") 109 110 apiCaller := basetesting.APICallerFunc( 111 func(objType string, 112 version int, 113 id, request string, 114 a, result interface{}, 115 ) error { 116 c.Check(objType, gc.Equals, "Storage") 117 c.Check(id, gc.Equals, "") 118 c.Check(request, gc.Equals, "ListStorageDetails") 119 c.Check(a, jc.DeepEquals, params.StorageFilters{ 120 []params.StorageFilter{{}}, 121 }) 122 123 c.Assert(result, gc.FitsTypeOf, ¶ms.StorageDetailsListResults{}) 124 results := result.(*params.StorageDetailsListResults) 125 results.Results = []params.StorageDetailsListResult{{ 126 Result: []params.StorageDetails{{ 127 StorageTag: storageTag.String(), 128 Status: params.EntityStatus{ 129 Status: "attached", 130 }, 131 Persistent: true, 132 }}, 133 }} 134 135 return nil 136 }, 137 ) 138 storageClient := storage.NewClient(apiCaller) 139 found, err := storageClient.ListStorageDetails() 140 c.Check(err, jc.ErrorIsNil) 141 c.Assert(found, gc.HasLen, 1) 142 expected := []params.StorageDetails{{ 143 StorageTag: "storage-db-dir-1000", 144 Status: params.EntityStatus{ 145 Status: "attached", 146 }, 147 Persistent: true, 148 }} 149 150 c.Assert(found, jc.DeepEquals, expected) 151 } 152 153 func (s *storageMockSuite) TestListStorageDetailsFacadeCallError(c *gc.C) { 154 msg := "facade failure" 155 apiCaller := basetesting.APICallerFunc( 156 func(objType string, 157 version int, 158 id, request string, 159 a, result interface{}, 160 ) error { 161 c.Check(objType, gc.Equals, "Storage") 162 c.Check(id, gc.Equals, "") 163 c.Check(request, gc.Equals, "ListStorageDetails") 164 165 return errors.New(msg) 166 }) 167 storageClient := storage.NewClient(apiCaller) 168 found, err := storageClient.ListStorageDetails() 169 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 170 c.Assert(found, gc.HasLen, 0) 171 } 172 173 func (s *storageMockSuite) TestListPools(c *gc.C) { 174 expected := []params.StoragePool{ 175 {Name: "name0", Provider: "type0"}, 176 {Name: "name1", Provider: "type1"}, 177 {Name: "name2", Provider: "type2"}, 178 } 179 want := len(expected) 180 181 apiCaller := basetesting.APICallerFunc( 182 func(objType string, 183 version int, 184 id, request string, 185 a, result interface{}, 186 ) error { 187 c.Check(objType, gc.Equals, "Storage") 188 c.Check(id, gc.Equals, "") 189 c.Check(request, gc.Equals, "ListPools") 190 191 args := a.(params.StoragePoolFilters) 192 c.Assert(args.Filters, gc.HasLen, 1) 193 c.Assert(args.Filters[0].Names, gc.HasLen, 2) 194 c.Assert(args.Filters[0].Providers, gc.HasLen, 1) 195 196 results := result.(*params.StoragePoolsResults) 197 pools := make([]params.StoragePool, want) 198 for i := 0; i < want; i++ { 199 pools[i] = params.StoragePool{ 200 Name: fmt.Sprintf("name%v", i), 201 Provider: fmt.Sprintf("type%v", i), 202 } 203 } 204 results.Results = []params.StoragePoolsResult{{ 205 Result: pools, 206 }} 207 208 return nil 209 }) 210 storageClient := storage.NewClient(apiCaller) 211 names := []string{"a", "b"} 212 types := []string{"1"} 213 found, err := storageClient.ListPools(types, names) 214 c.Assert(err, jc.ErrorIsNil) 215 c.Assert(found, gc.HasLen, want) 216 c.Assert(found, gc.DeepEquals, expected) 217 } 218 219 func (s *storageMockSuite) TestListPoolsFacadeCallError(c *gc.C) { 220 msg := "facade failure" 221 apiCaller := basetesting.APICallerFunc( 222 func(objType string, 223 version int, 224 id, request string, 225 a, result interface{}, 226 ) error { 227 c.Check(objType, gc.Equals, "Storage") 228 c.Check(id, gc.Equals, "") 229 c.Check(request, gc.Equals, "ListPools") 230 231 return errors.New(msg) 232 }) 233 storageClient := storage.NewClient(apiCaller) 234 found, err := storageClient.ListPools(nil, nil) 235 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 236 c.Assert(found, gc.HasLen, 0) 237 } 238 239 func (s *storageMockSuite) TestCreatePool(c *gc.C) { 240 var called bool 241 poolName := "poolName" 242 poolType := "poolType" 243 poolConfig := map[string]interface{}{ 244 "test": "one", 245 "pass": true, 246 } 247 apiCaller := basetesting.BestVersionCaller{ 248 APICallerFunc: basetesting.APICallerFunc( 249 func(objType string, 250 version int, 251 id, request string, 252 a, result interface{}, 253 ) error { 254 called = true 255 c.Check(objType, gc.Equals, "Storage") 256 c.Check(id, gc.Equals, "") 257 c.Check(request, gc.Equals, "CreatePool") 258 259 args, ok := a.(params.StoragePoolArgs) 260 c.Assert(ok, jc.IsTrue) 261 c.Assert(args.Pools, gc.HasLen, 1) 262 263 c.Assert(args.Pools[0].Name, gc.Equals, poolName) 264 c.Assert(args.Pools[0].Provider, gc.Equals, poolType) 265 c.Assert(args.Pools[0].Attrs, gc.DeepEquals, poolConfig) 266 results := result.(*params.ErrorResults) 267 268 results.Results = make([]params.ErrorResult, len(args.Pools)) 269 return nil 270 }, 271 ), 272 BestVersion: 5, 273 } 274 storageClient := storage.NewClient(apiCaller) 275 err := storageClient.CreatePool(poolName, poolType, poolConfig) 276 c.Assert(err, jc.ErrorIsNil) 277 c.Assert(called, jc.IsTrue) 278 } 279 280 func (s *storageMockSuite) TestCreatePoolFacadeCallError(c *gc.C) { 281 msg := "facade failure" 282 apiCaller := basetesting.APICallerFunc( 283 func(objType string, 284 version int, 285 id, request string, 286 a, result interface{}, 287 ) error { 288 c.Check(objType, gc.Equals, "Storage") 289 c.Check(id, gc.Equals, "") 290 c.Check(request, gc.Equals, "CreatePool") 291 292 return errors.New(msg) 293 }) 294 storageClient := storage.NewClient(apiCaller) 295 err := storageClient.CreatePool("", "", nil) 296 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 297 } 298 299 func (s *storageMockSuite) TestLegacyCreatePool(c *gc.C) { 300 var called bool 301 poolName := "poolName" 302 poolType := "poolType" 303 poolConfig := map[string]interface{}{ 304 "test": "one", 305 "pass": true, 306 } 307 308 apiCaller := basetesting.APICallerFunc( 309 func(objType string, 310 version int, 311 id, request string, 312 a, result interface{}, 313 ) error { 314 called = true 315 c.Check(objType, gc.Equals, "Storage") 316 c.Check(id, gc.Equals, "") 317 c.Check(request, gc.Equals, "CreatePool") 318 319 args, ok := a.(params.StoragePool) 320 c.Assert(ok, jc.IsTrue) 321 c.Assert(args.Name, gc.Equals, poolName) 322 c.Assert(args.Provider, gc.Equals, poolType) 323 c.Assert(args.Attrs, gc.DeepEquals, poolConfig) 324 325 return nil 326 }) 327 storageClient := storage.NewClient(apiCaller) 328 err := storageClient.CreatePool(poolName, poolType, poolConfig) 329 c.Assert(err, jc.ErrorIsNil) 330 c.Assert(called, jc.IsTrue) 331 } 332 333 func (s *storageMockSuite) TestLegacyCreatePoolFacadeCallError(c *gc.C) { 334 msg := "facade failure" 335 apiCaller := basetesting.APICallerFunc( 336 func(objType string, 337 version int, 338 id, request string, 339 a, result interface{}, 340 ) error { 341 c.Check(objType, gc.Equals, "Storage") 342 c.Check(id, gc.Equals, "") 343 c.Check(request, gc.Equals, "CreatePool") 344 345 return errors.New(msg) 346 }) 347 storageClient := storage.NewClient(apiCaller) 348 err := storageClient.CreatePool("", "", nil) 349 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 350 } 351 352 func (s *storageMockSuite) TestListVolumes(c *gc.C) { 353 var called bool 354 machines := []string{"0", "1"} 355 apiCaller := basetesting.APICallerFunc( 356 func(objType string, 357 version int, 358 id, request string, 359 a, result interface{}, 360 ) error { 361 called = true 362 c.Check(objType, gc.Equals, "Storage") 363 c.Check(id, gc.Equals, "") 364 c.Check(request, gc.Equals, "ListVolumes") 365 366 c.Assert(a, gc.FitsTypeOf, params.VolumeFilters{}) 367 args := a.(params.VolumeFilters) 368 c.Assert(args.Filters, gc.HasLen, 2) 369 c.Assert(args.Filters[0].Machines, jc.DeepEquals, []string{"machine-0"}) 370 c.Assert(args.Filters[1].Machines, jc.DeepEquals, []string{"machine-1"}) 371 372 c.Assert(result, gc.FitsTypeOf, ¶ms.VolumeDetailsListResults{}) 373 results := result.(*params.VolumeDetailsListResults) 374 375 details := params.VolumeDetails{ 376 VolumeTag: "volume-0", 377 MachineAttachments: map[string]params.VolumeAttachmentDetails{ 378 "machine-0": {}, 379 "machine-1": {}, 380 }, 381 } 382 results.Results = []params.VolumeDetailsListResult{{ 383 Result: []params.VolumeDetails{details}, 384 }, { 385 Result: []params.VolumeDetails{details}, 386 }} 387 return nil 388 }) 389 storageClient := storage.NewClient(apiCaller) 390 found, err := storageClient.ListVolumes(machines) 391 c.Assert(called, jc.IsTrue) 392 c.Assert(err, jc.ErrorIsNil) 393 c.Assert(found, gc.HasLen, 2) 394 for i := 0; i < 2; i++ { 395 c.Assert(found[i].Result, jc.DeepEquals, []params.VolumeDetails{{ 396 VolumeTag: "volume-0", 397 MachineAttachments: map[string]params.VolumeAttachmentDetails{ 398 "machine-0": {}, 399 "machine-1": {}, 400 }, 401 }}) 402 } 403 } 404 405 func (s *storageMockSuite) TestListVolumesEmptyFilter(c *gc.C) { 406 var called bool 407 tag := "ok" 408 apiCaller := basetesting.APICallerFunc( 409 func(objType string, 410 version int, 411 id, request string, 412 a, result interface{}, 413 ) error { 414 called = true 415 c.Check(objType, gc.Equals, "Storage") 416 c.Check(id, gc.Equals, "") 417 c.Check(request, gc.Equals, "ListVolumes") 418 419 c.Assert(a, gc.FitsTypeOf, params.VolumeFilters{}) 420 args := a.(params.VolumeFilters) 421 c.Assert(args.Filters, gc.HasLen, 1) 422 c.Assert(args.Filters[0].IsEmpty(), jc.IsTrue) 423 424 c.Assert(result, gc.FitsTypeOf, ¶ms.VolumeDetailsListResults{}) 425 results := result.(*params.VolumeDetailsListResults) 426 results.Results = []params.VolumeDetailsListResult{ 427 {Result: []params.VolumeDetails{{VolumeTag: tag}}}, 428 } 429 return nil 430 }, 431 ) 432 storageClient := storage.NewClient(apiCaller) 433 found, err := storageClient.ListVolumes(nil) 434 c.Assert(called, jc.IsTrue) 435 c.Assert(err, jc.ErrorIsNil) 436 c.Assert(found, gc.HasLen, 1) 437 c.Assert(found[0].Result, gc.HasLen, 1) 438 c.Assert(found[0].Result[0].VolumeTag, gc.Equals, tag) 439 } 440 441 func (s *storageMockSuite) TestListVolumesFacadeCallError(c *gc.C) { 442 msg := "facade failure" 443 apiCaller := basetesting.APICallerFunc( 444 func(objType string, 445 version int, 446 id, request string, 447 a, result interface{}, 448 ) error { 449 c.Check(objType, gc.Equals, "Storage") 450 c.Check(id, gc.Equals, "") 451 c.Check(request, gc.Equals, "ListVolumes") 452 453 return errors.New(msg) 454 }) 455 storageClient := storage.NewClient(apiCaller) 456 _, err := storageClient.ListVolumes(nil) 457 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 458 } 459 460 func (s *storageMockSuite) TestListFilesystems(c *gc.C) { 461 expected := params.FilesystemDetails{ 462 FilesystemTag: "filesystem-1", 463 Info: params.FilesystemInfo{ 464 FilesystemId: "fs-id", 465 Size: 4096, 466 }, 467 Status: params.EntityStatus{ 468 Status: "attached", 469 }, 470 MachineAttachments: map[string]params.FilesystemAttachmentDetails{ 471 "0": { 472 FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{ 473 MountPoint: "/mnt/kinabalu", 474 ReadOnly: false, 475 }, 476 }, 477 }, 478 } 479 480 apiCaller := basetesting.APICallerFunc( 481 func(objType string, 482 version int, 483 id, request string, 484 a, result interface{}, 485 ) error { 486 c.Check(objType, gc.Equals, "Storage") 487 c.Check(id, gc.Equals, "") 488 c.Check(request, gc.Equals, "ListFilesystems") 489 490 c.Assert(a, gc.FitsTypeOf, params.FilesystemFilters{}) 491 args := a.(params.FilesystemFilters) 492 c.Assert(args.Filters, jc.DeepEquals, []params.FilesystemFilter{{ 493 Machines: []string{"machine-1"}, 494 }, { 495 Machines: []string{"machine-2"}, 496 }}) 497 498 c.Assert(result, gc.FitsTypeOf, ¶ms.FilesystemDetailsListResults{}) 499 results := result.(*params.FilesystemDetailsListResults) 500 results.Results = []params.FilesystemDetailsListResult{{ 501 Result: []params.FilesystemDetails{expected}, 502 }, {}} 503 return nil 504 }, 505 ) 506 storageClient := storage.NewClient(apiCaller) 507 found, err := storageClient.ListFilesystems([]string{"1", "2"}) 508 c.Assert(err, jc.ErrorIsNil) 509 c.Assert(found, gc.HasLen, 2) 510 c.Assert(found[0].Result, jc.DeepEquals, []params.FilesystemDetails{expected}) 511 c.Assert(found[1].Result, jc.DeepEquals, []params.FilesystemDetails{}) 512 } 513 514 func (s *storageMockSuite) TestListFilesystemsEmptyFilter(c *gc.C) { 515 var called bool 516 apiCaller := basetesting.APICallerFunc( 517 func(objType string, 518 version int, 519 id, request string, 520 a, result interface{}, 521 ) error { 522 called = true 523 c.Check(objType, gc.Equals, "Storage") 524 c.Check(id, gc.Equals, "") 525 c.Check(request, gc.Equals, "ListFilesystems") 526 527 c.Assert(a, gc.FitsTypeOf, params.FilesystemFilters{}) 528 args := a.(params.FilesystemFilters) 529 c.Assert(args.Filters, gc.HasLen, 1) 530 c.Assert(args.Filters[0].IsEmpty(), jc.IsTrue) 531 532 c.Assert(result, gc.FitsTypeOf, ¶ms.FilesystemDetailsListResults{}) 533 results := result.(*params.FilesystemDetailsListResults) 534 results.Results = []params.FilesystemDetailsListResult{{}} 535 536 return nil 537 }, 538 ) 539 storageClient := storage.NewClient(apiCaller) 540 _, err := storageClient.ListFilesystems(nil) 541 c.Assert(called, jc.IsTrue) 542 c.Assert(err, jc.ErrorIsNil) 543 } 544 545 func (s *storageMockSuite) TestListFilesystemsFacadeCallError(c *gc.C) { 546 msg := "facade failure" 547 apiCaller := basetesting.APICallerFunc( 548 func(objType string, 549 version int, 550 id, request string, 551 a, result interface{}, 552 ) error { 553 c.Check(objType, gc.Equals, "Storage") 554 c.Check(id, gc.Equals, "") 555 c.Check(request, gc.Equals, "ListFilesystems") 556 557 return errors.New(msg) 558 }) 559 storageClient := storage.NewClient(apiCaller) 560 _, err := storageClient.ListFilesystems(nil) 561 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 562 } 563 564 func (s *storageMockSuite) TestAddToUnit(c *gc.C) { 565 size := uint64(42) 566 cons := params.StorageConstraints{ 567 Pool: "value", 568 Size: &size, 569 } 570 571 errOut := "error" 572 unitStorages := []params.StorageAddParams{ 573 {UnitTag: "u-a", StorageName: "one", Constraints: cons}, 574 {UnitTag: "u-b", StorageName: errOut, Constraints: cons}, 575 {UnitTag: "u-b", StorageName: "nil-constraints"}, 576 } 577 578 storageN := 3 579 expectedError := common.ServerError(errors.NotValidf("storage directive")) 580 expectedDetails := ¶ms.AddStorageDetails{[]string{"a/0", "b/1"}} 581 one := func(u, s string, attrs params.StorageConstraints) params.AddStorageResult { 582 result := params.AddStorageResult{} 583 if s == errOut { 584 result.Error = expectedError 585 } else { 586 result.Result = expectedDetails 587 } 588 return result 589 } 590 591 apiCaller := basetesting.APICallerFunc( 592 func(objType string, 593 version int, 594 id, request string, 595 a, result interface{}, 596 ) error { 597 c.Check(objType, gc.Equals, "Storage") 598 c.Check(id, gc.Equals, "") 599 c.Check(request, gc.Equals, "AddToUnit") 600 601 args, ok := a.(params.StoragesAddParams) 602 c.Assert(ok, jc.IsTrue) 603 c.Assert(args.Storages, gc.HasLen, storageN) 604 c.Assert(args.Storages, gc.DeepEquals, unitStorages) 605 606 if results, k := result.(*params.AddStorageResults); k { 607 out := []params.AddStorageResult{} 608 for _, s := range args.Storages { 609 out = append(out, one(s.UnitTag, s.StorageName, s.Constraints)) 610 } 611 results.Results = out 612 } 613 614 return nil 615 }) 616 storageClient := storage.NewClient(apiCaller) 617 r, err := storageClient.AddToUnit(unitStorages) 618 c.Assert(err, jc.ErrorIsNil) 619 c.Assert(r, gc.HasLen, storageN) 620 expected := []params.AddStorageResult{ 621 {Result: expectedDetails}, 622 {Error: expectedError}, 623 {Result: expectedDetails}, 624 } 625 c.Assert(r, jc.SameContents, expected) 626 } 627 628 func (s *storageMockSuite) TestAddToUnitFacadeCallError(c *gc.C) { 629 unitStorages := []params.StorageAddParams{ 630 {UnitTag: "u-a", StorageName: "one"}, 631 } 632 633 msg := "facade failure" 634 apiCaller := basetesting.APICallerFunc( 635 func(objType string, 636 version int, 637 id, request string, 638 a, result interface{}, 639 ) error { 640 c.Check(objType, gc.Equals, "Storage") 641 c.Check(id, gc.Equals, "") 642 c.Check(request, gc.Equals, "AddToUnit") 643 return errors.New(msg) 644 }) 645 storageClient := storage.NewClient(apiCaller) 646 found, err := storageClient.AddToUnit(unitStorages) 647 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 648 c.Assert(found, gc.HasLen, 0) 649 } 650 651 func (s *storageMockSuite) TestRemove(c *gc.C) { 652 apiCaller := basetesting.BestVersionCaller{ 653 APICallerFunc: basetesting.APICallerFunc( 654 func(objType string, 655 version int, 656 id, request string, 657 a, result interface{}, 658 ) error { 659 c.Check(objType, gc.Equals, "Storage") 660 c.Check(id, gc.Equals, "") 661 c.Check(request, gc.Equals, "Remove") 662 c.Check(a, jc.DeepEquals, params.RemoveStorage{[]params.RemoveStorageInstance{ 663 {Tag: "storage-foo-0", DestroyAttachments: false, DestroyStorage: false}, 664 {Tag: "storage-bar-1", DestroyAttachments: false, DestroyStorage: false}, 665 }}) 666 c.Assert(result, gc.FitsTypeOf, ¶ms.ErrorResults{}) 667 results := result.(*params.ErrorResults) 668 results.Results = []params.ErrorResult{ 669 {}, 670 {Error: ¶ms.Error{Message: "baz"}}, 671 } 672 return nil 673 }, 674 ), 675 BestVersion: 4, 676 } 677 client := storage.NewClient(apiCaller) 678 results, err := client.Remove([]string{"foo/0", "bar/1"}, false, false) 679 c.Check(err, jc.ErrorIsNil) 680 c.Assert(results, gc.HasLen, 2) 681 c.Assert(results[0].Error, gc.IsNil) 682 c.Assert(results[1].Error, jc.DeepEquals, ¶ms.Error{Message: "baz"}) 683 } 684 685 func (s *storageMockSuite) TestRemoveDestroyAttachments(c *gc.C) { 686 apiCaller := basetesting.BestVersionCaller{ 687 APICallerFunc: basetesting.APICallerFunc( 688 func(objType string, 689 version int, 690 id, request string, 691 a, result interface{}, 692 ) error { 693 c.Check(a, jc.DeepEquals, params.RemoveStorage{[]params.RemoveStorageInstance{{ 694 Tag: "storage-foo-0", 695 DestroyAttachments: true, 696 DestroyStorage: true, 697 }}}) 698 results := result.(*params.ErrorResults) 699 results.Results = []params.ErrorResult{{}} 700 return nil 701 }, 702 ), 703 BestVersion: 4, 704 } 705 client := storage.NewClient(apiCaller) 706 results, err := client.Remove([]string{"foo/0"}, true, true) 707 c.Check(err, jc.ErrorIsNil) 708 c.Assert(results, gc.HasLen, 1) 709 c.Assert(results[0].Error, gc.IsNil) 710 } 711 712 func (s *storageMockSuite) TestRemoveDestroyV3(c *gc.C) { 713 apiCaller := basetesting.BestVersionCaller{ 714 APICallerFunc: basetesting.APICallerFunc( 715 func(objType string, 716 version int, 717 id, request string, 718 a, result interface{}, 719 ) error { 720 c.Check(objType, gc.Equals, "Storage") 721 c.Check(id, gc.Equals, "") 722 c.Check(request, gc.Equals, "Destroy") 723 c.Check(a, jc.DeepEquals, params.Entities{[]params.Entity{ 724 {Tag: "storage-foo-0"}, 725 }}) 726 results := result.(*params.ErrorResults) 727 results.Results = []params.ErrorResult{{}} 728 return nil 729 }, 730 ), 731 BestVersion: 3, 732 } 733 client := storage.NewClient(apiCaller) 734 results, err := client.Remove([]string{"foo/0"}, true, true) 735 c.Check(err, jc.ErrorIsNil) 736 c.Assert(results, gc.HasLen, 1) 737 c.Assert(results[0].Error, gc.IsNil) 738 } 739 740 func (s *storageMockSuite) TestRemoveDestroyV3NoDestroyStorage(c *gc.C) { 741 apiCaller := basetesting.BestVersionCaller{BestVersion: 3} 742 client := storage.NewClient(apiCaller) 743 _, err := client.Remove([]string{"foo/0"}, true, false) 744 c.Check(err, gc.ErrorMatches, "this juju controller does not support non-destructive removal of storage") 745 } 746 747 func (s *storageMockSuite) TestRemoveInvalidStorageId(c *gc.C) { 748 client := storage.NewClient(basetesting.APICallerFunc( 749 func(_ string, _ int, _, _ string, _, _ interface{}) error { 750 return nil 751 }, 752 )) 753 _, err := client.Remove([]string{"foo/bar"}, false, false) 754 c.Check(err, gc.ErrorMatches, `storage ID "foo/bar" not valid`) 755 } 756 757 func (s *storageMockSuite) TestDetach(c *gc.C) { 758 apiCaller := basetesting.APICallerFunc( 759 func(objType string, 760 version int, 761 id, request string, 762 a, result interface{}, 763 ) error { 764 c.Check(objType, gc.Equals, "Storage") 765 c.Check(id, gc.Equals, "") 766 c.Check(request, gc.Equals, "Detach") 767 c.Check(a, jc.DeepEquals, params.StorageAttachmentIds{[]params.StorageAttachmentId{ 768 {StorageTag: "storage-foo-0"}, 769 {StorageTag: "storage-bar-1"}, 770 }}) 771 c.Assert(result, gc.FitsTypeOf, ¶ms.ErrorResults{}) 772 results := result.(*params.ErrorResults) 773 results.Results = []params.ErrorResult{ 774 {}, 775 {Error: ¶ms.Error{Message: "baz"}}, 776 } 777 return nil 778 }, 779 ) 780 client := storage.NewClient(apiCaller) 781 results, err := client.Detach([]string{"foo/0", "bar/1"}) 782 c.Check(err, jc.ErrorIsNil) 783 c.Assert(results, gc.HasLen, 2) 784 c.Assert(results[0].Error, gc.IsNil) 785 c.Assert(results[1].Error, jc.DeepEquals, ¶ms.Error{Message: "baz"}) 786 } 787 788 func (s *storageMockSuite) TestDetachArityMismatch(c *gc.C) { 789 apiCaller := basetesting.APICallerFunc( 790 func(objType string, version int, id, request string, a, result interface{}) error { 791 results := result.(*params.ErrorResults) 792 results.Results = []params.ErrorResult{{}, {}, {}} 793 return nil 794 }, 795 ) 796 client := storage.NewClient(apiCaller) 797 _, err := client.Detach([]string{"foo/0", "bar/1"}) 798 c.Check(err, gc.ErrorMatches, `expected 2 result\(s\), got 3`) 799 } 800 801 func (s *storageMockSuite) TestAttach(c *gc.C) { 802 apiCaller := basetesting.APICallerFunc( 803 func(objType string, 804 version int, 805 id, request string, 806 a, result interface{}, 807 ) error { 808 c.Check(objType, gc.Equals, "Storage") 809 c.Check(id, gc.Equals, "") 810 c.Check(request, gc.Equals, "Attach") 811 c.Check(a, jc.DeepEquals, params.StorageAttachmentIds{[]params.StorageAttachmentId{ 812 { 813 StorageTag: "storage-bar-1", 814 UnitTag: "unit-foo-0", 815 }, 816 { 817 StorageTag: "storage-baz-2", 818 UnitTag: "unit-foo-0", 819 }, 820 }}) 821 c.Assert(result, gc.FitsTypeOf, ¶ms.ErrorResults{}) 822 results := result.(*params.ErrorResults) 823 results.Results = []params.ErrorResult{ 824 {}, 825 {Error: ¶ms.Error{Message: "qux"}}, 826 } 827 return nil 828 }, 829 ) 830 client := storage.NewClient(apiCaller) 831 results, err := client.Attach("foo/0", []string{"bar/1", "baz/2"}) 832 c.Check(err, jc.ErrorIsNil) 833 c.Assert(results, gc.HasLen, 2) 834 c.Assert(results[0].Error, gc.IsNil) 835 c.Assert(results[1].Error, jc.DeepEquals, ¶ms.Error{Message: "qux"}) 836 } 837 838 func (s *storageMockSuite) TestAttachArityMismatch(c *gc.C) { 839 apiCaller := basetesting.APICallerFunc( 840 func(objType string, version int, id, request string, a, result interface{}) error { 841 results := result.(*params.ErrorResults) 842 results.Results = []params.ErrorResult{{}, {}, {}} 843 return nil 844 }, 845 ) 846 client := storage.NewClient(apiCaller) 847 _, err := client.Attach("foo/0", []string{"bar/1", "baz/2"}) 848 c.Check(err, gc.ErrorMatches, `expected 2 result\(s\), got 3`) 849 } 850 851 func (s *storageMockSuite) TestImport(c *gc.C) { 852 apiCaller := basetesting.APICallerFunc( 853 func(objType string, 854 version int, 855 id, request string, 856 a, result interface{}, 857 ) error { 858 c.Check(objType, gc.Equals, "Storage") 859 c.Check(id, gc.Equals, "") 860 c.Check(request, gc.Equals, "Import") 861 c.Check(a, jc.DeepEquals, params.BulkImportStorageParams{[]params.ImportStorageParams{{ 862 Kind: params.StorageKindBlock, 863 Pool: "foo", 864 ProviderId: "bar", 865 StorageName: "baz", 866 }}}) 867 c.Assert(result, gc.FitsTypeOf, ¶ms.ImportStorageResults{}) 868 results := result.(*params.ImportStorageResults) 869 results.Results = []params.ImportStorageResult{{ 870 Result: ¶ms.ImportStorageDetails{ 871 StorageTag: "storage-qux-0", 872 }, 873 }} 874 return nil 875 }, 876 ) 877 client := storage.NewClient(apiCaller) 878 storageTag, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz") 879 c.Assert(err, jc.ErrorIsNil) 880 c.Assert(storageTag, gc.Equals, names.NewStorageTag("qux/0")) 881 } 882 883 func (s *storageMockSuite) TestImportError(c *gc.C) { 884 apiCaller := basetesting.APICallerFunc( 885 func(objType string, version int, id, request string, a, result interface{}) error { 886 results := result.(*params.ImportStorageResults) 887 results.Results = []params.ImportStorageResult{{ 888 Error: ¶ms.Error{Message: "qux"}, 889 }} 890 return nil 891 }, 892 ) 893 client := storage.NewClient(apiCaller) 894 _, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz") 895 c.Check(err, gc.ErrorMatches, "qux") 896 } 897 898 func (s *storageMockSuite) TestImportArityMismatch(c *gc.C) { 899 apiCaller := basetesting.APICallerFunc( 900 func(objType string, version int, id, request string, a, result interface{}) error { 901 results := result.(*params.ImportStorageResults) 902 results.Results = []params.ImportStorageResult{{}, {}} 903 return nil 904 }, 905 ) 906 client := storage.NewClient(apiCaller) 907 _, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz") 908 c.Check(err, gc.ErrorMatches, `expected 1 result, got 2`) 909 } 910 911 func (s *storageMockSuite) TestRemovePool(c *gc.C) { 912 var called bool 913 poolName := "poolName" 914 915 apiCaller := basetesting.APICallerFunc( 916 func(objType string, 917 version int, 918 id, request string, 919 a, result interface{}, 920 ) error { 921 called = true 922 c.Check(objType, gc.Equals, "Storage") 923 c.Check(id, gc.Equals, "") 924 c.Check(request, gc.Equals, "RemovePool") 925 926 args, ok := a.(params.StoragePoolDeleteArgs) 927 c.Assert(ok, jc.IsTrue) 928 c.Assert(args.Pools, gc.HasLen, 1) 929 c.Assert(args.Pools[0].Name, gc.Equals, poolName) 930 931 results := result.(*params.ErrorResults) 932 results.Results = make([]params.ErrorResult, len(args.Pools)) 933 934 return nil 935 }) 936 storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller}) 937 err := storageClient.RemovePool(poolName) 938 c.Assert(err, jc.ErrorIsNil) 939 c.Assert(called, jc.IsTrue) 940 } 941 942 func (s *storageMockSuite) TestRemovePoolFacadeCallError(c *gc.C) { 943 msg := "facade failure" 944 apiCaller := basetesting.APICallerFunc( 945 func(objType string, 946 version int, 947 id, request string, 948 a, result interface{}, 949 ) error { 950 c.Check(objType, gc.Equals, "Storage") 951 c.Check(id, gc.Equals, "") 952 c.Check(request, gc.Equals, "RemovePool") 953 954 args, ok := a.(params.StoragePoolDeleteArgs) 955 c.Assert(ok, jc.IsTrue) 956 c.Assert(args.Pools, gc.HasLen, 1) 957 c.Assert(args.Pools[0].Name, gc.Equals, "") 958 959 results := result.(*params.ErrorResults) 960 results.Results = make([]params.ErrorResult, len(args.Pools)) 961 return errors.New(msg) 962 }) 963 storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller}) 964 err := storageClient.RemovePool("") 965 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 966 } 967 968 func (s *storageMockSuite) TestUpdatePool(c *gc.C) { 969 var called bool 970 poolName := "poolName" 971 providerType := "loop" 972 poolConfig := map[string]interface{}{ 973 "test": "one", 974 "pass": true, 975 } 976 977 apiCaller := basetesting.APICallerFunc( 978 func(objType string, 979 version int, 980 id, request string, 981 a, result interface{}, 982 ) error { 983 called = true 984 c.Check(objType, gc.Equals, "Storage") 985 c.Check(id, gc.Equals, "") 986 c.Check(request, gc.Equals, "UpdatePool") 987 988 args, ok := a.(params.StoragePoolArgs) 989 c.Assert(ok, jc.IsTrue) 990 c.Assert(args.Pools, gc.HasLen, 1) 991 c.Assert(args.Pools[0].Name, gc.Equals, poolName) 992 c.Assert(args.Pools[0].Provider, gc.Equals, providerType) 993 c.Assert(args.Pools[0].Attrs, gc.DeepEquals, poolConfig) 994 995 results := result.(*params.ErrorResults) 996 results.Results = make([]params.ErrorResult, len(args.Pools)) 997 998 return nil 999 }) 1000 storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller}) 1001 err := storageClient.UpdatePool(poolName, providerType, poolConfig) 1002 c.Assert(err, jc.ErrorIsNil) 1003 c.Assert(called, jc.IsTrue) 1004 } 1005 1006 func (s *storageMockSuite) TestUpdatePoolFacadeCallError(c *gc.C) { 1007 msg := "facade failure" 1008 apiCaller := basetesting.APICallerFunc( 1009 func(objType string, 1010 version int, 1011 id, request string, 1012 a, result interface{}, 1013 ) error { 1014 c.Check(objType, gc.Equals, "Storage") 1015 c.Check(id, gc.Equals, "") 1016 c.Check(request, gc.Equals, "UpdatePool") 1017 1018 return errors.New(msg) 1019 }) 1020 storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller}) 1021 err := storageClient.UpdatePool("", "", nil) 1022 c.Assert(errors.Cause(err), gc.ErrorMatches, msg) 1023 }