github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/vsphere/internal/vsphereclient/client_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package vsphereclient 5 6 import ( 7 "bytes" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/http/httptest" 12 "net/url" 13 14 "github.com/juju/loggo" 15 "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/vmware/govmomi" 18 "github.com/vmware/govmomi/session" 19 "github.com/vmware/govmomi/vim25" 20 "github.com/vmware/govmomi/vim25/methods" 21 "github.com/vmware/govmomi/vim25/mo" 22 "github.com/vmware/govmomi/vim25/soap" 23 "github.com/vmware/govmomi/vim25/types" 24 "github.com/vmware/govmomi/vim25/xml" 25 "golang.org/x/net/context" 26 gc "gopkg.in/check.v1" 27 ) 28 29 type clientSuite struct { 30 testing.IsolationSuite 31 32 server *httptest.Server 33 serviceContent types.ServiceContent 34 roundTripper mockRoundTripper 35 uploadRequests []*http.Request 36 onImageUpload func(*http.Request) 37 } 38 39 var _ = gc.Suite(&clientSuite{}) 40 41 func (s *clientSuite) SetUpTest(c *gc.C) { 42 s.IsolationSuite.SetUpTest(c) 43 s.serviceContent = types.ServiceContent{ 44 RootFolder: types.ManagedObjectReference{ 45 Type: "Folder", 46 Value: "FakeRootFolder", 47 }, 48 OvfManager: &types.ManagedObjectReference{ 49 Type: "OvfManager", 50 Value: "FakeOvfManager", 51 }, 52 SessionManager: &types.ManagedObjectReference{ 53 Type: "SessionManager", 54 Value: "FakeSessionManager", 55 }, 56 FileManager: &types.ManagedObjectReference{ 57 Type: "FileManager", 58 Value: "FakeFileManager", 59 }, 60 VirtualDiskManager: &types.ManagedObjectReference{ 61 Type: "VirtualDiskManager", 62 Value: "FakeVirtualDiskManager", 63 }, 64 PropertyCollector: types.ManagedObjectReference{ 65 Type: "PropertyCollector", 66 Value: "FakePropertyCollector", 67 }, 68 SearchIndex: &types.ManagedObjectReference{ 69 Type: "SearchIndex", 70 Value: "FakeSearchIndex", 71 }, 72 } 73 s.roundTripper = mockRoundTripper{ 74 collectors: make(map[string]*collector), 75 taskResult: make(map[types.ManagedObjectReference]types.AnyType), 76 taskError: make(map[types.ManagedObjectReference]*types.LocalizedMethodFault), 77 } 78 s.roundTripper.contents = map[string][]types.ObjectContent{ 79 "FakeRootFolder": {{ 80 Obj: types.ManagedObjectReference{ 81 Type: "Datacenter", 82 Value: "FakeDatacenter", 83 }, 84 PropSet: []types.DynamicProperty{ 85 {Name: "name", Val: "dc0"}, 86 }, 87 }}, 88 "FakeDatacenter": {{ 89 Obj: types.ManagedObjectReference{ 90 Type: "Datacenter", 91 Value: "FakeDatacenter", 92 }, 93 PropSet: []types.DynamicProperty{ 94 {Name: "name", Val: "dc0"}, 95 {Name: "hostFolder", Val: types.ManagedObjectReference{ 96 Type: "Folder", 97 Value: "FakeHostFolder", 98 }}, 99 {Name: "vmFolder", Val: types.ManagedObjectReference{ 100 Type: "Folder", 101 Value: "FakeVmFolder", 102 }}, 103 {Name: "datastoreFolder", Val: types.ManagedObjectReference{ 104 Type: "Folder", 105 Value: "FakeDatastoreFolder", 106 }}, 107 }, 108 }, { 109 Obj: types.ManagedObjectReference{ 110 Type: "Folder", 111 Value: "FakeVmFolder", 112 }, 113 PropSet: []types.DynamicProperty{{Name: "name", Val: "vm"}}, 114 }, { 115 Obj: types.ManagedObjectReference{ 116 Type: "Folder", 117 Value: "FakeHostFolder", 118 }, 119 PropSet: []types.DynamicProperty{{Name: "name", Val: "vm"}}, 120 }}, 121 "FakeHostFolder": {{ 122 Obj: types.ManagedObjectReference{ 123 Type: "ComputeResource", 124 Value: "z0", 125 }, 126 PropSet: []types.DynamicProperty{ 127 {Name: "resourcePool", Val: types.ManagedObjectReference{ 128 Type: "ResourcePool", 129 Value: "FakeResourcePool1", 130 }}, 131 {Name: "datastore", Val: []types.ManagedObjectReference{{ 132 Type: "Datastore", 133 Value: "FakeDatastore1", 134 }}}, 135 {Name: "name", Val: "z0"}, 136 }, 137 }, { 138 Obj: types.ManagedObjectReference{ 139 Type: "ComputeResource", 140 Value: "z1", 141 }, 142 PropSet: []types.DynamicProperty{ 143 {Name: "resourcePool", Val: types.ManagedObjectReference{ 144 Type: "ResourcePool", 145 Value: "FakeResourcePool2", 146 }}, 147 {Name: "datastore", Val: []types.ManagedObjectReference{{ 148 Type: "Datastore", 149 Value: "FakeDatastore2", 150 }}}, 151 {Name: "name", Val: "z1"}, 152 }, 153 }}, 154 "FakeDatastoreFolder": {{ 155 Obj: types.ManagedObjectReference{ 156 Type: "Datastore", 157 Value: "FakeDatastore1", 158 }, 159 PropSet: []types.DynamicProperty{ 160 {Name: "name", Val: "datastore1"}, 161 {Name: "summary.accessible", Val: false}, 162 }, 163 }, { 164 Obj: types.ManagedObjectReference{ 165 Type: "Datastore", 166 Value: "FakeDatastore2", 167 }, 168 PropSet: []types.DynamicProperty{ 169 {Name: "name", Val: "datastore2"}, 170 {Name: "summary.accessible", Val: true}, 171 }, 172 }}, 173 "FakeVmFolder": {{ 174 Obj: types.ManagedObjectReference{ 175 Type: "Folder", 176 Value: "FakeControllerVmFolder", 177 }, 178 PropSet: []types.DynamicProperty{ 179 {Name: "name", Val: "foo"}, 180 }, 181 }}, 182 "FakeControllerVmFolder": {{ 183 Obj: types.ManagedObjectReference{ 184 Type: "Folder", 185 Value: "FakeModelVmFolder", 186 }, 187 PropSet: []types.DynamicProperty{ 188 {Name: "name", Val: "bar"}, 189 }, 190 }}, 191 "FakeModelVmFolder": {{ 192 Obj: types.ManagedObjectReference{ 193 Type: "VirtualMachine", 194 Value: "FakeVm0", 195 }, 196 PropSet: []types.DynamicProperty{ 197 {Name: "name", Val: "vm-0"}, 198 }, 199 }, { 200 Obj: types.ManagedObjectReference{ 201 Type: "VirtualMachine", 202 Value: "FakeVm1", 203 }, 204 PropSet: []types.DynamicProperty{ 205 {Name: "name", Val: "vm-1"}, 206 }, 207 }}, 208 "FakeVm0": {{ 209 Obj: types.ManagedObjectReference{ 210 Type: "VirtualMachine", 211 Value: "FakeVm0", 212 }, 213 PropSet: []types.DynamicProperty{ 214 {Name: "name", Val: "vm-0"}, 215 {Name: "runtime.powerState", Val: "poweredOff"}, 216 { 217 Name: "config.hardware.device", 218 Val: []types.BaseVirtualDevice{ 219 &types.VirtualDisk{ 220 VirtualDevice: types.VirtualDevice{ 221 Backing: &types.VirtualDiskFlatVer2BackingInfo{ 222 VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ 223 FileName: "disk.vmdk", 224 }, 225 }, 226 }, 227 }, 228 }, 229 }, 230 { 231 Name: "resourcePool", 232 Val: types.ManagedObjectReference{ 233 Type: "ResourcePool", 234 Value: "FakeResourcePool0", 235 }, 236 }, 237 }, 238 }}, 239 "FakeVm1": {{ 240 Obj: types.ManagedObjectReference{ 241 Type: "VirtualMachine", 242 Value: "FakeVm1", 243 }, 244 PropSet: []types.DynamicProperty{ 245 {Name: "name", Val: "vm-1"}, 246 {Name: "runtime.powerState", Val: "poweredOn"}, 247 { 248 Name: "config.hardware.device", 249 Val: []types.BaseVirtualDevice{ 250 &types.VirtualDisk{ 251 VirtualDevice: types.VirtualDevice{ 252 Backing: &types.VirtualDiskFlatVer2BackingInfo{ 253 VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{ 254 FileName: "disk.vmdk", 255 }, 256 }, 257 }, 258 CapacityInKB: 1024 * 1024 * 10, // 10 GiB 259 }, 260 }, 261 }, 262 { 263 Name: "resourcePool", 264 Val: types.ManagedObjectReference{ 265 Type: "ResourcePool", 266 Value: "FakeResourcePool1", 267 }, 268 }, 269 }, 270 }}, 271 "FakeDatastore1": {{ 272 Obj: types.ManagedObjectReference{ 273 Type: "Datastore", 274 Value: "FakeDatastore1", 275 }, 276 PropSet: []types.DynamicProperty{ 277 {Name: "name", Val: "datastore1"}, 278 {Name: "summary.accessible", Val: false}, 279 }, 280 }}, 281 "FakeDatastore2": {{ 282 Obj: types.ManagedObjectReference{ 283 Type: "Datastore", 284 Value: "FakeDatastore2", 285 }, 286 PropSet: []types.DynamicProperty{ 287 {Name: "name", Val: "datastore2"}, 288 {Name: "summary.accessible", Val: true}, 289 }, 290 }}, 291 "network-0": {{ 292 Obj: types.ManagedObjectReference{ 293 Type: "Network", 294 Value: "network-0", 295 }, 296 PropSet: []types.DynamicProperty{ 297 {Name: "name", Val: "VM Network"}, 298 }, 299 }}, 300 "network-1": {{ 301 Obj: types.ManagedObjectReference{ 302 Type: "Network", 303 Value: "network-1", 304 }, 305 PropSet: []types.DynamicProperty{ 306 {Name: "name", Val: "zing"}, 307 }, 308 }}, 309 "onetwork-0": {{ 310 Obj: types.ManagedObjectReference{ 311 Type: "OpaqueNetwork", 312 Value: "onetwork-0", 313 }, 314 PropSet: []types.DynamicProperty{ 315 {Name: "name", Val: "arpa"}, 316 }, 317 }}, 318 "dvportgroup-0": {{ 319 Obj: types.ManagedObjectReference{ 320 Type: "DistributedVirtualPortgroup", 321 Value: "dvportgroup-0", 322 }, 323 PropSet: []types.DynamicProperty{ 324 {Name: "name", Val: "yoink"}, 325 {Name: "config.key", Val: "hole"}, 326 { 327 Name: "config.distributedVirtualSwitch", 328 Val: types.ManagedObjectReference{ 329 Type: "DistributedVirtualSwitch", 330 Value: "dvs-0", 331 }, 332 }, 333 }, 334 }}, 335 "dvs-0": {{ 336 Obj: types.ManagedObjectReference{ 337 Type: "DistributedVirtualSwitch", 338 Value: "dvs-0", 339 }, 340 PropSet: []types.DynamicProperty{ 341 {Name: "uuid", Val: "yup"}, 342 }, 343 }}, 344 } 345 346 s.roundTripper.importVAppResult = types.ManagedObjectReference{ 347 Type: "VirtualMachine", 348 Value: "FakeVm0", 349 } 350 s.roundTripper.taskResult[searchDatastoreTask] = types.HostDatastoreBrowserSearchResults{} 351 s.roundTripper.taskResult[cloneVMTask] = types.ManagedObjectReference{ 352 Type: "VirtualMachine", 353 Value: "FakeVm1", 354 } 355 356 // Create an HTTP server to receive image uploads. 357 s.uploadRequests = nil 358 s.onImageUpload = nil 359 s.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 360 var buf bytes.Buffer 361 io.Copy(&buf, r.Body) 362 rcopy := *r 363 rcopy.Body = ioutil.NopCloser(&buf) 364 s.uploadRequests = append(s.uploadRequests, &rcopy) 365 if s.onImageUpload != nil { 366 s.onImageUpload(r) 367 } 368 })) 369 s.AddCleanup(func(*gc.C) { 370 s.server.Close() 371 }) 372 s.roundTripper.serverURL = s.server.URL 373 } 374 375 func (s *clientSuite) newFakeClient(roundTripper soap.RoundTripper, dc string) *Client { 376 soapURL, err := url.Parse(s.server.URL + "/soap") 377 if err != nil { 378 panic(err) 379 } 380 381 vimClient := &vim25.Client{ 382 Client: soap.NewClient(soapURL, true), 383 ServiceContent: s.serviceContent, 384 RoundTripper: roundTripper, 385 } 386 return &Client{ 387 client: &govmomi.Client{ 388 Client: vimClient, 389 SessionManager: session.NewManager(vimClient), 390 }, 391 datacenter: dc, 392 logger: loggo.GetLogger("vsphereclient"), 393 } 394 } 395 396 func (s *clientSuite) TestDial(c *gc.C) { 397 mux := http.NewServeMux() 398 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 399 e := xml.NewEncoder(w) 400 e.Encode(soap.Envelope{Body: methods.RetrieveServiceContentBody{ 401 Res: &types.RetrieveServiceContentResponse{s.serviceContent}, 402 }}) 403 e.Flush() 404 }) 405 server := httptest.NewServer(mux) 406 defer server.Close() 407 408 url, err := url.Parse(server.URL) 409 c.Assert(err, jc.ErrorIsNil) 410 411 ctx := context.Background() 412 client, err := Dial(ctx, url, "dc", loggo.GetLogger("vsphereclient")) 413 c.Assert(err, jc.ErrorIsNil) 414 c.Assert(client, gc.NotNil) 415 } 416 417 func (s *clientSuite) TestClose(c *gc.C) { 418 client := s.newFakeClient(&s.roundTripper, "dc0") 419 err := client.Close(context.Background()) 420 c.Assert(err, jc.ErrorIsNil) 421 s.roundTripper.CheckCallNames(c, "Logout") 422 } 423 424 func (s *clientSuite) TestComputeResources(c *gc.C) { 425 client := s.newFakeClient(&s.roundTripper, "dc0") 426 result, err := client.ComputeResources(context.Background()) 427 c.Assert(err, jc.ErrorIsNil) 428 429 s.roundTripper.CheckCalls(c, []testing.StubCall{ 430 retrievePropertiesStubCall("FakeRootFolder"), 431 retrievePropertiesStubCall("FakeRootFolder"), 432 retrievePropertiesStubCall("FakeDatacenter"), 433 retrievePropertiesStubCall("FakeHostFolder"), 434 }) 435 436 c.Assert(result, gc.HasLen, 2) 437 c.Assert(result[0].Name, gc.Equals, "z0") 438 c.Assert(result[1].Name, gc.Equals, "z1") 439 } 440 441 func (s *clientSuite) TestDestroyVMFolder(c *gc.C) { 442 client := s.newFakeClient(&s.roundTripper, "dc0") 443 err := client.DestroyVMFolder(context.Background(), "foo") 444 c.Assert(err, jc.ErrorIsNil) 445 446 s.roundTripper.CheckCalls(c, []testing.StubCall{ 447 retrievePropertiesStubCall("FakeRootFolder"), 448 retrievePropertiesStubCall("FakeRootFolder"), 449 retrievePropertiesStubCall("FakeDatacenter"), 450 retrievePropertiesStubCall("FakeRootFolder"), 451 retrievePropertiesStubCall("FakeDatacenter"), 452 retrievePropertiesStubCall("FakeVmFolder"), 453 retrievePropertiesStubCall("FakeHostFolder"), 454 {"Destroy_Task", nil}, 455 {"CreatePropertyCollector", nil}, 456 {"CreateFilter", nil}, 457 {"WaitForUpdatesEx", nil}, 458 }) 459 } 460 461 func (s *clientSuite) TestDestroyVMFolderRace(c *gc.C) { 462 s.roundTripper.taskError[destroyTask] = &types.LocalizedMethodFault{ 463 Fault: &types.ManagedObjectNotFound{}, 464 } 465 client := s.newFakeClient(&s.roundTripper, "dc0") 466 err := client.DestroyVMFolder(context.Background(), "foo") 467 c.Assert(err, jc.ErrorIsNil) 468 } 469 470 func (s *clientSuite) TestEnsureVMFolder(c *gc.C) { 471 client := s.newFakeClient(&s.roundTripper, "dc0") 472 folder, err := client.EnsureVMFolder(context.Background(), "foo/bar") 473 c.Assert(err, jc.ErrorIsNil) 474 c.Assert(folder, gc.NotNil) 475 476 s.roundTripper.CheckCalls(c, []testing.StubCall{ 477 retrievePropertiesStubCall("FakeRootFolder"), 478 retrievePropertiesStubCall("FakeRootFolder"), 479 retrievePropertiesStubCall("FakeDatacenter"), 480 {"CreateFolder", nil}, 481 {"CreateFolder", nil}, 482 }) 483 } 484 485 func (s *clientSuite) TestMoveVMFolderInto(c *gc.C) { 486 client := s.newFakeClient(&s.roundTripper, "dc0") 487 err := client.MoveVMFolderInto(context.Background(), "foo", "foo/bar") 488 c.Assert(err, jc.ErrorIsNil) 489 490 s.roundTripper.CheckCalls(c, []testing.StubCall{ 491 retrievePropertiesStubCall("FakeRootFolder"), 492 retrievePropertiesStubCall("FakeRootFolder"), 493 retrievePropertiesStubCall("FakeDatacenter"), 494 retrievePropertiesStubCall("FakeRootFolder"), 495 retrievePropertiesStubCall("FakeDatacenter"), 496 retrievePropertiesStubCall("FakeVmFolder"), 497 retrievePropertiesStubCall("FakeHostFolder"), 498 retrievePropertiesStubCall("FakeRootFolder"), 499 retrievePropertiesStubCall("FakeDatacenter"), 500 retrievePropertiesStubCall("FakeVmFolder"), 501 retrievePropertiesStubCall("FakeControllerVmFolder"), 502 retrievePropertiesStubCall("FakeHostFolder"), 503 {"MoveIntoFolder_Task", nil}, 504 {"CreatePropertyCollector", nil}, 505 {"CreateFilter", nil}, 506 {"WaitForUpdatesEx", nil}, 507 }) 508 } 509 510 func (s *clientSuite) TestMoveVMsInto(c *gc.C) { 511 client := s.newFakeClient(&s.roundTripper, "dc0") 512 err := client.MoveVMsInto( 513 context.Background(), "foo", 514 types.ManagedObjectReference{ 515 Type: "VirtualMachine", 516 Value: "vm-0", 517 }, 518 types.ManagedObjectReference{ 519 Type: "VirtualMachine", 520 Value: "vm-1", 521 }, 522 ) 523 c.Assert(err, jc.ErrorIsNil) 524 525 s.roundTripper.CheckCalls(c, []testing.StubCall{ 526 retrievePropertiesStubCall("FakeRootFolder"), 527 retrievePropertiesStubCall("FakeRootFolder"), 528 retrievePropertiesStubCall("FakeDatacenter"), 529 retrievePropertiesStubCall("FakeRootFolder"), 530 retrievePropertiesStubCall("FakeDatacenter"), 531 retrievePropertiesStubCall("FakeVmFolder"), 532 retrievePropertiesStubCall("FakeHostFolder"), 533 {"MoveIntoFolder_Task", nil}, 534 {"CreatePropertyCollector", nil}, 535 {"CreateFilter", nil}, 536 {"WaitForUpdatesEx", nil}, 537 }) 538 } 539 540 func (s *clientSuite) TestRemoveVirtualMachines(c *gc.C) { 541 client := s.newFakeClient(&s.roundTripper, "dc0") 542 err := client.RemoveVirtualMachines(context.Background(), "foo/bar/*") 543 c.Assert(err, jc.ErrorIsNil) 544 545 s.roundTripper.CheckCalls(c, []testing.StubCall{ 546 retrievePropertiesStubCall("FakeRootFolder"), 547 retrievePropertiesStubCall("FakeRootFolder"), 548 retrievePropertiesStubCall("FakeDatacenter"), 549 retrievePropertiesStubCall("FakeVmFolder"), 550 retrievePropertiesStubCall("FakeVmFolder"), 551 retrievePropertiesStubCall("FakeControllerVmFolder"), 552 retrievePropertiesStubCall("FakeModelVmFolder"), 553 retrievePropertiesStubCall("FakeVm0", "FakeVm1"), 554 {"Destroy_Task", nil}, 555 {"PowerOffVM_Task", nil}, 556 {"Destroy_Task", nil}, 557 {"CreatePropertyCollector", nil}, 558 {"CreateFilter", nil}, 559 {"WaitForUpdatesEx", nil}, 560 {"CreatePropertyCollector", nil}, 561 {"CreateFilter", nil}, 562 {"WaitForUpdatesEx", nil}, 563 {"CreatePropertyCollector", nil}, 564 {"CreateFilter", nil}, 565 {"WaitForUpdatesEx", nil}, 566 }) 567 } 568 569 func (s *clientSuite) TestRemoveVirtualMachinesDestroyRace(c *gc.C) { 570 s.roundTripper.taskError[destroyTask] = &types.LocalizedMethodFault{ 571 Fault: &types.ManagedObjectNotFound{}, 572 } 573 client := s.newFakeClient(&s.roundTripper, "dc0") 574 err := client.RemoveVirtualMachines(context.Background(), "foo/bar/*") 575 c.Assert(err, jc.ErrorIsNil) 576 } 577 578 func (s *clientSuite) TestUpdateVirtualMachineExtraConfig(c *gc.C) { 579 client := s.newFakeClient(&s.roundTripper, "dc0") 580 var vm mo.VirtualMachine 581 vm.Self = types.ManagedObjectReference{ 582 Type: "VirtualMachine", 583 Value: "FakeVm0", 584 } 585 err := client.UpdateVirtualMachineExtraConfig( 586 context.Background(), &vm, map[string]string{ 587 "k0": "v0", 588 "k1": "", 589 }, 590 ) 591 c.Assert(err, jc.ErrorIsNil) 592 593 s.roundTripper.CheckCallNames(c, 594 "ReconfigVM_Task", 595 "CreatePropertyCollector", 596 "CreateFilter", 597 "WaitForUpdatesEx", 598 ) 599 } 600 601 func (s *clientSuite) TestVirtualMachines(c *gc.C) { 602 client := s.newFakeClient(&s.roundTripper, "dc0") 603 result, err := client.VirtualMachines(context.Background(), "foo/bar/*") 604 c.Assert(err, jc.ErrorIsNil) 605 606 s.roundTripper.CheckCalls(c, []testing.StubCall{ 607 retrievePropertiesStubCall("FakeRootFolder"), 608 retrievePropertiesStubCall("FakeRootFolder"), 609 retrievePropertiesStubCall("FakeDatacenter"), 610 retrievePropertiesStubCall("FakeVmFolder"), 611 retrievePropertiesStubCall("FakeVmFolder"), 612 retrievePropertiesStubCall("FakeControllerVmFolder"), 613 retrievePropertiesStubCall("FakeModelVmFolder"), 614 retrievePropertiesStubCall("FakeVm0"), 615 retrievePropertiesStubCall("FakeVm1"), 616 }) 617 618 c.Assert(result, gc.HasLen, 2) 619 c.Assert(result[0].Name, gc.Equals, "vm-0") 620 c.Assert(result[1].Name, gc.Equals, "vm-1") 621 } 622 623 func (s *clientSuite) TestDatastores(c *gc.C) { 624 client := s.newFakeClient(&s.roundTripper, "dc0") 625 result, err := client.Datastores(context.Background()) 626 c.Assert(err, jc.ErrorIsNil) 627 628 s.roundTripper.CheckCalls(c, []testing.StubCall{ 629 retrievePropertiesStubCall("FakeRootFolder"), 630 retrievePropertiesStubCall("FakeRootFolder"), 631 retrievePropertiesStubCall("FakeDatacenter"), 632 retrievePropertiesStubCall("FakeDatastoreFolder"), 633 }) 634 635 c.Assert(result, gc.HasLen, 2) 636 c.Assert(result[0].Name, gc.Equals, "datastore1") 637 c.Assert(result[1].Name, gc.Equals, "datastore2") 638 } 639 640 func (s *clientSuite) TestDeleteDatastoreFile(c *gc.C) { 641 client := s.newFakeClient(&s.roundTripper, "dc0") 642 err := client.DeleteDatastoreFile(context.Background(), "[datastore1] file/path") 643 c.Assert(err, jc.ErrorIsNil) 644 645 s.roundTripper.CheckCalls(c, []testing.StubCall{ 646 retrievePropertiesStubCall("FakeRootFolder"), 647 retrievePropertiesStubCall("FakeRootFolder"), 648 {"DeleteDatastoreFile", []interface{}{"[datastore1] file/path"}}, 649 {"CreatePropertyCollector", nil}, 650 {"CreateFilter", nil}, 651 {"WaitForUpdatesEx", nil}, 652 }) 653 } 654 655 func (s *clientSuite) TestDeleteDatastoreFileNotFound(c *gc.C) { 656 s.roundTripper.taskError[deleteDatastoreFileTask] = &types.LocalizedMethodFault{ 657 Fault: &types.FileNotFound{}, 658 } 659 660 client := s.newFakeClient(&s.roundTripper, "dc0") 661 err := client.DeleteDatastoreFile(context.Background(), "[datastore1] file/path") 662 c.Assert(err, jc.ErrorIsNil) 663 } 664 665 func (s *clientSuite) TestDeleteDatastoreError(c *gc.C) { 666 s.roundTripper.taskError[deleteDatastoreFileTask] = &types.LocalizedMethodFault{ 667 Fault: &types.NotAuthenticated{}, 668 LocalizedMessage: "nope", 669 } 670 671 client := s.newFakeClient(&s.roundTripper, "dc0") 672 err := client.DeleteDatastoreFile(context.Background(), "[datastore1] file/path") 673 c.Assert(err, gc.ErrorMatches, "nope") 674 }