github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/api/uniter/unit_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter_test 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/names" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v5" 16 17 "github.com/juju/juju/api" 18 "github.com/juju/juju/api/base" 19 "github.com/juju/juju/api/uniter" 20 "github.com/juju/juju/apiserver/common" 21 "github.com/juju/juju/apiserver/params" 22 "github.com/juju/juju/juju/testing" 23 "github.com/juju/juju/network" 24 "github.com/juju/juju/state" 25 statetesting "github.com/juju/juju/state/testing" 26 jujufactory "github.com/juju/juju/testing/factory" 27 ) 28 29 type unitSuite struct { 30 uniterSuite 31 32 apiUnit *uniter.Unit 33 } 34 35 var _ = gc.Suite(&unitSuite{}) 36 37 func (s *unitSuite) SetUpTest(c *gc.C) { 38 s.uniterSuite.SetUpTest(c) 39 40 var err error 41 s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag)) 42 c.Assert(err, jc.ErrorIsNil) 43 } 44 45 func (s *unitSuite) TestRequestReboot(c *gc.C) { 46 err := s.apiUnit.RequestReboot() 47 c.Assert(err, jc.ErrorIsNil) 48 rFlag, err := s.wordpressMachine.GetRebootFlag() 49 c.Assert(err, jc.ErrorIsNil) 50 c.Assert(rFlag, jc.IsTrue) 51 } 52 53 func (s *unitSuite) TestUnitAndUnitTag(c *gc.C) { 54 apiUnitFoo, err := s.uniter.Unit(names.NewUnitTag("foo/42")) 55 c.Assert(err, gc.ErrorMatches, "permission denied") 56 c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized) 57 c.Assert(apiUnitFoo, gc.IsNil) 58 59 c.Assert(s.apiUnit.Tag(), gc.Equals, s.wordpressUnit.Tag().(names.UnitTag)) 60 } 61 62 func (s *unitSuite) TestSetAgentStatus(c *gc.C) { 63 statusInfo, err := s.wordpressUnit.AgentStatus() 64 c.Assert(err, jc.ErrorIsNil) 65 c.Assert(statusInfo.Status, gc.Equals, state.StatusAllocating) 66 c.Assert(statusInfo.Message, gc.Equals, "") 67 c.Assert(statusInfo.Data, gc.HasLen, 0) 68 69 unitStatusInfo, err := s.wordpressUnit.Status() 70 c.Assert(err, jc.ErrorIsNil) 71 c.Assert(unitStatusInfo.Status, gc.Equals, state.StatusUnknown) 72 c.Assert(unitStatusInfo.Message, gc.Equals, "Waiting for agent initialization to finish") 73 c.Assert(unitStatusInfo.Data, gc.HasLen, 0) 74 75 err = s.apiUnit.SetAgentStatus(params.StatusIdle, "blah", nil) 76 c.Assert(err, jc.ErrorIsNil) 77 78 statusInfo, err = s.wordpressUnit.AgentStatus() 79 c.Assert(err, jc.ErrorIsNil) 80 c.Assert(statusInfo.Status, gc.Equals, state.StatusIdle) 81 c.Assert(statusInfo.Message, gc.Equals, "blah") 82 c.Assert(statusInfo.Data, gc.HasLen, 0) 83 c.Assert(statusInfo.Since, gc.NotNil) 84 85 // Ensure that unit has not changed. 86 unitStatusInfo, err = s.wordpressUnit.Status() 87 c.Assert(err, jc.ErrorIsNil) 88 c.Assert(unitStatusInfo.Status, gc.Equals, state.StatusUnknown) 89 c.Assert(unitStatusInfo.Message, gc.Equals, "Waiting for agent initialization to finish") 90 c.Assert(unitStatusInfo.Data, gc.HasLen, 0) 91 } 92 93 func (s *unitSuite) TestSetUnitStatus(c *gc.C) { 94 statusInfo, err := s.wordpressUnit.Status() 95 c.Assert(err, jc.ErrorIsNil) 96 c.Assert(statusInfo.Status, gc.Equals, state.StatusUnknown) 97 c.Assert(statusInfo.Message, gc.Equals, "Waiting for agent initialization to finish") 98 c.Assert(statusInfo.Data, gc.HasLen, 0) 99 100 agentStatusInfo, err := s.wordpressUnit.AgentStatus() 101 c.Assert(err, jc.ErrorIsNil) 102 c.Assert(agentStatusInfo.Status, gc.Equals, state.StatusAllocating) 103 c.Assert(agentStatusInfo.Message, gc.Equals, "") 104 c.Assert(agentStatusInfo.Data, gc.HasLen, 0) 105 106 err = s.apiUnit.SetUnitStatus(params.StatusActive, "blah", nil) 107 c.Assert(err, jc.ErrorIsNil) 108 109 statusInfo, err = s.wordpressUnit.Status() 110 c.Assert(err, jc.ErrorIsNil) 111 c.Assert(statusInfo.Status, gc.Equals, state.StatusActive) 112 c.Assert(statusInfo.Message, gc.Equals, "blah") 113 c.Assert(statusInfo.Data, gc.HasLen, 0) 114 c.Assert(statusInfo.Since, gc.NotNil) 115 116 // Ensure unit's agent has not changed. 117 agentStatusInfo, err = s.wordpressUnit.AgentStatus() 118 c.Assert(err, jc.ErrorIsNil) 119 c.Assert(agentStatusInfo.Status, gc.Equals, state.StatusAllocating) 120 c.Assert(agentStatusInfo.Message, gc.Equals, "") 121 c.Assert(agentStatusInfo.Data, gc.HasLen, 0) 122 } 123 124 func (s *unitSuite) TestSetUnitStatusOldServer(c *gc.C) { 125 s.patchNewState(c, uniter.NewStateV1) 126 127 err := s.apiUnit.SetUnitStatus(params.StatusActive, "blah", nil) 128 c.Assert(err, jc.Satisfies, errors.IsNotImplemented) 129 c.Assert(err.Error(), gc.Equals, "SetUnitStatus not implemented") 130 } 131 132 func (s *unitSuite) TestSetAgentStatusOldServer(c *gc.C) { 133 s.patchNewState(c, uniter.NewStateV1) 134 135 statusInfo, err := s.wordpressUnit.Status() 136 c.Assert(err, jc.ErrorIsNil) 137 c.Assert(statusInfo.Status, gc.Equals, state.StatusUnknown) 138 c.Assert(statusInfo.Message, gc.Equals, "Waiting for agent initialization to finish") 139 c.Assert(statusInfo.Data, gc.HasLen, 0) 140 141 err = s.apiUnit.SetAgentStatus(params.StatusIdle, "blah", nil) 142 c.Assert(err, jc.ErrorIsNil) 143 144 statusInfo, err = s.wordpressUnit.AgentStatus() 145 c.Assert(err, jc.ErrorIsNil) 146 c.Assert(statusInfo.Status, gc.Equals, state.StatusIdle) 147 c.Assert(statusInfo.Message, gc.Equals, "blah") 148 c.Assert(statusInfo.Data, gc.HasLen, 0) 149 } 150 151 func (s *unitSuite) TestUnitStatus(c *gc.C) { 152 err := s.wordpressUnit.SetStatus(state.StatusMaintenance, "blah", nil) 153 c.Assert(err, jc.ErrorIsNil) 154 155 result, err := s.apiUnit.UnitStatus() 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(result.Since, gc.NotNil) 158 result.Since = nil 159 c.Assert(result, gc.DeepEquals, params.StatusResult{ 160 Status: params.StatusMaintenance, 161 Info: "blah", 162 Data: map[string]interface{}{}, 163 }) 164 } 165 166 func (s *unitSuite) TestEnsureDead(c *gc.C) { 167 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 168 169 err := s.apiUnit.EnsureDead() 170 c.Assert(err, jc.ErrorIsNil) 171 172 err = s.wordpressUnit.Refresh() 173 c.Assert(err, jc.ErrorIsNil) 174 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 175 176 err = s.apiUnit.EnsureDead() 177 c.Assert(err, jc.ErrorIsNil) 178 err = s.wordpressUnit.Refresh() 179 c.Assert(err, jc.ErrorIsNil) 180 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 181 182 err = s.wordpressUnit.Remove() 183 c.Assert(err, jc.ErrorIsNil) 184 err = s.wordpressUnit.Refresh() 185 c.Assert(err, jc.Satisfies, errors.IsNotFound) 186 187 err = s.apiUnit.EnsureDead() 188 c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`) 189 c.Assert(err, jc.Satisfies, params.IsCodeNotFound) 190 } 191 192 func (s *unitSuite) TestDestroy(c *gc.C) { 193 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 194 195 err := s.apiUnit.Destroy() 196 c.Assert(err, jc.ErrorIsNil) 197 198 err = s.wordpressUnit.Refresh() 199 c.Assert(err, gc.ErrorMatches, `unit "wordpress/0" not found`) 200 } 201 202 func (s *unitSuite) TestDestroyAllSubordinates(c *gc.C) { 203 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 204 205 // Call without subordinates - no change. 206 err := s.apiUnit.DestroyAllSubordinates() 207 c.Assert(err, jc.ErrorIsNil) 208 209 // Add a couple of subordinates and try again. 210 _, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 211 _, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 212 c.Assert(loggingSub.Life(), gc.Equals, state.Alive) 213 c.Assert(monitoringSub.Life(), gc.Equals, state.Alive) 214 215 err = s.apiUnit.DestroyAllSubordinates() 216 c.Assert(err, jc.ErrorIsNil) 217 218 // Verify they got destroyed. 219 err = loggingSub.Refresh() 220 c.Assert(err, jc.ErrorIsNil) 221 c.Assert(loggingSub.Life(), gc.Equals, state.Dying) 222 err = monitoringSub.Refresh() 223 c.Assert(err, jc.ErrorIsNil) 224 c.Assert(monitoringSub.Life(), gc.Equals, state.Dying) 225 } 226 227 func (s *unitSuite) TestRefresh(c *gc.C) { 228 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 229 230 err := s.apiUnit.EnsureDead() 231 c.Assert(err, jc.ErrorIsNil) 232 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 233 234 err = s.apiUnit.Refresh() 235 c.Assert(err, jc.ErrorIsNil) 236 c.Assert(s.apiUnit.Life(), gc.Equals, params.Dead) 237 } 238 239 func (s *unitSuite) TestWatch(c *gc.C) { 240 c.Assert(s.apiUnit.Life(), gc.Equals, params.Alive) 241 242 w, err := s.apiUnit.Watch() 243 c.Assert(err, jc.ErrorIsNil) 244 defer statetesting.AssertStop(c, w) 245 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 246 247 // Initial event. 248 wc.AssertOneChange() 249 250 // Change something other than the lifecycle and make sure it's 251 // not detected. 252 err = s.apiUnit.SetAgentStatus(params.StatusIdle, "not really", nil) 253 c.Assert(err, jc.ErrorIsNil) 254 wc.AssertNoChange() 255 256 // Make the unit dead and check it's detected. 257 err = s.apiUnit.EnsureDead() 258 c.Assert(err, jc.ErrorIsNil) 259 wc.AssertOneChange() 260 261 statetesting.AssertStop(c, w) 262 wc.AssertClosed() 263 } 264 265 func (s *unitSuite) TestResolve(c *gc.C) { 266 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 267 c.Assert(err, jc.ErrorIsNil) 268 269 mode, err := s.apiUnit.Resolved() 270 c.Assert(err, jc.ErrorIsNil) 271 c.Assert(mode, gc.Equals, params.ResolvedRetryHooks) 272 273 err = s.apiUnit.ClearResolved() 274 c.Assert(err, jc.ErrorIsNil) 275 276 mode, err = s.apiUnit.Resolved() 277 c.Assert(err, jc.ErrorIsNil) 278 c.Assert(mode, gc.Equals, params.ResolvedNone) 279 } 280 281 func (s *unitSuite) TestAssignedMachineV0NotImplemented(c *gc.C) { 282 s.patchNewState(c, uniter.NewStateV0) 283 284 _, err := s.apiUnit.AssignedMachine() 285 c.Assert(err, jc.Satisfies, errors.IsNotImplemented) 286 c.Assert(err.Error(), gc.Equals, "unit.AssignedMachine() (need V1+) not implemented") 287 } 288 289 func (s *unitSuite) TestAssignedMachineV1(c *gc.C) { 290 s.patchNewState(c, uniter.NewStateV1) 291 292 machineTag, err := s.apiUnit.AssignedMachine() 293 c.Assert(err, jc.ErrorIsNil) 294 c.Assert(machineTag, gc.Equals, s.wordpressMachine.Tag()) 295 } 296 297 func (s *unitSuite) TestIsPrincipal(c *gc.C) { 298 ok, err := s.apiUnit.IsPrincipal() 299 c.Assert(err, jc.ErrorIsNil) 300 c.Assert(ok, jc.IsTrue) 301 } 302 303 func (s *unitSuite) TestHasSubordinates(c *gc.C) { 304 found, err := s.apiUnit.HasSubordinates() 305 c.Assert(err, jc.ErrorIsNil) 306 c.Assert(found, jc.IsFalse) 307 308 // Add a couple of subordinates and try again. 309 s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 310 s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 311 312 found, err = s.apiUnit.HasSubordinates() 313 c.Assert(err, jc.ErrorIsNil) 314 c.Assert(found, jc.IsTrue) 315 } 316 317 func (s *unitSuite) TestPublicAddress(c *gc.C) { 318 address, err := s.apiUnit.PublicAddress() 319 c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no public address set`) 320 321 err = s.wordpressMachine.SetProviderAddresses( 322 network.NewScopedAddress("1.2.3.4", network.ScopePublic), 323 ) 324 c.Assert(err, jc.ErrorIsNil) 325 326 address, err = s.apiUnit.PublicAddress() 327 c.Assert(err, jc.ErrorIsNil) 328 c.Assert(address, gc.Equals, "1.2.3.4") 329 } 330 331 func (s *unitSuite) TestPrivateAddress(c *gc.C) { 332 address, err := s.apiUnit.PrivateAddress() 333 c.Assert(err, gc.ErrorMatches, `"unit-wordpress-0" has no private address set`) 334 335 err = s.wordpressMachine.SetProviderAddresses( 336 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal), 337 ) 338 c.Assert(err, jc.ErrorIsNil) 339 340 address, err = s.apiUnit.PrivateAddress() 341 c.Assert(err, jc.ErrorIsNil) 342 c.Assert(address, gc.Equals, "1.2.3.4") 343 } 344 345 func (s *unitSuite) TestAvailabilityZone(c *gc.C) { 346 uniter.PatchUnitResponse(s, s.apiUnit, "AvailabilityZone", 347 func(result interface{}) error { 348 if results, ok := result.(*params.StringResults); ok { 349 results.Results = []params.StringResult{{ 350 Result: "a-zone", 351 }} 352 } 353 return nil 354 }, 355 ) 356 357 zone, err := s.apiUnit.AvailabilityZone() 358 c.Assert(err, jc.ErrorIsNil) 359 360 c.Check(zone, gc.Equals, "a-zone") 361 } 362 363 func (s *unitSuite) TestOpenClosePortRanges(c *gc.C) { 364 ports, err := s.wordpressUnit.OpenedPorts() 365 c.Assert(err, jc.ErrorIsNil) 366 c.Assert(ports, gc.HasLen, 0) 367 368 err = s.apiUnit.OpenPorts("tcp", 1234, 1400) 369 c.Assert(err, jc.ErrorIsNil) 370 err = s.apiUnit.OpenPorts("udp", 4321, 5000) 371 c.Assert(err, jc.ErrorIsNil) 372 373 ports, err = s.wordpressUnit.OpenedPorts() 374 c.Assert(err, jc.ErrorIsNil) 375 // OpenedPorts returns a sorted slice. 376 c.Assert(ports, gc.DeepEquals, []network.PortRange{ 377 {Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 378 {Protocol: "udp", FromPort: 4321, ToPort: 5000}, 379 }) 380 381 err = s.apiUnit.ClosePorts("udp", 4321, 5000) 382 c.Assert(err, jc.ErrorIsNil) 383 384 ports, err = s.wordpressUnit.OpenedPorts() 385 c.Assert(err, jc.ErrorIsNil) 386 // OpenedPorts returns a sorted slice. 387 c.Assert(ports, gc.DeepEquals, []network.PortRange{ 388 {Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 389 }) 390 391 err = s.apiUnit.ClosePorts("tcp", 1234, 1400) 392 c.Assert(err, jc.ErrorIsNil) 393 394 ports, err = s.wordpressUnit.OpenedPorts() 395 c.Assert(err, jc.ErrorIsNil) 396 c.Assert(ports, gc.HasLen, 0) 397 } 398 399 func (s *unitSuite) TestOpenClosePort(c *gc.C) { 400 ports, err := s.wordpressUnit.OpenedPorts() 401 c.Assert(err, jc.ErrorIsNil) 402 c.Assert(ports, gc.HasLen, 0) 403 404 err = s.apiUnit.OpenPort("tcp", 1234) 405 c.Assert(err, jc.ErrorIsNil) 406 err = s.apiUnit.OpenPort("tcp", 4321) 407 c.Assert(err, jc.ErrorIsNil) 408 409 ports, err = s.wordpressUnit.OpenedPorts() 410 c.Assert(err, jc.ErrorIsNil) 411 // OpenedPorts returns a sorted slice. 412 c.Assert(ports, gc.DeepEquals, []network.PortRange{ 413 {Protocol: "tcp", FromPort: 1234, ToPort: 1234}, 414 {Protocol: "tcp", FromPort: 4321, ToPort: 4321}, 415 }) 416 417 err = s.apiUnit.ClosePort("tcp", 4321) 418 c.Assert(err, jc.ErrorIsNil) 419 420 ports, err = s.wordpressUnit.OpenedPorts() 421 c.Assert(err, jc.ErrorIsNil) 422 // OpenedPorts returns a sorted slice. 423 c.Assert(ports, gc.DeepEquals, []network.PortRange{ 424 {Protocol: "tcp", FromPort: 1234, ToPort: 1234}, 425 }) 426 427 err = s.apiUnit.ClosePort("tcp", 1234) 428 c.Assert(err, jc.ErrorIsNil) 429 430 ports, err = s.wordpressUnit.OpenedPorts() 431 c.Assert(err, jc.ErrorIsNil) 432 c.Assert(ports, gc.HasLen, 0) 433 } 434 435 func (s *unitSuite) TestGetSetCharmURL(c *gc.C) { 436 // No charm URL set yet. 437 curl, ok := s.wordpressUnit.CharmURL() 438 c.Assert(curl, gc.IsNil) 439 c.Assert(ok, jc.IsFalse) 440 441 // Now check the same through the API. 442 _, err := s.apiUnit.CharmURL() 443 c.Assert(err, gc.Equals, uniter.ErrNoCharmURLSet) 444 445 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 446 c.Assert(err, jc.ErrorIsNil) 447 448 curl, err = s.apiUnit.CharmURL() 449 c.Assert(err, jc.ErrorIsNil) 450 c.Assert(curl, gc.NotNil) 451 c.Assert(curl.String(), gc.Equals, s.wordpressCharm.String()) 452 } 453 454 func (s *unitSuite) TestConfigSettings(c *gc.C) { 455 // Make sure ConfigSettings returns an error when 456 // no charm URL is set, as its state counterpart does. 457 settings, err := s.apiUnit.ConfigSettings() 458 c.Assert(err, gc.ErrorMatches, "unit charm not set") 459 460 // Now set the charm and try again. 461 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 462 c.Assert(err, jc.ErrorIsNil) 463 464 settings, err = s.apiUnit.ConfigSettings() 465 c.Assert(err, jc.ErrorIsNil) 466 c.Assert(settings, gc.DeepEquals, charm.Settings{ 467 "blog-title": "My Title", 468 }) 469 470 // Update the config and check we get the changes on the next call. 471 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 472 "blog-title": "superhero paparazzi", 473 }) 474 c.Assert(err, jc.ErrorIsNil) 475 476 settings, err = s.apiUnit.ConfigSettings() 477 c.Assert(err, jc.ErrorIsNil) 478 c.Assert(settings, gc.DeepEquals, charm.Settings{ 479 "blog-title": "superhero paparazzi", 480 }) 481 } 482 483 func (s *unitSuite) TestWatchConfigSettings(c *gc.C) { 484 // Make sure WatchConfigSettings returns an error when 485 // no charm URL is set, as its state counterpart does. 486 w, err := s.apiUnit.WatchConfigSettings() 487 c.Assert(err, gc.ErrorMatches, "unit charm not set") 488 489 // Now set the charm and try again. 490 err = s.apiUnit.SetCharmURL(s.wordpressCharm.URL()) 491 c.Assert(err, jc.ErrorIsNil) 492 493 w, err = s.apiUnit.WatchConfigSettings() 494 defer statetesting.AssertStop(c, w) 495 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 496 497 // Initial event. 498 wc.AssertOneChange() 499 500 // Update config a couple of times, check a single event. 501 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 502 "blog-title": "superhero paparazzi", 503 }) 504 c.Assert(err, jc.ErrorIsNil) 505 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 506 "blog-title": "sauceror central", 507 }) 508 c.Assert(err, jc.ErrorIsNil) 509 wc.AssertOneChange() 510 511 // Non-change is not reported. 512 err = s.wordpressService.UpdateConfigSettings(charm.Settings{ 513 "blog-title": "sauceror central", 514 }) 515 c.Assert(err, jc.ErrorIsNil) 516 wc.AssertNoChange() 517 518 // NOTE: This test is not as exhaustive as the one in state, 519 // because the watcher is already tested there. Here we just 520 // ensure we get the events when we expect them and don't get 521 // them when they're not expected. 522 523 statetesting.AssertStop(c, w) 524 wc.AssertClosed() 525 } 526 527 func (s *unitSuite) TestWatchActionNotifications(c *gc.C) { 528 w, err := s.apiUnit.WatchActionNotifications() 529 c.Assert(err, jc.ErrorIsNil) 530 531 defer statetesting.AssertStop(c, w) 532 wc := statetesting.NewStringsWatcherC(c, s.BackingState, w) 533 534 // Initial event. 535 wc.AssertChange() 536 537 // Add a couple of actions and make sure the changes are detected. 538 action, err := s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{ 539 "outfile": "foo.txt", 540 }) 541 c.Assert(err, jc.ErrorIsNil) 542 wc.AssertChange(action.Id()) 543 544 action, err = s.wordpressUnit.AddAction("fakeaction", map[string]interface{}{ 545 "outfile": "foo.bz2", 546 "compression": map[string]interface{}{ 547 "kind": "bzip", 548 "quality": float64(5.0), 549 }, 550 }) 551 c.Assert(err, jc.ErrorIsNil) 552 wc.AssertChange(action.Id()) 553 554 statetesting.AssertStop(c, w) 555 wc.AssertClosed() 556 } 557 558 func (s *unitSuite) TestWatchActionNotificationsError(c *gc.C) { 559 uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications", 560 func(result interface{}) error { 561 return fmt.Errorf("Test error") 562 }, 563 ) 564 565 _, err := s.apiUnit.WatchActionNotifications() 566 c.Assert(err.Error(), gc.Equals, "Test error") 567 } 568 569 func (s *unitSuite) TestWatchActionNotificationsErrorResults(c *gc.C) { 570 uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications", 571 func(results interface{}) error { 572 if results, ok := results.(*params.StringsWatchResults); ok { 573 results.Results = make([]params.StringsWatchResult, 1) 574 results.Results[0] = params.StringsWatchResult{ 575 Error: ¶ms.Error{ 576 Message: "An error in the watch result.", 577 Code: params.CodeNotAssigned, 578 }, 579 } 580 } 581 return nil 582 }, 583 ) 584 585 _, err := s.apiUnit.WatchActionNotifications() 586 c.Assert(err.Error(), gc.Equals, "An error in the watch result.") 587 } 588 589 func (s *unitSuite) TestWatchActionNotificationsNoResults(c *gc.C) { 590 uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications", 591 func(results interface{}) error { 592 return nil 593 }, 594 ) 595 596 _, err := s.apiUnit.WatchActionNotifications() 597 c.Assert(err.Error(), gc.Equals, "expected 1 result, got 0") 598 } 599 600 func (s *unitSuite) TestWatchActionNotificationsMoreResults(c *gc.C) { 601 uniter.PatchUnitResponse(s, s.apiUnit, "WatchActionNotifications", 602 func(results interface{}) error { 603 if results, ok := results.(*params.StringsWatchResults); ok { 604 results.Results = make([]params.StringsWatchResult, 2) 605 } 606 return nil 607 }, 608 ) 609 610 _, err := s.apiUnit.WatchActionNotifications() 611 c.Assert(err.Error(), gc.Equals, "expected 1 result, got 2") 612 } 613 614 func (s *unitSuite) TestServiceNameAndTag(c *gc.C) { 615 c.Assert(s.apiUnit.ServiceName(), gc.Equals, s.wordpressService.Name()) 616 c.Assert(s.apiUnit.ServiceTag(), gc.Equals, s.wordpressService.Tag()) 617 } 618 619 func (s *unitSuite) TestJoinedRelations(c *gc.C) { 620 joinedRelations, err := s.apiUnit.JoinedRelations() 621 c.Assert(err, jc.ErrorIsNil) 622 c.Assert(joinedRelations, gc.HasLen, 0) 623 624 rel1, _, _ := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 625 joinedRelations, err = s.apiUnit.JoinedRelations() 626 c.Assert(err, jc.ErrorIsNil) 627 c.Assert(joinedRelations, gc.DeepEquals, []names.RelationTag{ 628 rel1.Tag().(names.RelationTag), 629 }) 630 631 rel2, _, _ := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 632 joinedRelations, err = s.apiUnit.JoinedRelations() 633 c.Assert(err, jc.ErrorIsNil) 634 c.Assert(joinedRelations, jc.SameContents, []names.RelationTag{ 635 rel1.Tag().(names.RelationTag), 636 rel2.Tag().(names.RelationTag), 637 }) 638 } 639 640 func (s *unitSuite) TestWatchAddresses(c *gc.C) { 641 w, err := s.apiUnit.WatchAddresses() 642 defer statetesting.AssertStop(c, w) 643 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 644 645 // Initial event. 646 wc.AssertOneChange() 647 648 // Update config a couple of times, check a single event. 649 err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.3")) 650 c.Assert(err, jc.ErrorIsNil) 651 err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4")) 652 c.Assert(err, jc.ErrorIsNil) 653 wc.AssertOneChange() 654 655 // Non-change is not reported. 656 err = s.wordpressMachine.SetProviderAddresses(network.NewAddress("0.1.2.4")) 657 c.Assert(err, jc.ErrorIsNil) 658 wc.AssertNoChange() 659 660 // Change is reported for machine addresses. 661 err = s.wordpressMachine.SetMachineAddresses(network.NewAddress("0.1.2.5")) 662 c.Assert(err, jc.ErrorIsNil) 663 wc.AssertOneChange() 664 665 // Set machine addresses to empty is reported. 666 err = s.wordpressMachine.SetMachineAddresses() 667 c.Assert(err, jc.ErrorIsNil) 668 wc.AssertOneChange() 669 670 // NOTE: This test is not as exhaustive as the one in state, 671 // because the watcher is already tested there. Here we just 672 // ensure we get the events when we expect them and don't get 673 // them when they're not expected. 674 675 statetesting.AssertStop(c, w) 676 wc.AssertClosed() 677 } 678 679 func (s *unitSuite) TestWatchAddressesErrors(c *gc.C) { 680 err := s.wordpressUnit.UnassignFromMachine() 681 c.Assert(err, jc.ErrorIsNil) 682 _, err = s.apiUnit.WatchAddresses() 683 c.Assert(err, jc.Satisfies, params.IsCodeNotAssigned) 684 } 685 686 func (s *unitSuite) TestAddMetrics(c *gc.C) { 687 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 688 func(results interface{}) error { 689 result := results.(*params.ErrorResults) 690 result.Results = make([]params.ErrorResult, 1) 691 return nil 692 }, 693 ) 694 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 695 err := s.apiUnit.AddMetrics(metrics) 696 c.Assert(err, jc.ErrorIsNil) 697 } 698 699 func (s *unitSuite) TestAddMetricsError(c *gc.C) { 700 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 701 func(results interface{}) error { 702 result := results.(*params.ErrorResults) 703 result.Results = make([]params.ErrorResult, 1) 704 return fmt.Errorf("test error") 705 }, 706 ) 707 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 708 err := s.apiUnit.AddMetrics(metrics) 709 c.Assert(err, gc.ErrorMatches, "unable to add metric: test error") 710 } 711 712 func (s *unitSuite) TestAddMetricsResultError(c *gc.C) { 713 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 714 func(results interface{}) error { 715 result := results.(*params.ErrorResults) 716 result.Results = make([]params.ErrorResult, 1) 717 result.Results[0].Error = ¶ms.Error{ 718 Message: "error adding metrics", 719 Code: params.CodeNotAssigned, 720 } 721 return nil 722 }, 723 ) 724 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 725 err := s.apiUnit.AddMetrics(metrics) 726 c.Assert(err, gc.ErrorMatches, "error adding metrics") 727 } 728 729 func (s *unitSuite) TestMeterStatus(c *gc.C) { 730 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 731 func(results interface{}) error { 732 result := results.(*params.MeterStatusResults) 733 result.Results = make([]params.MeterStatusResult, 1) 734 result.Results[0].Code = "GREEN" 735 result.Results[0].Info = "All ok." 736 return nil 737 }, 738 ) 739 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 740 c.Assert(err, jc.ErrorIsNil) 741 c.Assert(statusCode, gc.Equals, "GREEN") 742 c.Assert(statusInfo, gc.Equals, "All ok.") 743 } 744 745 func (s *unitSuite) TestMeterStatusError(c *gc.C) { 746 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 747 func(results interface{}) error { 748 result := results.(*params.MeterStatusResults) 749 result.Results = make([]params.MeterStatusResult, 1) 750 return fmt.Errorf("boo") 751 }, 752 ) 753 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 754 c.Assert(err, gc.ErrorMatches, "boo") 755 c.Assert(statusCode, gc.Equals, "") 756 c.Assert(statusInfo, gc.Equals, "") 757 } 758 759 func (s *unitSuite) TestMeterStatusResultError(c *gc.C) { 760 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 761 func(results interface{}) error { 762 result := results.(*params.MeterStatusResults) 763 result.Results = make([]params.MeterStatusResult, 1) 764 result.Results[0].Error = ¶ms.Error{ 765 Message: "error getting meter status", 766 Code: params.CodeNotAssigned, 767 } 768 return nil 769 }, 770 ) 771 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 772 c.Assert(err, gc.ErrorMatches, "error getting meter status") 773 c.Assert(statusCode, gc.Equals, "") 774 c.Assert(statusInfo, gc.Equals, "") 775 } 776 777 func (s *unitSuite) TestWatchMeterStatus(c *gc.C) { 778 w, err := s.apiUnit.WatchMeterStatus() 779 defer statetesting.AssertStop(c, w) 780 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 781 782 // Initial event. 783 wc.AssertOneChange() 784 785 err = s.wordpressUnit.SetMeterStatus("GREEN", "ok") 786 c.Assert(err, jc.ErrorIsNil) 787 err = s.wordpressUnit.SetMeterStatus("AMBER", "ok") 788 c.Assert(err, jc.ErrorIsNil) 789 wc.AssertOneChange() 790 791 // Non-change is not reported. 792 err = s.wordpressUnit.SetMeterStatus("AMBER", "ok") 793 c.Assert(err, jc.ErrorIsNil) 794 wc.AssertNoChange() 795 796 mm, err := s.State.MetricsManager() 797 c.Assert(err, jc.ErrorIsNil) 798 err = mm.SetLastSuccessfulSend(time.Now()) 799 c.Assert(err, jc.ErrorIsNil) 800 for i := 0; i < 3; i++ { 801 err := mm.IncrementConsecutiveErrors() 802 c.Assert(err, jc.ErrorIsNil) 803 } 804 status := mm.MeterStatus() 805 c.Assert(status.Code, gc.Equals, state.MeterAmber) // Confirm meter status has changed 806 wc.AssertOneChange() 807 808 statetesting.AssertStop(c, w) 809 wc.AssertClosed() 810 } 811 812 func (s *unitSuite) patchNewState( 813 c *gc.C, 814 patchFunc func(_ base.APICaller, _ names.UnitTag) *uniter.State, 815 ) { 816 s.uniterSuite.patchNewState(c, patchFunc) 817 var err error 818 s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag)) 819 c.Assert(err, jc.ErrorIsNil) 820 } 821 822 type unitMetricBatchesSuite struct { 823 testing.JujuConnSuite 824 825 st api.Connection 826 uniter *uniter.State 827 apiUnit *uniter.Unit 828 charm *state.Charm 829 } 830 831 var _ = gc.Suite(&unitMetricBatchesSuite{}) 832 833 func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) { 834 s.JujuConnSuite.SetUpTest(c) 835 836 s.charm = s.Factory.MakeCharm(c, &jujufactory.CharmParams{ 837 Name: "metered", 838 URL: "cs:quantal/metered", 839 }) 840 service := s.Factory.MakeService(c, &jujufactory.ServiceParams{ 841 Charm: s.charm, 842 }) 843 unit := s.Factory.MakeUnit(c, &jujufactory.UnitParams{ 844 Service: service, 845 SetCharmURL: true, 846 }) 847 848 password, err := utils.RandomPassword() 849 c.Assert(err, jc.ErrorIsNil) 850 err = unit.SetPassword(password) 851 c.Assert(err, jc.ErrorIsNil) 852 s.st = s.OpenAPIAs(c, unit.Tag(), password) 853 854 // Create the uniter API facade. 855 s.uniter, err = s.st.Uniter() 856 c.Assert(err, jc.ErrorIsNil) 857 c.Assert(s.uniter, gc.NotNil) 858 859 s.apiUnit, err = s.uniter.Unit(unit.Tag().(names.UnitTag)) 860 c.Assert(err, jc.ErrorIsNil) 861 } 862 863 func (s *unitMetricBatchesSuite) TestSendMetricBatchPatch(c *gc.C) { 864 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 865 uuid := utils.MustNewUUID().String() 866 batch := params.MetricBatch{ 867 UUID: uuid, 868 CharmURL: s.charm.URL().String(), 869 Created: time.Now(), 870 Metrics: metrics, 871 } 872 873 var called bool 874 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches", 875 func(response interface{}) error { 876 called = true 877 result := response.(*params.ErrorResults) 878 result.Results = make([]params.ErrorResult, 1) 879 return nil 880 }) 881 882 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 883 c.Assert(err, jc.ErrorIsNil) 884 c.Assert(results, gc.HasLen, 1) 885 c.Assert(results[batch.UUID], gc.IsNil) 886 c.Assert(called, jc.IsTrue) 887 } 888 889 func (s *unitMetricBatchesSuite) TestSendMetricBatchFail(c *gc.C) { 890 var called bool 891 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches", 892 func(response interface{}) error { 893 called = true 894 result := response.(*params.ErrorResults) 895 result.Results = make([]params.ErrorResult, 1) 896 result.Results[0].Error = common.ServerError(common.ErrPerm) 897 return nil 898 }) 899 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 900 uuid := utils.MustNewUUID().String() 901 batch := params.MetricBatch{ 902 UUID: uuid, 903 CharmURL: s.charm.URL().String(), 904 Created: time.Now(), 905 Metrics: metrics, 906 } 907 908 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 909 c.Assert(err, jc.ErrorIsNil) 910 c.Assert(results, gc.HasLen, 1) 911 c.Assert(results[batch.UUID], gc.ErrorMatches, "permission denied") 912 c.Assert(called, jc.IsTrue) 913 } 914 915 func (s *unitMetricBatchesSuite) TestSendMetricBatchNotImplemented(c *gc.C) { 916 var called bool 917 uniter.PatchUnitFacadeCall(s, s.apiUnit, func(request string, args, response interface{}) error { 918 switch request { 919 case "AddMetricBatches": 920 result := response.(*params.ErrorResults) 921 result.Results = make([]params.ErrorResult, 1) 922 return ¶ms.Error{"not implemented", params.CodeNotImplemented} 923 case "AddMetrics": 924 called = true 925 result := response.(*params.ErrorResults) 926 result.Results = make([]params.ErrorResult, 1) 927 return nil 928 default: 929 panic(fmt.Errorf("unexpected request %q received", request)) 930 } 931 }) 932 933 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 934 uuid := utils.MustNewUUID().String() 935 batch := params.MetricBatch{ 936 UUID: uuid, 937 CharmURL: s.charm.URL().String(), 938 Created: time.Now(), 939 Metrics: metrics, 940 } 941 942 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 943 c.Assert(err, jc.ErrorIsNil) 944 c.Assert(called, jc.IsTrue) 945 c.Assert(results, gc.HasLen, 1) 946 c.Assert(results[batch.UUID], gc.IsNil) 947 } 948 949 func (s *unitMetricBatchesSuite) TestSendMetricBatch(c *gc.C) { 950 uuid := utils.MustNewUUID().String() 951 now := time.Now().Round(time.Second).UTC() 952 metrics := []params.Metric{{"pings", "5", now}} 953 batch := params.MetricBatch{ 954 UUID: uuid, 955 CharmURL: s.charm.URL().String(), 956 Created: now, 957 Metrics: metrics, 958 } 959 960 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 961 c.Assert(err, jc.ErrorIsNil) 962 c.Assert(results, gc.HasLen, 1) 963 c.Assert(results[batch.UUID], gc.IsNil) 964 965 batches, err := s.State.MetricBatches() 966 c.Assert(err, gc.IsNil) 967 c.Assert(batches, gc.HasLen, 1) 968 c.Assert(batches[0].UUID(), gc.Equals, uuid) 969 c.Assert(batches[0].Sent(), jc.IsFalse) 970 c.Assert(batches[0].CharmURL(), gc.Equals, s.charm.URL().String()) 971 c.Assert(batches[0].Metrics(), gc.HasLen, 1) 972 c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings") 973 c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings") 974 c.Assert(batches[0].Metrics()[0].Value, gc.Equals, "5") 975 }