github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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 // NOTE: This test is not as exhaustive as the one in state, 661 // because the watcher is already tested there. Here we just 662 // ensure we get the events when we expect them and don't get 663 // them when they're not expected. 664 665 statetesting.AssertStop(c, w) 666 wc.AssertClosed() 667 } 668 669 func (s *unitSuite) TestWatchAddressesErrors(c *gc.C) { 670 err := s.wordpressUnit.UnassignFromMachine() 671 c.Assert(err, jc.ErrorIsNil) 672 _, err = s.apiUnit.WatchAddresses() 673 c.Assert(err, jc.Satisfies, params.IsCodeNotAssigned) 674 } 675 676 func (s *unitSuite) TestAddMetrics(c *gc.C) { 677 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 678 func(results interface{}) error { 679 result := results.(*params.ErrorResults) 680 result.Results = make([]params.ErrorResult, 1) 681 return nil 682 }, 683 ) 684 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 685 err := s.apiUnit.AddMetrics(metrics) 686 c.Assert(err, jc.ErrorIsNil) 687 } 688 689 func (s *unitSuite) TestAddMetricsError(c *gc.C) { 690 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 691 func(results interface{}) error { 692 result := results.(*params.ErrorResults) 693 result.Results = make([]params.ErrorResult, 1) 694 return fmt.Errorf("test error") 695 }, 696 ) 697 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 698 err := s.apiUnit.AddMetrics(metrics) 699 c.Assert(err, gc.ErrorMatches, "unable to add metric: test error") 700 } 701 702 func (s *unitSuite) TestAddMetricsResultError(c *gc.C) { 703 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetrics", 704 func(results interface{}) error { 705 result := results.(*params.ErrorResults) 706 result.Results = make([]params.ErrorResult, 1) 707 result.Results[0].Error = ¶ms.Error{ 708 Message: "error adding metrics", 709 Code: params.CodeNotAssigned, 710 } 711 return nil 712 }, 713 ) 714 metrics := []params.Metric{{"A", "23", time.Now()}, {"B", "27.0", time.Now()}} 715 err := s.apiUnit.AddMetrics(metrics) 716 c.Assert(err, gc.ErrorMatches, "error adding metrics") 717 } 718 719 func (s *unitSuite) TestMeterStatus(c *gc.C) { 720 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 721 func(results interface{}) error { 722 result := results.(*params.MeterStatusResults) 723 result.Results = make([]params.MeterStatusResult, 1) 724 result.Results[0].Code = "GREEN" 725 result.Results[0].Info = "All ok." 726 return nil 727 }, 728 ) 729 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 730 c.Assert(err, jc.ErrorIsNil) 731 c.Assert(statusCode, gc.Equals, "GREEN") 732 c.Assert(statusInfo, gc.Equals, "All ok.") 733 } 734 735 func (s *unitSuite) TestMeterStatusError(c *gc.C) { 736 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 737 func(results interface{}) error { 738 result := results.(*params.MeterStatusResults) 739 result.Results = make([]params.MeterStatusResult, 1) 740 return fmt.Errorf("boo") 741 }, 742 ) 743 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 744 c.Assert(err, gc.ErrorMatches, "boo") 745 c.Assert(statusCode, gc.Equals, "") 746 c.Assert(statusInfo, gc.Equals, "") 747 } 748 749 func (s *unitSuite) TestMeterStatusResultError(c *gc.C) { 750 uniter.PatchUnitResponse(s, s.apiUnit, "GetMeterStatus", 751 func(results interface{}) error { 752 result := results.(*params.MeterStatusResults) 753 result.Results = make([]params.MeterStatusResult, 1) 754 result.Results[0].Error = ¶ms.Error{ 755 Message: "error getting meter status", 756 Code: params.CodeNotAssigned, 757 } 758 return nil 759 }, 760 ) 761 statusCode, statusInfo, err := s.apiUnit.MeterStatus() 762 c.Assert(err, gc.ErrorMatches, "error getting meter status") 763 c.Assert(statusCode, gc.Equals, "") 764 c.Assert(statusInfo, gc.Equals, "") 765 } 766 767 func (s *unitSuite) TestWatchMeterStatus(c *gc.C) { 768 w, err := s.apiUnit.WatchMeterStatus() 769 defer statetesting.AssertStop(c, w) 770 wc := statetesting.NewNotifyWatcherC(c, s.BackingState, w) 771 772 // Initial event. 773 wc.AssertOneChange() 774 775 err = s.wordpressUnit.SetMeterStatus("GREEN", "ok") 776 c.Assert(err, jc.ErrorIsNil) 777 err = s.wordpressUnit.SetMeterStatus("AMBER", "ok") 778 c.Assert(err, jc.ErrorIsNil) 779 wc.AssertOneChange() 780 781 // Non-change is not reported. 782 err = s.wordpressUnit.SetMeterStatus("AMBER", "ok") 783 c.Assert(err, jc.ErrorIsNil) 784 wc.AssertNoChange() 785 786 mm, err := s.State.MetricsManager() 787 c.Assert(err, jc.ErrorIsNil) 788 err = mm.SetLastSuccessfulSend(time.Now()) 789 c.Assert(err, jc.ErrorIsNil) 790 for i := 0; i < 3; i++ { 791 err := mm.IncrementConsecutiveErrors() 792 c.Assert(err, jc.ErrorIsNil) 793 } 794 status := mm.MeterStatus() 795 c.Assert(status.Code, gc.Equals, state.MeterAmber) // Confirm meter status has changed 796 wc.AssertOneChange() 797 798 statetesting.AssertStop(c, w) 799 wc.AssertClosed() 800 } 801 802 func (s *unitSuite) patchNewState( 803 c *gc.C, 804 patchFunc func(_ base.APICaller, _ names.UnitTag) *uniter.State, 805 ) { 806 s.uniterSuite.patchNewState(c, patchFunc) 807 var err error 808 s.apiUnit, err = s.uniter.Unit(s.wordpressUnit.Tag().(names.UnitTag)) 809 c.Assert(err, jc.ErrorIsNil) 810 } 811 812 type unitMetricBatchesSuite struct { 813 testing.JujuConnSuite 814 815 st *api.State 816 uniter *uniter.State 817 apiUnit *uniter.Unit 818 charm *state.Charm 819 } 820 821 var _ = gc.Suite(&unitMetricBatchesSuite{}) 822 823 func (s *unitMetricBatchesSuite) SetUpTest(c *gc.C) { 824 s.JujuConnSuite.SetUpTest(c) 825 826 s.charm = s.Factory.MakeCharm(c, &jujufactory.CharmParams{ 827 Name: "metered", 828 URL: "cs:quantal/metered", 829 }) 830 service := s.Factory.MakeService(c, &jujufactory.ServiceParams{ 831 Charm: s.charm, 832 }) 833 unit := s.Factory.MakeUnit(c, &jujufactory.UnitParams{ 834 Service: service, 835 SetCharmURL: true, 836 }) 837 838 password, err := utils.RandomPassword() 839 c.Assert(err, jc.ErrorIsNil) 840 err = unit.SetPassword(password) 841 c.Assert(err, jc.ErrorIsNil) 842 s.st = s.OpenAPIAs(c, unit.Tag(), password) 843 844 // Create the uniter API facade. 845 s.uniter, err = s.st.Uniter() 846 c.Assert(err, jc.ErrorIsNil) 847 c.Assert(s.uniter, gc.NotNil) 848 849 s.apiUnit, err = s.uniter.Unit(unit.Tag().(names.UnitTag)) 850 c.Assert(err, jc.ErrorIsNil) 851 } 852 853 func (s *unitMetricBatchesSuite) TestSendMetricBatchPatch(c *gc.C) { 854 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 855 uuid := utils.MustNewUUID().String() 856 batch := params.MetricBatch{ 857 UUID: uuid, 858 CharmURL: s.charm.URL().String(), 859 Created: time.Now(), 860 Metrics: metrics, 861 } 862 863 var called bool 864 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches", 865 func(response interface{}) error { 866 called = true 867 result := response.(*params.ErrorResults) 868 result.Results = make([]params.ErrorResult, 1) 869 return nil 870 }) 871 872 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 873 c.Assert(err, jc.ErrorIsNil) 874 c.Assert(results, gc.HasLen, 1) 875 c.Assert(results[batch.UUID], gc.IsNil) 876 c.Assert(called, jc.IsTrue) 877 } 878 879 func (s *unitMetricBatchesSuite) TestSendMetricBatchFail(c *gc.C) { 880 var called bool 881 uniter.PatchUnitResponse(s, s.apiUnit, "AddMetricBatches", 882 func(response interface{}) error { 883 called = true 884 result := response.(*params.ErrorResults) 885 result.Results = make([]params.ErrorResult, 1) 886 result.Results[0].Error = common.ServerError(common.ErrPerm) 887 return nil 888 }) 889 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 890 uuid := utils.MustNewUUID().String() 891 batch := params.MetricBatch{ 892 UUID: uuid, 893 CharmURL: s.charm.URL().String(), 894 Created: time.Now(), 895 Metrics: metrics, 896 } 897 898 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 899 c.Assert(err, jc.ErrorIsNil) 900 c.Assert(results, gc.HasLen, 1) 901 c.Assert(results[batch.UUID], gc.ErrorMatches, "permission denied") 902 c.Assert(called, jc.IsTrue) 903 } 904 905 func (s *unitMetricBatchesSuite) TestSendMetricBatchNotImplemented(c *gc.C) { 906 var called bool 907 uniter.PatchUnitFacadeCall(s, s.apiUnit, func(request string, args, response interface{}) error { 908 switch request { 909 case "AddMetricBatches": 910 result := response.(*params.ErrorResults) 911 result.Results = make([]params.ErrorResult, 1) 912 return ¶ms.Error{"not implemented", params.CodeNotImplemented} 913 case "AddMetrics": 914 called = true 915 result := response.(*params.ErrorResults) 916 result.Results = make([]params.ErrorResult, 1) 917 return nil 918 default: 919 panic(fmt.Errorf("unexpected request %q received", request)) 920 } 921 }) 922 923 metrics := []params.Metric{{"pings", "5", time.Now().UTC()}} 924 uuid := utils.MustNewUUID().String() 925 batch := params.MetricBatch{ 926 UUID: uuid, 927 CharmURL: s.charm.URL().String(), 928 Created: time.Now(), 929 Metrics: metrics, 930 } 931 932 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 933 c.Assert(err, jc.ErrorIsNil) 934 c.Assert(called, jc.IsTrue) 935 c.Assert(results, gc.HasLen, 1) 936 c.Assert(results[batch.UUID], gc.IsNil) 937 } 938 939 func (s *unitMetricBatchesSuite) TestSendMetricBatch(c *gc.C) { 940 uuid := utils.MustNewUUID().String() 941 now := time.Now().Round(time.Second).UTC() 942 metrics := []params.Metric{{"pings", "5", now}} 943 batch := params.MetricBatch{ 944 UUID: uuid, 945 CharmURL: s.charm.URL().String(), 946 Created: now, 947 Metrics: metrics, 948 } 949 950 results, err := s.apiUnit.AddMetricBatches([]params.MetricBatch{batch}) 951 c.Assert(err, jc.ErrorIsNil) 952 c.Assert(results, gc.HasLen, 1) 953 c.Assert(results[batch.UUID], gc.IsNil) 954 955 batches, err := s.State.MetricBatches() 956 c.Assert(err, gc.IsNil) 957 c.Assert(batches, gc.HasLen, 1) 958 c.Assert(batches[0].UUID(), gc.Equals, uuid) 959 c.Assert(batches[0].Sent(), jc.IsFalse) 960 c.Assert(batches[0].CharmURL(), gc.Equals, s.charm.URL().String()) 961 c.Assert(batches[0].Metrics(), gc.HasLen, 1) 962 c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings") 963 c.Assert(batches[0].Metrics()[0].Key, gc.Equals, "pings") 964 c.Assert(batches[0].Metrics()[0].Value, gc.Equals, "5") 965 }