github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/apiserver/instancepoller/instancepoller_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package instancepoller_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/instancepoller" 15 "github.com/juju/juju/apiserver/params" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/network" 18 "github.com/juju/juju/state" 19 statetesting "github.com/juju/juju/state/testing" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type InstancePollerSuite struct { 24 coretesting.BaseSuite 25 26 st *mockState 27 api *instancepoller.InstancePollerAPI 28 authoriser apiservertesting.FakeAuthorizer 29 resources *common.Resources 30 31 machineEntities params.Entities 32 machineErrorResults params.ErrorResults 33 34 mixedEntities params.Entities 35 mixedErrorResults params.ErrorResults 36 } 37 38 var _ = gc.Suite(&InstancePollerSuite{}) 39 40 func (s *InstancePollerSuite) SetUpTest(c *gc.C) { 41 s.BaseSuite.SetUpTest(c) 42 43 s.authoriser = apiservertesting.FakeAuthorizer{ 44 EnvironManager: true, 45 } 46 s.resources = common.NewResources() 47 s.AddCleanup(func(*gc.C) { s.resources.StopAll() }) 48 49 s.st = NewMockState() 50 instancepoller.PatchState(s, s.st) 51 52 var err error 53 s.api, err = instancepoller.NewInstancePollerAPI(nil, s.resources, s.authoriser) 54 c.Assert(err, jc.ErrorIsNil) 55 56 s.machineEntities = params.Entities{ 57 Entities: []params.Entity{ 58 {Tag: "machine-1"}, 59 {Tag: "machine-2"}, 60 {Tag: "machine-3"}, 61 }} 62 s.machineErrorResults = params.ErrorResults{ 63 Results: []params.ErrorResult{ 64 {Error: apiservertesting.ServerError("pow!")}, 65 {Error: apiservertesting.ServerError("FAIL")}, 66 {Error: apiservertesting.NotProvisionedError("42")}, 67 }} 68 69 s.mixedEntities = params.Entities{ 70 Entities: []params.Entity{ 71 {Tag: "machine-1"}, 72 {Tag: "machine-2"}, 73 {Tag: "machine-42"}, 74 {Tag: "service-unknown"}, 75 {Tag: "invalid-tag"}, 76 {Tag: "unit-missing-1"}, 77 {Tag: ""}, 78 {Tag: "42"}, 79 }} 80 s.mixedErrorResults = params.ErrorResults{ 81 Results: []params.ErrorResult{ 82 {Error: nil}, 83 {Error: nil}, 84 {Error: apiservertesting.NotFoundError("machine 42")}, 85 {Error: apiservertesting.ServerError(`"service-unknown" is not a valid machine tag`)}, 86 {Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)}, 87 {Error: apiservertesting.ServerError(`"unit-missing-1" is not a valid machine tag`)}, 88 {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 89 {Error: apiservertesting.ServerError(`"42" is not a valid tag`)}, 90 }} 91 } 92 93 func (s *InstancePollerSuite) TestNewInstancePollerAPIRequiresEnvironManager(c *gc.C) { 94 anAuthoriser := s.authoriser 95 anAuthoriser.EnvironManager = false 96 api, err := instancepoller.NewInstancePollerAPI(nil, s.resources, anAuthoriser) 97 c.Assert(api, gc.IsNil) 98 c.Assert(err, gc.ErrorMatches, "permission denied") 99 } 100 101 func (s *InstancePollerSuite) TestEnvironConfigFailure(c *gc.C) { 102 s.st.SetErrors(errors.New("boom")) 103 104 result, err := s.api.EnvironConfig() 105 c.Assert(err, gc.ErrorMatches, "boom") 106 c.Assert(result, jc.DeepEquals, params.EnvironConfigResult{}) 107 108 s.st.CheckCallNames(c, "EnvironConfig") 109 } 110 111 func (s *InstancePollerSuite) TestEnvironConfigSuccess(c *gc.C) { 112 envConfig := coretesting.EnvironConfig(c) 113 s.st.SetConfig(c, envConfig) 114 115 result, err := s.api.EnvironConfig() 116 c.Assert(err, jc.ErrorIsNil) 117 c.Assert(result, jc.DeepEquals, params.EnvironConfigResult{ 118 Config: envConfig.AllAttrs(), 119 }) 120 121 s.st.CheckCallNames(c, "EnvironConfig") 122 } 123 124 func (s *InstancePollerSuite) TestWatchForEnvironConfigChangesFailure(c *gc.C) { 125 // Force the Changes() method of the mock watcher to return a 126 // closed channel by setting an error. 127 s.st.SetErrors(errors.New("boom")) 128 129 result, err := s.api.WatchForEnvironConfigChanges() 130 c.Assert(err, gc.ErrorMatches, "boom") 131 c.Assert(result, jc.DeepEquals, params.NotifyWatchResult{}) 132 133 c.Assert(s.resources.Count(), gc.Equals, 0) // no watcher registered 134 s.st.CheckCallNames(c, "WatchForEnvironConfigChanges") 135 } 136 137 func (s *InstancePollerSuite) TestWatchForEnvironConfigChangesSuccess(c *gc.C) { 138 result, err := s.api.WatchForEnvironConfigChanges() 139 c.Assert(err, jc.ErrorIsNil) 140 c.Assert(result, jc.DeepEquals, params.NotifyWatchResult{ 141 Error: nil, NotifyWatcherId: "1", 142 }) 143 144 // Verify the watcher resource was registered. 145 c.Assert(s.resources.Count(), gc.Equals, 1) 146 resource := s.resources.Get("1") 147 defer statetesting.AssertStop(c, resource) 148 149 // Check that the watcher has consumed the initial event 150 wc := statetesting.NewNotifyWatcherC(c, s.st, resource.(state.NotifyWatcher)) 151 wc.AssertNoChange() 152 153 s.st.CheckCallNames(c, "WatchForEnvironConfigChanges") 154 155 // Try changing the config to verify an event is reported. 156 envConfig := coretesting.EnvironConfig(c) 157 s.st.SetConfig(c, envConfig) 158 wc.AssertOneChange() 159 } 160 161 func (s *InstancePollerSuite) TestWatchEnvironMachinesFailure(c *gc.C) { 162 // Force the Changes() method of the mock watcher to return a 163 // closed channel by setting an error. 164 s.st.SetErrors(errors.Errorf("boom")) 165 166 result, err := s.api.WatchEnvironMachines() 167 c.Assert(err, gc.ErrorMatches, "cannot obtain initial environment machines: boom") 168 c.Assert(result, jc.DeepEquals, params.StringsWatchResult{}) 169 170 c.Assert(s.resources.Count(), gc.Equals, 0) // no watcher registered 171 s.st.CheckCallNames(c, "WatchEnvironMachines") 172 } 173 174 func (s *InstancePollerSuite) TestWatchEnvironMachinesSuccess(c *gc.C) { 175 // Add a couple of machines. 176 s.st.SetMachineInfo(c, machineInfo{id: "2"}) 177 s.st.SetMachineInfo(c, machineInfo{id: "1"}) 178 179 expectedResult := params.StringsWatchResult{ 180 Error: nil, 181 StringsWatcherId: "1", 182 Changes: []string{"1", "2"}, // initial event (sorted ids) 183 } 184 result, err := s.api.WatchEnvironMachines() 185 c.Assert(err, jc.ErrorIsNil) 186 c.Assert(result, jc.DeepEquals, expectedResult) 187 188 // Verify the watcher resource was registered. 189 c.Assert(s.resources.Count(), gc.Equals, 1) 190 resource1 := s.resources.Get("1") 191 defer func() { 192 if resource1 != nil { 193 statetesting.AssertStop(c, resource1) 194 } 195 }() 196 197 // Check that the watcher has consumed the initial event 198 wc1 := statetesting.NewStringsWatcherC(c, s.st, resource1.(state.StringsWatcher)) 199 wc1.AssertNoChange() 200 201 s.st.CheckCallNames(c, "WatchEnvironMachines") 202 203 // Add another watcher to verify events coalescence. 204 result, err = s.api.WatchEnvironMachines() 205 c.Assert(err, jc.ErrorIsNil) 206 expectedResult.StringsWatcherId = "2" 207 c.Assert(result, jc.DeepEquals, expectedResult) 208 s.st.CheckCallNames(c, "WatchEnvironMachines", "WatchEnvironMachines") 209 c.Assert(s.resources.Count(), gc.Equals, 2) 210 resource2 := s.resources.Get("2") 211 defer statetesting.AssertStop(c, resource2) 212 wc2 := statetesting.NewStringsWatcherC(c, s.st, resource2.(state.StringsWatcher)) 213 wc2.AssertNoChange() 214 215 // Remove machine 1, check it's reported. 216 s.st.RemoveMachine(c, "1") 217 wc1.AssertChangeInSingleEvent("1") 218 219 // Make separate changes, check they're combined. 220 s.st.SetMachineInfo(c, machineInfo{id: "2", life: state.Dying}) 221 s.st.SetMachineInfo(c, machineInfo{id: "3"}) 222 s.st.RemoveMachine(c, "42") // ignored 223 wc1.AssertChangeInSingleEvent("2", "3") 224 wc2.AssertChangeInSingleEvent("1", "2", "3") 225 226 // Stop the first watcher and assert its changes chan is closed. 227 c.Assert(resource1.Stop(), jc.ErrorIsNil) 228 wc1.AssertClosed() 229 resource1 = nil 230 } 231 232 func (s *InstancePollerSuite) TestLifeSuccess(c *gc.C) { 233 s.st.SetMachineInfo(c, machineInfo{id: "1", life: state.Alive}) 234 s.st.SetMachineInfo(c, machineInfo{id: "2", life: state.Dying}) 235 236 result, err := s.api.Life(s.mixedEntities) 237 c.Assert(err, jc.ErrorIsNil) 238 c.Assert(result, jc.DeepEquals, params.LifeResults{ 239 Results: []params.LifeResult{ 240 {Life: params.Alive}, 241 {Life: params.Dying}, 242 {Error: apiservertesting.NotFoundError("machine 42")}, 243 {Error: apiservertesting.ErrUnauthorized}, 244 {Error: apiservertesting.ErrUnauthorized}, 245 {Error: apiservertesting.ErrUnauthorized}, 246 {Error: apiservertesting.ErrUnauthorized}, 247 {Error: apiservertesting.ErrUnauthorized}, 248 }}, 249 ) 250 251 s.st.CheckFindEntityCall(c, 0, "1") 252 s.st.CheckCall(c, 1, "Life") 253 s.st.CheckFindEntityCall(c, 2, "2") 254 s.st.CheckCall(c, 3, "Life") 255 s.st.CheckFindEntityCall(c, 4, "42") 256 } 257 258 func (s *InstancePollerSuite) TestLifeFailure(c *gc.C) { 259 s.st.SetErrors( 260 errors.New("pow!"), // m1 := FindEntity("1"); Life not called 261 nil, // m2 := FindEntity("2") 262 errors.New("FAIL"), // m2.Life() - unused 263 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 264 ) 265 s.st.SetMachineInfo(c, machineInfo{id: "1", life: state.Alive}) 266 s.st.SetMachineInfo(c, machineInfo{id: "2", life: state.Dead}) 267 s.st.SetMachineInfo(c, machineInfo{id: "3", life: state.Dying}) 268 269 result, err := s.api.Life(s.machineEntities) 270 c.Assert(err, jc.ErrorIsNil) 271 c.Assert(result, jc.DeepEquals, params.LifeResults{ 272 Results: []params.LifeResult{ 273 {Error: apiservertesting.ServerError("pow!")}, 274 {Life: params.Dead}, 275 {Error: apiservertesting.NotProvisionedError("42")}, 276 }}, 277 ) 278 279 s.st.CheckFindEntityCall(c, 0, "1") 280 s.st.CheckFindEntityCall(c, 1, "2") 281 s.st.CheckCall(c, 2, "Life") 282 s.st.CheckFindEntityCall(c, 3, "3") 283 } 284 285 func (s *InstancePollerSuite) TestInstanceIdSuccess(c *gc.C) { 286 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceId: "i-foo"}) 287 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceId: ""}) 288 289 result, err := s.api.InstanceId(s.mixedEntities) 290 c.Assert(err, jc.ErrorIsNil) 291 c.Assert(result, jc.DeepEquals, params.StringResults{ 292 Results: []params.StringResult{ 293 {Result: "i-foo"}, 294 {Result: ""}, 295 {Error: apiservertesting.NotFoundError("machine 42")}, 296 {Error: apiservertesting.ErrUnauthorized}, 297 {Error: apiservertesting.ErrUnauthorized}, 298 {Error: apiservertesting.ErrUnauthorized}, 299 {Error: apiservertesting.ErrUnauthorized}, 300 {Error: apiservertesting.ErrUnauthorized}, 301 }}, 302 ) 303 304 s.st.CheckFindEntityCall(c, 0, "1") 305 s.st.CheckCall(c, 1, "InstanceId") 306 s.st.CheckFindEntityCall(c, 2, "2") 307 s.st.CheckCall(c, 3, "InstanceId") 308 s.st.CheckFindEntityCall(c, 4, "42") 309 } 310 311 func (s *InstancePollerSuite) TestInstanceIdFailure(c *gc.C) { 312 s.st.SetErrors( 313 errors.New("pow!"), // m1 := FindEntity("1"); InstanceId not called 314 nil, // m2 := FindEntity("2") 315 errors.New("FAIL"), // m2.InstanceId() 316 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 317 ) 318 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceId: ""}) 319 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceId: "i-bar"}) 320 321 result, err := s.api.InstanceId(s.machineEntities) 322 c.Assert(err, jc.ErrorIsNil) 323 c.Assert(result, jc.DeepEquals, params.StringResults{ 324 Results: []params.StringResult{ 325 {Error: apiservertesting.ServerError("pow!")}, 326 {Error: apiservertesting.ServerError("FAIL")}, 327 {Error: apiservertesting.NotProvisionedError("42")}, 328 }}, 329 ) 330 331 s.st.CheckFindEntityCall(c, 0, "1") 332 s.st.CheckFindEntityCall(c, 1, "2") 333 s.st.CheckCall(c, 2, "InstanceId") 334 s.st.CheckFindEntityCall(c, 3, "3") 335 } 336 337 func (s *InstancePollerSuite) TestStatusSuccess(c *gc.C) { 338 now := time.Now() 339 s1 := state.StatusInfo{ 340 Status: state.StatusError, 341 Message: "not really", 342 Data: map[string]interface{}{ 343 "price": 4.2, 344 "bool": false, 345 "bar": []string{"a", "b"}, 346 }, 347 Since: &now, 348 } 349 s2 := state.StatusInfo{} 350 s.st.SetMachineInfo(c, machineInfo{id: "1", status: s1}) 351 s.st.SetMachineInfo(c, machineInfo{id: "2", status: s2}) 352 353 result, err := s.api.Status(s.mixedEntities) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(result, jc.DeepEquals, params.StatusResults{ 356 Results: []params.StatusResult{ 357 { 358 Status: params.StatusError, 359 Info: s1.Message, 360 Data: s1.Data, 361 Since: s1.Since, 362 }, 363 {Status: "", Info: "", Data: nil, Since: nil}, 364 {Error: apiservertesting.NotFoundError("machine 42")}, 365 {Error: apiservertesting.ErrUnauthorized}, 366 {Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)}, 367 {Error: apiservertesting.ErrUnauthorized}, 368 {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 369 {Error: apiservertesting.ServerError(`"42" is not a valid tag`)}, 370 }}, 371 ) 372 373 s.st.CheckFindEntityCall(c, 0, "1") 374 s.st.CheckCall(c, 1, "Status") 375 s.st.CheckFindEntityCall(c, 2, "2") 376 s.st.CheckCall(c, 3, "Status") 377 s.st.CheckFindEntityCall(c, 4, "42") 378 } 379 380 func (s *InstancePollerSuite) TestStatusFailure(c *gc.C) { 381 s.st.SetErrors( 382 errors.New("pow!"), // m1 := FindEntity("1"); Status not called 383 nil, // m2 := FindEntity("2") 384 errors.New("FAIL"), // m2.Status() 385 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 386 ) 387 s.st.SetMachineInfo(c, machineInfo{id: "1"}) 388 s.st.SetMachineInfo(c, machineInfo{id: "2"}) 389 390 result, err := s.api.Status(s.machineEntities) 391 c.Assert(err, jc.ErrorIsNil) 392 c.Assert(result, jc.DeepEquals, params.StatusResults{ 393 Results: []params.StatusResult{ 394 {Error: apiservertesting.ServerError("pow!")}, 395 {Error: apiservertesting.ServerError("FAIL")}, 396 {Error: apiservertesting.NotProvisionedError("42")}, 397 }}, 398 ) 399 400 s.st.CheckFindEntityCall(c, 0, "1") 401 s.st.CheckFindEntityCall(c, 1, "2") 402 s.st.CheckCall(c, 2, "Status") 403 s.st.CheckFindEntityCall(c, 3, "3") 404 } 405 406 func (s *InstancePollerSuite) TestProviderAddressesSuccess(c *gc.C) { 407 addrs := network.NewAddresses("0.1.2.3", "127.0.0.1", "8.8.8.8") 408 expectedAddresses := params.FromNetworkAddresses(addrs) 409 s.st.SetMachineInfo(c, machineInfo{id: "1", providerAddresses: addrs}) 410 s.st.SetMachineInfo(c, machineInfo{id: "2", providerAddresses: nil}) 411 412 result, err := s.api.ProviderAddresses(s.mixedEntities) 413 c.Assert(err, jc.ErrorIsNil) 414 c.Assert(result, jc.DeepEquals, params.MachineAddressesResults{ 415 Results: []params.MachineAddressesResult{ 416 {Addresses: expectedAddresses}, 417 {Addresses: nil}, 418 {Error: apiservertesting.NotFoundError("machine 42")}, 419 {Error: apiservertesting.ServerError(`"service-unknown" is not a valid machine tag`)}, 420 {Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)}, 421 {Error: apiservertesting.ServerError(`"unit-missing-1" is not a valid machine tag`)}, 422 {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 423 {Error: apiservertesting.ServerError(`"42" is not a valid tag`)}, 424 }}, 425 ) 426 427 s.st.CheckFindEntityCall(c, 0, "1") 428 s.st.CheckCall(c, 1, "ProviderAddresses") 429 s.st.CheckFindEntityCall(c, 2, "2") 430 s.st.CheckCall(c, 3, "ProviderAddresses") 431 s.st.CheckFindEntityCall(c, 4, "42") 432 } 433 434 func (s *InstancePollerSuite) TestProviderAddressesFailure(c *gc.C) { 435 s.st.SetErrors( 436 errors.New("pow!"), // m1 := FindEntity("1") 437 nil, // m2 := FindEntity("2") 438 errors.New("FAIL"), // m2.ProviderAddresses()- unused 439 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 440 ) 441 s.st.SetMachineInfo(c, machineInfo{id: "1"}) 442 s.st.SetMachineInfo(c, machineInfo{id: "2"}) 443 444 result, err := s.api.ProviderAddresses(s.machineEntities) 445 c.Assert(err, jc.ErrorIsNil) 446 c.Assert(result, jc.DeepEquals, params.MachineAddressesResults{ 447 Results: []params.MachineAddressesResult{ 448 {Error: apiservertesting.ServerError("pow!")}, 449 {Addresses: nil}, 450 {Error: apiservertesting.NotProvisionedError("42")}, 451 }}, 452 ) 453 454 s.st.CheckFindEntityCall(c, 0, "1") 455 s.st.CheckFindEntityCall(c, 1, "2") 456 s.st.CheckCall(c, 2, "ProviderAddresses") 457 s.st.CheckFindEntityCall(c, 3, "3") 458 } 459 460 func (s *InstancePollerSuite) TestSetProviderAddressesSuccess(c *gc.C) { 461 oldAddrs := network.NewAddresses("0.1.2.3", "127.0.0.1", "8.8.8.8") 462 newAddrs := network.NewAddresses("1.2.3.4", "8.4.4.8", "2001:db8::") 463 s.st.SetMachineInfo(c, machineInfo{id: "1", providerAddresses: oldAddrs}) 464 s.st.SetMachineInfo(c, machineInfo{id: "2", providerAddresses: nil}) 465 466 result, err := s.api.SetProviderAddresses(params.SetMachinesAddresses{ 467 MachineAddresses: []params.MachineAddresses{ 468 {Tag: "machine-1", Addresses: nil}, 469 {Tag: "machine-2", Addresses: params.FromNetworkAddresses(newAddrs)}, 470 {Tag: "machine-42"}, 471 {Tag: "service-unknown"}, 472 {Tag: "invalid-tag"}, 473 {Tag: "unit-missing-1"}, 474 {Tag: ""}, 475 {Tag: "42"}, 476 }}, 477 ) 478 c.Assert(err, jc.ErrorIsNil) 479 c.Assert(result, jc.DeepEquals, s.mixedErrorResults) 480 481 s.st.CheckFindEntityCall(c, 0, "1") 482 s.st.CheckSetProviderAddressesCall(c, 1, []network.Address{}) 483 s.st.CheckFindEntityCall(c, 2, "2") 484 s.st.CheckSetProviderAddressesCall(c, 3, newAddrs) 485 s.st.CheckFindEntityCall(c, 4, "42") 486 487 // Ensure machines were updated. 488 machine, err := s.st.Machine("1") 489 c.Assert(err, jc.ErrorIsNil) 490 c.Assert(machine.ProviderAddresses(), gc.HasLen, 0) 491 492 machine, err = s.st.Machine("2") 493 c.Assert(err, jc.ErrorIsNil) 494 c.Assert(machine.ProviderAddresses(), jc.DeepEquals, newAddrs) 495 } 496 497 func (s *InstancePollerSuite) TestSetProviderAddressesFailure(c *gc.C) { 498 s.st.SetErrors( 499 errors.New("pow!"), // m1 := FindEntity("1") 500 nil, // m2 := FindEntity("2") 501 errors.New("FAIL"), // m2.SetProviderAddresses() 502 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 503 ) 504 oldAddrs := network.NewAddresses("0.1.2.3", "127.0.0.1", "8.8.8.8") 505 newAddrs := network.NewAddresses("1.2.3.4", "8.4.4.8", "2001:db8::") 506 s.st.SetMachineInfo(c, machineInfo{id: "1", providerAddresses: oldAddrs}) 507 s.st.SetMachineInfo(c, machineInfo{id: "2", providerAddresses: nil}) 508 509 result, err := s.api.SetProviderAddresses(params.SetMachinesAddresses{ 510 MachineAddresses: []params.MachineAddresses{ 511 {Tag: "machine-1", Addresses: nil}, 512 {Tag: "machine-2", Addresses: params.FromNetworkAddresses(newAddrs)}, 513 {Tag: "machine-3"}, 514 }}, 515 ) 516 c.Assert(err, jc.ErrorIsNil) 517 c.Assert(result, jc.DeepEquals, s.machineErrorResults) 518 519 s.st.CheckFindEntityCall(c, 0, "1") 520 s.st.CheckFindEntityCall(c, 1, "2") 521 s.st.CheckSetProviderAddressesCall(c, 2, newAddrs) 522 s.st.CheckFindEntityCall(c, 3, "3") 523 524 // Ensure machine 2 wasn't updated. 525 machine, err := s.st.Machine("2") 526 c.Assert(err, jc.ErrorIsNil) 527 c.Assert(machine.ProviderAddresses(), gc.HasLen, 0) 528 } 529 530 func (s *InstancePollerSuite) TestInstanceStatusSuccess(c *gc.C) { 531 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: "foo"}) 532 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: ""}) 533 534 result, err := s.api.InstanceStatus(s.mixedEntities) 535 c.Assert(err, jc.ErrorIsNil) 536 c.Assert(result, jc.DeepEquals, params.StringResults{ 537 Results: []params.StringResult{ 538 {Result: "foo"}, 539 {Result: ""}, 540 {Error: apiservertesting.NotFoundError("machine 42")}, 541 {Error: apiservertesting.ServerError(`"service-unknown" is not a valid machine tag`)}, 542 {Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)}, 543 {Error: apiservertesting.ServerError(`"unit-missing-1" is not a valid machine tag`)}, 544 {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 545 {Error: apiservertesting.ServerError(`"42" is not a valid tag`)}, 546 }}, 547 ) 548 549 s.st.CheckFindEntityCall(c, 0, "1") 550 s.st.CheckCall(c, 1, "InstanceStatus") 551 s.st.CheckFindEntityCall(c, 2, "2") 552 s.st.CheckCall(c, 3, "InstanceStatus") 553 s.st.CheckFindEntityCall(c, 4, "42") 554 } 555 556 func (s *InstancePollerSuite) TestInstanceStatusFailure(c *gc.C) { 557 s.st.SetErrors( 558 errors.New("pow!"), // m1 := FindEntity("1") 559 nil, // m2 := FindEntity("2") 560 errors.New("FAIL"), // m2.InstanceStatus() 561 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 562 ) 563 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: "foo"}) 564 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: ""}) 565 566 result, err := s.api.InstanceStatus(s.machineEntities) 567 c.Assert(err, jc.ErrorIsNil) 568 c.Assert(result, jc.DeepEquals, params.StringResults{ 569 Results: []params.StringResult{ 570 {Error: apiservertesting.ServerError("pow!")}, 571 {Error: apiservertesting.ServerError("FAIL")}, 572 {Error: apiservertesting.NotProvisionedError("42")}, 573 }}, 574 ) 575 576 s.st.CheckFindEntityCall(c, 0, "1") 577 s.st.CheckFindEntityCall(c, 1, "2") 578 s.st.CheckCall(c, 2, "InstanceStatus") 579 s.st.CheckFindEntityCall(c, 3, "3") 580 } 581 582 func (s *InstancePollerSuite) TestSetInstanceStatusSuccess(c *gc.C) { 583 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: "foo"}) 584 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: ""}) 585 586 result, err := s.api.SetInstanceStatus(params.SetInstancesStatus{ 587 Entities: []params.InstanceStatus{ 588 {Tag: "machine-1", Status: ""}, 589 {Tag: "machine-2", Status: "new status"}, 590 {Tag: "machine-42"}, 591 {Tag: "service-unknown"}, 592 {Tag: "invalid-tag"}, 593 {Tag: "unit-missing-1"}, 594 {Tag: ""}, 595 {Tag: "42"}, 596 }}, 597 ) 598 c.Assert(err, jc.ErrorIsNil) 599 c.Assert(result, jc.DeepEquals, s.mixedErrorResults) 600 601 s.st.CheckFindEntityCall(c, 0, "1") 602 s.st.CheckCall(c, 1, "SetInstanceStatus", "") 603 s.st.CheckFindEntityCall(c, 2, "2") 604 s.st.CheckCall(c, 3, "SetInstanceStatus", "new status") 605 s.st.CheckFindEntityCall(c, 4, "42") 606 607 // Ensure machines were updated. 608 machine, err := s.st.Machine("1") 609 c.Assert(err, jc.ErrorIsNil) 610 setStatus, err := machine.InstanceStatus() 611 c.Assert(err, jc.ErrorIsNil) 612 c.Assert(setStatus, gc.Equals, "") 613 614 machine, err = s.st.Machine("2") 615 c.Assert(err, jc.ErrorIsNil) 616 setStatus, err = machine.InstanceStatus() 617 c.Assert(err, jc.ErrorIsNil) 618 c.Assert(setStatus, gc.Equals, "new status") 619 } 620 621 func (s *InstancePollerSuite) TestSetInstanceStatusFailure(c *gc.C) { 622 s.st.SetErrors( 623 errors.New("pow!"), // m1 := FindEntity("1") 624 nil, // m2 := FindEntity("2") 625 errors.New("FAIL"), // m2.SetInstanceStatus() 626 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 627 ) 628 s.st.SetMachineInfo(c, machineInfo{id: "1", instanceStatus: "foo"}) 629 s.st.SetMachineInfo(c, machineInfo{id: "2", instanceStatus: ""}) 630 631 result, err := s.api.SetInstanceStatus(params.SetInstancesStatus{ 632 Entities: []params.InstanceStatus{ 633 {Tag: "machine-1", Status: "new"}, 634 {Tag: "machine-2", Status: "invalid"}, 635 {Tag: "machine-3", Status: ""}, 636 }}, 637 ) 638 c.Assert(err, jc.ErrorIsNil) 639 c.Assert(result, jc.DeepEquals, s.machineErrorResults) 640 641 s.st.CheckFindEntityCall(c, 0, "1") 642 s.st.CheckFindEntityCall(c, 1, "2") 643 s.st.CheckCall(c, 2, "SetInstanceStatus", "invalid") 644 s.st.CheckFindEntityCall(c, 3, "3") 645 } 646 647 func (s *InstancePollerSuite) TestAreManuallyProvisionedSuccess(c *gc.C) { 648 s.st.SetMachineInfo(c, machineInfo{id: "1", isManual: true}) 649 s.st.SetMachineInfo(c, machineInfo{id: "2", isManual: false}) 650 651 result, err := s.api.AreManuallyProvisioned(s.mixedEntities) 652 c.Assert(err, jc.ErrorIsNil) 653 c.Assert(result, jc.DeepEquals, params.BoolResults{ 654 Results: []params.BoolResult{ 655 {Result: true}, 656 {Result: false}, 657 {Error: apiservertesting.NotFoundError("machine 42")}, 658 {Error: apiservertesting.ServerError(`"service-unknown" is not a valid machine tag`)}, 659 {Error: apiservertesting.ServerError(`"invalid-tag" is not a valid tag`)}, 660 {Error: apiservertesting.ServerError(`"unit-missing-1" is not a valid machine tag`)}, 661 {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 662 {Error: apiservertesting.ServerError(`"42" is not a valid tag`)}, 663 }}, 664 ) 665 666 s.st.CheckFindEntityCall(c, 0, "1") 667 s.st.CheckCall(c, 1, "IsManual") 668 s.st.CheckFindEntityCall(c, 2, "2") 669 s.st.CheckCall(c, 3, "IsManual") 670 s.st.CheckFindEntityCall(c, 4, "42") 671 } 672 673 func (s *InstancePollerSuite) TestAreManuallyProvisionedFailure(c *gc.C) { 674 s.st.SetErrors( 675 errors.New("pow!"), // m1 := FindEntity("1") 676 nil, // m2 := FindEntity("2") 677 errors.New("FAIL"), // m2.IsManual() 678 errors.NotProvisionedf("machine 42"), // FindEntity("3") (ensure wrapping is preserved) 679 ) 680 s.st.SetMachineInfo(c, machineInfo{id: "1", isManual: true}) 681 s.st.SetMachineInfo(c, machineInfo{id: "2", isManual: false}) 682 683 result, err := s.api.AreManuallyProvisioned(s.machineEntities) 684 c.Assert(err, jc.ErrorIsNil) 685 c.Assert(result, jc.DeepEquals, params.BoolResults{ 686 Results: []params.BoolResult{ 687 {Error: apiservertesting.ServerError("pow!")}, 688 {Error: apiservertesting.ServerError("FAIL")}, 689 {Error: apiservertesting.NotProvisionedError("42")}, 690 }}, 691 ) 692 693 s.st.CheckFindEntityCall(c, 0, "1") 694 s.st.CheckFindEntityCall(c, 1, "2") 695 s.st.CheckCall(c, 2, "IsManual") 696 s.st.CheckFindEntityCall(c, 3, "3") 697 }