github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/uniter/uniter_base_test.go (about) 1 // Copyright 2014 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/apiserver/common" 18 "github.com/juju/juju/apiserver/params" 19 apiservertesting "github.com/juju/juju/apiserver/testing" 20 "github.com/juju/juju/apiserver/uniter" 21 "github.com/juju/juju/juju/testing" 22 "github.com/juju/juju/network" 23 "github.com/juju/juju/state" 24 "github.com/juju/juju/state/multiwatcher" 25 statetesting "github.com/juju/juju/state/testing" 26 coretesting "github.com/juju/juju/testing" 27 jujuFactory "github.com/juju/juju/testing/factory" 28 ) 29 30 // uniterBaseSuite implements common testing suite for all API 31 // versions. It's not intended to be used directly or registered as a 32 // suite, but embedded. 33 type uniterBaseSuite struct { 34 testing.JujuConnSuite 35 36 authorizer apiservertesting.FakeAuthorizer 37 resources *common.Resources 38 39 machine0 *state.Machine 40 machine1 *state.Machine 41 wordpress *state.Service 42 wpCharm *state.Charm 43 mysql *state.Service 44 wordpressUnit *state.Unit 45 mysqlUnit *state.Unit 46 47 meteredService *state.Service 48 meteredCharm *state.Charm 49 meteredUnit *state.Unit 50 } 51 52 func (s *uniterBaseSuite) setUpTest(c *gc.C) { 53 s.JujuConnSuite.SetUpTest(c) 54 55 factory := jujuFactory.NewFactory(s.State) 56 // Create two machines, two services and add a unit to each service. 57 s.machine0 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 58 Series: "quantal", 59 Jobs: []state.MachineJob{state.JobHostUnits, state.JobManageEnviron}, 60 }) 61 s.machine1 = factory.MakeMachine(c, &jujuFactory.MachineParams{ 62 Series: "quantal", 63 Jobs: []state.MachineJob{state.JobHostUnits}, 64 }) 65 s.wpCharm = factory.MakeCharm(c, &jujuFactory.CharmParams{ 66 Name: "wordpress", 67 URL: "cs:quantal/wordpress-3", 68 }) 69 s.wordpress = factory.MakeService(c, &jujuFactory.ServiceParams{ 70 Name: "wordpress", 71 Charm: s.wpCharm, 72 Creator: s.AdminUserTag(c), 73 }) 74 mysqlCharm := factory.MakeCharm(c, &jujuFactory.CharmParams{ 75 Name: "mysql", 76 }) 77 s.mysql = factory.MakeService(c, &jujuFactory.ServiceParams{ 78 Name: "mysql", 79 Charm: mysqlCharm, 80 Creator: s.AdminUserTag(c), 81 }) 82 s.wordpressUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 83 Service: s.wordpress, 84 Machine: s.machine0, 85 }) 86 s.mysqlUnit = factory.MakeUnit(c, &jujuFactory.UnitParams{ 87 Service: s.mysql, 88 Machine: s.machine1, 89 }) 90 91 s.meteredCharm = s.Factory.MakeCharm(c, &jujuFactory.CharmParams{ 92 Name: "metered", 93 URL: "cs:quantal/metered", 94 }) 95 s.meteredService = s.Factory.MakeService(c, &jujuFactory.ServiceParams{ 96 Charm: s.meteredCharm, 97 }) 98 s.meteredUnit = s.Factory.MakeUnit(c, &jujuFactory.UnitParams{ 99 Service: s.meteredService, 100 SetCharmURL: true, 101 }) 102 103 // Create a FakeAuthorizer so we can check permissions, 104 // set up assuming unit 0 has logged in. 105 s.authorizer = apiservertesting.FakeAuthorizer{ 106 Tag: s.wordpressUnit.Tag(), 107 } 108 109 // Create the resource registry separately to track invocations to 110 // Register. 111 s.resources = common.NewResources() 112 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 113 } 114 115 func (s *uniterBaseSuite) testUniterFailsWithNonUnitAgentUser( 116 c *gc.C, 117 factory func(_ *state.State, _ *common.Resources, _ common.Authorizer) error, 118 ) { 119 anAuthorizer := s.authorizer 120 anAuthorizer.Tag = names.NewMachineTag("9") 121 err := factory(s.State, s.resources, anAuthorizer) 122 c.Assert(err, gc.NotNil) 123 c.Assert(err, gc.ErrorMatches, "permission denied") 124 } 125 126 func (s *uniterBaseSuite) testSetStatus( 127 c *gc.C, 128 facade interface { 129 SetStatus(args params.SetStatus) (params.ErrorResults, error) 130 }, 131 ) { 132 err := s.wordpressUnit.SetAgentStatus(state.StatusExecuting, "blah", nil) 133 c.Assert(err, jc.ErrorIsNil) 134 err = s.mysqlUnit.SetAgentStatus(state.StatusExecuting, "foo", nil) 135 c.Assert(err, jc.ErrorIsNil) 136 137 args := params.SetStatus{ 138 Entities: []params.EntityStatusArgs{ 139 {Tag: "unit-mysql-0", Status: params.StatusError, Info: "not really"}, 140 {Tag: "unit-wordpress-0", Status: params.StatusRebooting, Info: "foobar"}, 141 {Tag: "unit-foo-42", Status: params.StatusActive, Info: "blah"}, 142 }} 143 result, err := facade.SetStatus(args) 144 c.Assert(err, jc.ErrorIsNil) 145 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 146 Results: []params.ErrorResult{ 147 {apiservertesting.ErrUnauthorized}, 148 {nil}, 149 {apiservertesting.ErrUnauthorized}, 150 }, 151 }) 152 153 // Verify mysqlUnit - no change. 154 statusInfo, err := s.mysqlUnit.AgentStatus() 155 c.Assert(err, jc.ErrorIsNil) 156 c.Assert(statusInfo.Status, gc.Equals, state.StatusExecuting) 157 c.Assert(statusInfo.Message, gc.Equals, "foo") 158 // ...wordpressUnit is fine though. 159 statusInfo, err = s.wordpressUnit.AgentStatus() 160 c.Assert(err, jc.ErrorIsNil) 161 c.Assert(statusInfo.Status, gc.Equals, state.StatusRebooting) 162 c.Assert(statusInfo.Message, gc.Equals, "foobar") 163 } 164 165 func (s *uniterBaseSuite) testSetAgentStatus( 166 c *gc.C, 167 facade interface { 168 SetAgentStatus(args params.SetStatus) (params.ErrorResults, error) 169 }, 170 ) { 171 err := s.wordpressUnit.SetAgentStatus(state.StatusExecuting, "blah", nil) 172 c.Assert(err, jc.ErrorIsNil) 173 err = s.mysqlUnit.SetAgentStatus(state.StatusExecuting, "foo", nil) 174 c.Assert(err, jc.ErrorIsNil) 175 176 args := params.SetStatus{ 177 Entities: []params.EntityStatusArgs{ 178 {Tag: "unit-mysql-0", Status: params.StatusError, Info: "not really"}, 179 {Tag: "unit-wordpress-0", Status: params.StatusExecuting, Info: "foobar"}, 180 {Tag: "unit-foo-42", Status: params.StatusRebooting, Info: "blah"}, 181 }} 182 result, err := facade.SetAgentStatus(args) 183 c.Assert(err, jc.ErrorIsNil) 184 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 185 Results: []params.ErrorResult{ 186 {apiservertesting.ErrUnauthorized}, 187 {nil}, 188 {apiservertesting.ErrUnauthorized}, 189 }, 190 }) 191 192 // Verify mysqlUnit - no change. 193 statusInfo, err := s.mysqlUnit.AgentStatus() 194 c.Assert(err, jc.ErrorIsNil) 195 c.Assert(statusInfo.Status, gc.Equals, state.StatusExecuting) 196 c.Assert(statusInfo.Message, gc.Equals, "foo") 197 // ...wordpressUnit is fine though. 198 statusInfo, err = s.wordpressUnit.AgentStatus() 199 c.Assert(err, jc.ErrorIsNil) 200 c.Assert(statusInfo.Status, gc.Equals, state.StatusExecuting) 201 c.Assert(statusInfo.Message, gc.Equals, "foobar") 202 } 203 204 func (s *uniterBaseSuite) testSetUnitStatus( 205 c *gc.C, 206 facade interface { 207 SetUnitStatus(args params.SetStatus) (params.ErrorResults, error) 208 }, 209 ) { 210 err := s.wordpressUnit.SetStatus(state.StatusActive, "blah", nil) 211 c.Assert(err, jc.ErrorIsNil) 212 err = s.mysqlUnit.SetStatus(state.StatusTerminated, "foo", nil) 213 c.Assert(err, jc.ErrorIsNil) 214 215 args := params.SetStatus{ 216 Entities: []params.EntityStatusArgs{ 217 {Tag: "unit-mysql-0", Status: params.StatusError, Info: "not really"}, 218 {Tag: "unit-wordpress-0", Status: params.StatusTerminated, Info: "foobar"}, 219 {Tag: "unit-foo-42", Status: params.StatusActive, Info: "blah"}, 220 }} 221 result, err := facade.SetUnitStatus(args) 222 c.Assert(err, jc.ErrorIsNil) 223 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 224 Results: []params.ErrorResult{ 225 {apiservertesting.ErrUnauthorized}, 226 {nil}, 227 {apiservertesting.ErrUnauthorized}, 228 }, 229 }) 230 231 // Verify mysqlUnit - no change. 232 statusInfo, err := s.mysqlUnit.Status() 233 c.Assert(err, jc.ErrorIsNil) 234 c.Assert(statusInfo.Status, gc.Equals, state.StatusTerminated) 235 c.Assert(statusInfo.Message, gc.Equals, "foo") 236 // ...wordpressUnit is fine though. 237 statusInfo, err = s.wordpressUnit.Status() 238 c.Assert(err, jc.ErrorIsNil) 239 c.Assert(statusInfo.Status, gc.Equals, state.StatusTerminated) 240 c.Assert(statusInfo.Message, gc.Equals, "foobar") 241 } 242 243 func (s *uniterBaseSuite) testLife( 244 c *gc.C, 245 facade interface { 246 Life(args params.Entities) (params.LifeResults, error) 247 }, 248 ) { 249 // Add a relation wordpress-mysql. 250 rel := s.addRelation(c, "wordpress", "mysql") 251 relUnit, err := rel.Unit(s.wordpressUnit) 252 c.Assert(err, jc.ErrorIsNil) 253 err = relUnit.EnterScope(nil) 254 c.Assert(err, jc.ErrorIsNil) 255 c.Assert(rel.Life(), gc.Equals, state.Alive) 256 257 // Make the wordpressUnit dead. 258 err = s.wordpressUnit.EnsureDead() 259 c.Assert(err, jc.ErrorIsNil) 260 err = s.wordpressUnit.Refresh() 261 c.Assert(err, jc.ErrorIsNil) 262 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 263 264 // Add another unit, so the service will stay dying when we 265 // destroy it later. 266 extraUnit, err := s.wordpress.AddUnit() 267 c.Assert(err, jc.ErrorIsNil) 268 c.Assert(extraUnit, gc.NotNil) 269 270 // Make the wordpress service dying. 271 err = s.wordpress.Destroy() 272 c.Assert(err, jc.ErrorIsNil) 273 err = s.wordpress.Refresh() 274 c.Assert(err, jc.ErrorIsNil) 275 c.Assert(s.wordpress.Life(), gc.Equals, state.Dying) 276 277 args := params.Entities{Entities: []params.Entity{ 278 {Tag: "unit-mysql-0"}, 279 {Tag: "unit-wordpress-0"}, 280 {Tag: "unit-foo-42"}, 281 {Tag: "service-mysql"}, 282 {Tag: "service-wordpress"}, 283 {Tag: "machine-0"}, 284 {Tag: "machine-1"}, 285 {Tag: "machine-42"}, 286 {Tag: "service-foo"}, 287 // TODO(dfc) these aren't valid tags any more 288 // but I hope to restore this test when params.Entity takes 289 // tags, not strings, which is coming soon. 290 // {Tag: "just-foo"}, 291 {Tag: rel.Tag().String()}, 292 {Tag: "relation-svc1.rel1#svc2.rel2"}, 293 // {Tag: "relation-blah"}, 294 }} 295 result, err := facade.Life(args) 296 c.Assert(err, jc.ErrorIsNil) 297 c.Assert(result, gc.DeepEquals, params.LifeResults{ 298 Results: []params.LifeResult{ 299 {Error: apiservertesting.ErrUnauthorized}, 300 {Life: "dead"}, 301 {Error: apiservertesting.ErrUnauthorized}, 302 {Error: apiservertesting.ErrUnauthorized}, 303 {Life: "dying"}, 304 {Error: apiservertesting.ErrUnauthorized}, 305 {Error: apiservertesting.ErrUnauthorized}, 306 {Error: apiservertesting.ErrUnauthorized}, 307 {Error: apiservertesting.ErrUnauthorized}, 308 // TODO(dfc) see above 309 // {Error: apiservertesting.ErrUnauthorized}, 310 {Error: apiservertesting.ErrUnauthorized}, 311 {Error: apiservertesting.ErrUnauthorized}, 312 // {Error: apiservertesting.ErrUnauthorized}, 313 }, 314 }) 315 } 316 317 func (s *uniterBaseSuite) testEnsureDead( 318 c *gc.C, 319 facade interface { 320 EnsureDead(args params.Entities) (params.ErrorResults, error) 321 }, 322 ) { 323 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 324 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 325 326 args := params.Entities{Entities: []params.Entity{ 327 {Tag: "unit-mysql-0"}, 328 {Tag: "unit-wordpress-0"}, 329 {Tag: "unit-foo-42"}, 330 }} 331 result, err := facade.EnsureDead(args) 332 c.Assert(err, jc.ErrorIsNil) 333 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 334 Results: []params.ErrorResult{ 335 {apiservertesting.ErrUnauthorized}, 336 {nil}, 337 {apiservertesting.ErrUnauthorized}, 338 }, 339 }) 340 341 err = s.wordpressUnit.Refresh() 342 c.Assert(err, jc.ErrorIsNil) 343 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 344 err = s.mysqlUnit.Refresh() 345 c.Assert(err, jc.ErrorIsNil) 346 c.Assert(s.mysqlUnit.Life(), gc.Equals, state.Alive) 347 348 // Try it again on a Dead unit; should work. 349 args = params.Entities{ 350 Entities: []params.Entity{{Tag: "unit-wordpress-0"}}, 351 } 352 result, err = facade.EnsureDead(args) 353 c.Assert(err, jc.ErrorIsNil) 354 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 355 Results: []params.ErrorResult{{nil}}, 356 }) 357 358 // Verify Life is unchanged. 359 err = s.wordpressUnit.Refresh() 360 c.Assert(err, jc.ErrorIsNil) 361 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Dead) 362 } 363 364 func (s *uniterBaseSuite) testWatch( 365 c *gc.C, 366 facade interface { 367 Watch(args params.Entities) (params.NotifyWatchResults, error) 368 }, 369 ) { 370 c.Assert(s.resources.Count(), gc.Equals, 0) 371 372 args := params.Entities{Entities: []params.Entity{ 373 {Tag: "unit-mysql-0"}, 374 {Tag: "unit-wordpress-0"}, 375 {Tag: "unit-foo-42"}, 376 {Tag: "service-mysql"}, 377 {Tag: "service-wordpress"}, 378 {Tag: "service-foo"}, 379 // TODO(dfc) these aren't valid tags any more 380 // but I hope to restore this test when params.Entity takes 381 // tags, not strings, which is coming soon. 382 // {Tag: "just-foo"}, 383 }} 384 result, err := facade.Watch(args) 385 c.Assert(err, jc.ErrorIsNil) 386 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 387 Results: []params.NotifyWatchResult{ 388 {Error: apiservertesting.ErrUnauthorized}, 389 {NotifyWatcherId: "1"}, 390 {Error: apiservertesting.ErrUnauthorized}, 391 {Error: apiservertesting.ErrUnauthorized}, 392 {NotifyWatcherId: "2"}, 393 {Error: apiservertesting.ErrUnauthorized}, 394 // see above 395 // {Error: apiservertesting.ErrUnauthorized}, 396 }, 397 }) 398 399 // Verify the resource was registered and stop when done 400 c.Assert(s.resources.Count(), gc.Equals, 2) 401 resource1 := s.resources.Get("1") 402 defer statetesting.AssertStop(c, resource1) 403 resource2 := s.resources.Get("2") 404 defer statetesting.AssertStop(c, resource2) 405 406 // Check that the Watch has consumed the initial event ("returned" in 407 // the Watch call) 408 wc := statetesting.NewNotifyWatcherC(c, s.State, resource1.(state.NotifyWatcher)) 409 wc.AssertNoChange() 410 wc = statetesting.NewNotifyWatcherC(c, s.State, resource2.(state.NotifyWatcher)) 411 wc.AssertNoChange() 412 } 413 414 func (s *uniterBaseSuite) testPublicAddress( 415 c *gc.C, 416 facade interface { 417 PublicAddress(args params.Entities) (params.StringResults, error) 418 }, 419 ) { 420 // Try first without setting an address. 421 args := params.Entities{Entities: []params.Entity{ 422 {Tag: "unit-mysql-0"}, 423 {Tag: "unit-wordpress-0"}, 424 {Tag: "unit-foo-42"}, 425 }} 426 expectErr := ¶ms.Error{ 427 Code: params.CodeNoAddressSet, 428 Message: `"unit-wordpress-0" has no public address set`, 429 } 430 result, err := facade.PublicAddress(args) 431 c.Assert(err, jc.ErrorIsNil) 432 c.Assert(result, gc.DeepEquals, params.StringResults{ 433 Results: []params.StringResult{ 434 {Error: apiservertesting.ErrUnauthorized}, 435 {Error: expectErr}, 436 {Error: apiservertesting.ErrUnauthorized}, 437 }, 438 }) 439 440 // Now set it an try again. 441 err = s.machine0.SetProviderAddresses( 442 network.NewScopedAddress("1.2.3.4", network.ScopePublic), 443 ) 444 c.Assert(err, jc.ErrorIsNil) 445 address, ok := s.wordpressUnit.PublicAddress() 446 c.Assert(address, gc.Equals, "1.2.3.4") 447 c.Assert(ok, jc.IsTrue) 448 449 result, err = facade.PublicAddress(args) 450 c.Assert(err, jc.ErrorIsNil) 451 c.Assert(result, gc.DeepEquals, params.StringResults{ 452 Results: []params.StringResult{ 453 {Error: apiservertesting.ErrUnauthorized}, 454 {Result: "1.2.3.4"}, 455 {Error: apiservertesting.ErrUnauthorized}, 456 }, 457 }) 458 } 459 460 func (s *uniterBaseSuite) testPrivateAddress( 461 c *gc.C, 462 facade interface { 463 PrivateAddress(args params.Entities) (params.StringResults, error) 464 }, 465 ) { 466 args := params.Entities{Entities: []params.Entity{ 467 {Tag: "unit-mysql-0"}, 468 {Tag: "unit-wordpress-0"}, 469 {Tag: "unit-foo-42"}, 470 }} 471 expectErr := ¶ms.Error{ 472 Code: params.CodeNoAddressSet, 473 Message: `"unit-wordpress-0" has no private address set`, 474 } 475 result, err := facade.PrivateAddress(args) 476 c.Assert(err, jc.ErrorIsNil) 477 c.Assert(result, gc.DeepEquals, params.StringResults{ 478 Results: []params.StringResult{ 479 {Error: apiservertesting.ErrUnauthorized}, 480 {Error: expectErr}, 481 {Error: apiservertesting.ErrUnauthorized}, 482 }, 483 }) 484 485 // Now set it and try again. 486 err = s.machine0.SetProviderAddresses( 487 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal), 488 ) 489 c.Assert(err, jc.ErrorIsNil) 490 address, ok := s.wordpressUnit.PrivateAddress() 491 c.Assert(address, gc.Equals, "1.2.3.4") 492 c.Assert(ok, jc.IsTrue) 493 494 result, err = facade.PrivateAddress(args) 495 c.Assert(err, jc.ErrorIsNil) 496 c.Assert(result, gc.DeepEquals, params.StringResults{ 497 Results: []params.StringResult{ 498 {Error: apiservertesting.ErrUnauthorized}, 499 {Result: "1.2.3.4"}, 500 {Error: apiservertesting.ErrUnauthorized}, 501 }, 502 }) 503 } 504 505 func (s *uniterBaseSuite) testAvailabilityZone( 506 c *gc.C, 507 facade interface { 508 AvailabilityZone(args params.Entities) (params.StringResults, error) 509 }, 510 ) { 511 s.PatchValue(uniter.GetZone, func(st *state.State, tag names.Tag) (string, error) { 512 return "a_zone", nil 513 }) 514 515 args := params.Entities{Entities: []params.Entity{ 516 {Tag: "unit-wordpress-0"}, 517 }} 518 result, err := facade.AvailabilityZone(args) 519 c.Assert(err, jc.ErrorIsNil) 520 521 c.Check(result, gc.DeepEquals, params.StringResults{ 522 Results: []params.StringResult{ 523 {Result: "a_zone"}, 524 }, 525 }) 526 } 527 528 func (s *uniterBaseSuite) testResolved( 529 c *gc.C, 530 facade interface { 531 Resolved(args params.Entities) (params.ResolvedModeResults, error) 532 }, 533 ) { 534 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 535 c.Assert(err, jc.ErrorIsNil) 536 mode := s.wordpressUnit.Resolved() 537 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 538 539 args := params.Entities{Entities: []params.Entity{ 540 {Tag: "unit-mysql-0"}, 541 {Tag: "unit-wordpress-0"}, 542 {Tag: "unit-foo-42"}, 543 }} 544 result, err := facade.Resolved(args) 545 c.Assert(err, jc.ErrorIsNil) 546 c.Assert(result, gc.DeepEquals, params.ResolvedModeResults{ 547 Results: []params.ResolvedModeResult{ 548 {Error: apiservertesting.ErrUnauthorized}, 549 {Mode: params.ResolvedMode(mode)}, 550 {Error: apiservertesting.ErrUnauthorized}, 551 }, 552 }) 553 } 554 555 func (s *uniterBaseSuite) testClearResolved( 556 c *gc.C, 557 facade interface { 558 ClearResolved(args params.Entities) (params.ErrorResults, error) 559 }, 560 ) { 561 err := s.wordpressUnit.SetResolved(state.ResolvedRetryHooks) 562 c.Assert(err, jc.ErrorIsNil) 563 mode := s.wordpressUnit.Resolved() 564 c.Assert(mode, gc.Equals, state.ResolvedRetryHooks) 565 566 args := params.Entities{Entities: []params.Entity{ 567 {Tag: "unit-mysql-0"}, 568 {Tag: "unit-wordpress-0"}, 569 {Tag: "unit-foo-42"}, 570 }} 571 result, err := facade.ClearResolved(args) 572 c.Assert(err, jc.ErrorIsNil) 573 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 574 Results: []params.ErrorResult{ 575 {apiservertesting.ErrUnauthorized}, 576 {nil}, 577 {apiservertesting.ErrUnauthorized}, 578 }, 579 }) 580 581 // Verify wordpressUnit's resolved mode has changed. 582 err = s.wordpressUnit.Refresh() 583 c.Assert(err, jc.ErrorIsNil) 584 mode = s.wordpressUnit.Resolved() 585 c.Assert(mode, gc.Equals, state.ResolvedNone) 586 } 587 588 type getPrincipal interface { 589 GetPrincipal(args params.Entities) (params.StringBoolResults, error) 590 } 591 592 func (s *uniterBaseSuite) testGetPrincipal( 593 c *gc.C, 594 facade getPrincipal, 595 factory func(_ *state.State, _ *common.Resources, _ common.Authorizer) (getPrincipal, error), 596 ) { 597 // Add a subordinate to wordpressUnit. 598 _, _, subordinate := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 599 600 principal, ok := subordinate.PrincipalName() 601 c.Assert(principal, gc.Equals, s.wordpressUnit.Name()) 602 c.Assert(ok, jc.IsTrue) 603 604 // First try it as wordpressUnit's agent. 605 args := params.Entities{Entities: []params.Entity{ 606 {Tag: "unit-mysql-0"}, 607 {Tag: "unit-wordpress-0"}, 608 {Tag: subordinate.Tag().String()}, 609 {Tag: "unit-foo-42"}, 610 }} 611 result, err := facade.GetPrincipal(args) 612 c.Assert(err, jc.ErrorIsNil) 613 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 614 Results: []params.StringBoolResult{ 615 {Error: apiservertesting.ErrUnauthorized}, 616 {Result: "", Ok: false, Error: nil}, 617 {Error: apiservertesting.ErrUnauthorized}, 618 {Error: apiservertesting.ErrUnauthorized}, 619 }, 620 }) 621 622 // Now try as subordinate's agent. 623 subAuthorizer := s.authorizer 624 subAuthorizer.Tag = subordinate.Tag() 625 subUniter, err := factory(s.State, s.resources, subAuthorizer) 626 c.Assert(err, jc.ErrorIsNil) 627 628 result, err = subUniter.GetPrincipal(args) 629 c.Assert(err, jc.ErrorIsNil) 630 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 631 Results: []params.StringBoolResult{ 632 {Error: apiservertesting.ErrUnauthorized}, 633 {Error: apiservertesting.ErrUnauthorized}, 634 {Result: "unit-wordpress-0", Ok: true, Error: nil}, 635 {Error: apiservertesting.ErrUnauthorized}, 636 }, 637 }) 638 } 639 640 func (s *uniterBaseSuite) testHasSubordinates( 641 c *gc.C, 642 facade interface { 643 HasSubordinates(args params.Entities) (params.BoolResults, error) 644 }, 645 ) { 646 // Try first without any subordinates for wordpressUnit. 647 args := params.Entities{Entities: []params.Entity{ 648 {Tag: "unit-mysql-0"}, 649 {Tag: "unit-wordpress-0"}, 650 {Tag: "unit-logging-0"}, 651 {Tag: "unit-foo-42"}, 652 }} 653 result, err := facade.HasSubordinates(args) 654 c.Assert(err, jc.ErrorIsNil) 655 c.Assert(result, gc.DeepEquals, params.BoolResults{ 656 Results: []params.BoolResult{ 657 {Error: apiservertesting.ErrUnauthorized}, 658 {Result: false}, 659 {Error: apiservertesting.ErrUnauthorized}, 660 {Error: apiservertesting.ErrUnauthorized}, 661 }, 662 }) 663 664 // Add two subordinates to wordpressUnit and try again. 665 s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 666 s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 667 668 result, err = facade.HasSubordinates(args) 669 c.Assert(err, jc.ErrorIsNil) 670 c.Assert(result, gc.DeepEquals, params.BoolResults{ 671 Results: []params.BoolResult{ 672 {Error: apiservertesting.ErrUnauthorized}, 673 {Result: true}, 674 {Error: apiservertesting.ErrUnauthorized}, 675 {Error: apiservertesting.ErrUnauthorized}, 676 }, 677 }) 678 } 679 680 func (s *uniterBaseSuite) testDestroy( 681 c *gc.C, 682 facade interface { 683 Destroy(args params.Entities) (params.ErrorResults, error) 684 }, 685 ) { 686 c.Assert(s.wordpressUnit.Life(), gc.Equals, state.Alive) 687 688 args := params.Entities{Entities: []params.Entity{ 689 {Tag: "unit-mysql-0"}, 690 {Tag: "unit-wordpress-0"}, 691 {Tag: "unit-foo-42"}, 692 }} 693 result, err := facade.Destroy(args) 694 c.Assert(err, jc.ErrorIsNil) 695 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 696 Results: []params.ErrorResult{ 697 {apiservertesting.ErrUnauthorized}, 698 {nil}, 699 {apiservertesting.ErrUnauthorized}, 700 }, 701 }) 702 703 // Verify wordpressUnit is destroyed and removed. 704 err = s.wordpressUnit.Refresh() 705 c.Assert(err, jc.Satisfies, errors.IsNotFound) 706 } 707 708 func (s *uniterBaseSuite) testDestroyAllSubordinates( 709 c *gc.C, 710 facade interface { 711 DestroyAllSubordinates(args params.Entities) (params.ErrorResults, error) 712 }, 713 ) { 714 // Add two subordinates to wordpressUnit. 715 _, _, loggingSub := s.addRelatedService(c, "wordpress", "logging", s.wordpressUnit) 716 _, _, monitoringSub := s.addRelatedService(c, "wordpress", "monitoring", s.wordpressUnit) 717 c.Assert(loggingSub.Life(), gc.Equals, state.Alive) 718 c.Assert(monitoringSub.Life(), gc.Equals, state.Alive) 719 720 err := s.wordpressUnit.Refresh() 721 c.Assert(err, jc.ErrorIsNil) 722 subordinates := s.wordpressUnit.SubordinateNames() 723 c.Assert(subordinates, gc.DeepEquals, []string{"logging/0", "monitoring/0"}) 724 725 args := params.Entities{Entities: []params.Entity{ 726 {Tag: "unit-mysql-0"}, 727 {Tag: "unit-wordpress-0"}, 728 {Tag: "unit-foo-42"}, 729 }} 730 result, err := facade.DestroyAllSubordinates(args) 731 c.Assert(err, jc.ErrorIsNil) 732 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 733 Results: []params.ErrorResult{ 734 {apiservertesting.ErrUnauthorized}, 735 {nil}, 736 {apiservertesting.ErrUnauthorized}, 737 }, 738 }) 739 740 // Verify wordpressUnit's subordinates were destroyed. 741 err = loggingSub.Refresh() 742 c.Assert(err, jc.ErrorIsNil) 743 c.Assert(loggingSub.Life(), gc.Equals, state.Dying) 744 err = monitoringSub.Refresh() 745 c.Assert(err, jc.ErrorIsNil) 746 c.Assert(monitoringSub.Life(), gc.Equals, state.Dying) 747 } 748 749 func (s *uniterBaseSuite) testCharmURL( 750 c *gc.C, 751 facade interface { 752 CharmURL(args params.Entities) (params.StringBoolResults, error) 753 }, 754 ) { 755 // Set wordpressUnit's charm URL first. 756 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 757 c.Assert(err, jc.ErrorIsNil) 758 curl, ok := s.wordpressUnit.CharmURL() 759 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 760 c.Assert(ok, jc.IsTrue) 761 762 // Make sure wordpress service's charm is what we expect. 763 curl, force := s.wordpress.CharmURL() 764 c.Assert(curl, gc.DeepEquals, s.wpCharm.URL()) 765 c.Assert(force, jc.IsFalse) 766 767 args := params.Entities{Entities: []params.Entity{ 768 {Tag: "unit-mysql-0"}, 769 {Tag: "unit-wordpress-0"}, 770 {Tag: "unit-foo-42"}, 771 {Tag: "service-mysql"}, 772 {Tag: "service-wordpress"}, 773 {Tag: "service-foo"}, 774 // TODO(dfc) these aren't valid tags any more 775 // but I hope to restore this test when params.Entity takes 776 // tags, not strings, which is coming soon. 777 // {Tag: "just-foo"}, 778 }} 779 result, err := facade.CharmURL(args) 780 c.Assert(err, jc.ErrorIsNil) 781 c.Assert(result, gc.DeepEquals, params.StringBoolResults{ 782 Results: []params.StringBoolResult{ 783 {Error: apiservertesting.ErrUnauthorized}, 784 {Result: s.wpCharm.String(), Ok: ok}, 785 {Error: apiservertesting.ErrUnauthorized}, 786 {Error: apiservertesting.ErrUnauthorized}, 787 {Result: s.wpCharm.String(), Ok: force}, 788 {Error: apiservertesting.ErrUnauthorized}, 789 // see above 790 // {Error: apiservertesting.ErrUnauthorized}, 791 }, 792 }) 793 } 794 795 func (s *uniterBaseSuite) testSetCharmURL( 796 c *gc.C, 797 facade interface { 798 SetCharmURL(args params.EntitiesCharmURL) (params.ErrorResults, error) 799 }, 800 ) { 801 _, ok := s.wordpressUnit.CharmURL() 802 c.Assert(ok, jc.IsFalse) 803 804 args := params.EntitiesCharmURL{Entities: []params.EntityCharmURL{ 805 {Tag: "unit-mysql-0", CharmURL: "cs:quantal/service-42"}, 806 {Tag: "unit-wordpress-0", CharmURL: s.wpCharm.String()}, 807 {Tag: "unit-foo-42", CharmURL: "cs:quantal/foo-321"}, 808 }} 809 result, err := facade.SetCharmURL(args) 810 c.Assert(err, jc.ErrorIsNil) 811 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 812 Results: []params.ErrorResult{ 813 {apiservertesting.ErrUnauthorized}, 814 {nil}, 815 {apiservertesting.ErrUnauthorized}, 816 }, 817 }) 818 819 // Verify the charm URL was set. 820 err = s.wordpressUnit.Refresh() 821 c.Assert(err, jc.ErrorIsNil) 822 charmUrl, needsUpgrade := s.wordpressUnit.CharmURL() 823 c.Assert(charmUrl, gc.NotNil) 824 c.Assert(charmUrl.String(), gc.Equals, s.wpCharm.String()) 825 c.Assert(needsUpgrade, jc.IsTrue) 826 } 827 828 func (s *uniterBaseSuite) testOpenPorts( 829 c *gc.C, 830 facade interface { 831 OpenPorts(args params.EntitiesPortRanges) (params.ErrorResults, error) 832 }, 833 ) { 834 openedPorts, err := s.wordpressUnit.OpenedPorts() 835 c.Assert(err, jc.ErrorIsNil) 836 c.Assert(openedPorts, gc.HasLen, 0) 837 838 args := params.EntitiesPortRanges{Entities: []params.EntityPortRange{ 839 {Tag: "unit-mysql-0", Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 840 {Tag: "unit-wordpress-0", Protocol: "udp", FromPort: 4321, ToPort: 5000}, 841 {Tag: "unit-foo-42", Protocol: "tcp", FromPort: 42, ToPort: 42}, 842 }} 843 result, err := facade.OpenPorts(args) 844 c.Assert(err, jc.ErrorIsNil) 845 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 846 Results: []params.ErrorResult{ 847 {apiservertesting.ErrUnauthorized}, 848 {nil}, 849 {apiservertesting.ErrUnauthorized}, 850 }, 851 }) 852 853 // Verify the wordpressUnit's port is opened. 854 openedPorts, err = s.wordpressUnit.OpenedPorts() 855 c.Assert(err, jc.ErrorIsNil) 856 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 857 {Protocol: "udp", FromPort: 4321, ToPort: 5000}, 858 }) 859 } 860 861 func (s *uniterBaseSuite) testClosePorts( 862 c *gc.C, 863 facade interface { 864 ClosePorts(args params.EntitiesPortRanges) (params.ErrorResults, error) 865 }, 866 ) { 867 // Open port udp:4321 in advance on wordpressUnit. 868 err := s.wordpressUnit.OpenPorts("udp", 4321, 5000) 869 c.Assert(err, jc.ErrorIsNil) 870 openedPorts, err := s.wordpressUnit.OpenedPorts() 871 c.Assert(err, jc.ErrorIsNil) 872 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 873 {Protocol: "udp", FromPort: 4321, ToPort: 5000}, 874 }) 875 876 args := params.EntitiesPortRanges{Entities: []params.EntityPortRange{ 877 {Tag: "unit-mysql-0", Protocol: "tcp", FromPort: 1234, ToPort: 1400}, 878 {Tag: "unit-wordpress-0", Protocol: "udp", FromPort: 4321, ToPort: 5000}, 879 {Tag: "unit-foo-42", Protocol: "tcp", FromPort: 42, ToPort: 42}, 880 }} 881 result, err := facade.ClosePorts(args) 882 c.Assert(err, jc.ErrorIsNil) 883 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 884 Results: []params.ErrorResult{ 885 {apiservertesting.ErrUnauthorized}, 886 {nil}, 887 {apiservertesting.ErrUnauthorized}, 888 }, 889 }) 890 891 // Verify the wordpressUnit's port is closed. 892 openedPorts, err = s.wordpressUnit.OpenedPorts() 893 c.Assert(err, jc.ErrorIsNil) 894 c.Assert(openedPorts, gc.HasLen, 0) 895 } 896 897 func (s *uniterBaseSuite) testOpenPort( 898 c *gc.C, 899 facade interface { 900 OpenPort(args params.EntitiesPorts) (params.ErrorResults, error) 901 }, 902 ) { 903 openedPorts, err := s.wordpressUnit.OpenedPorts() 904 c.Assert(err, jc.ErrorIsNil) 905 c.Assert(openedPorts, gc.HasLen, 0) 906 907 args := params.EntitiesPorts{Entities: []params.EntityPort{ 908 {Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234}, 909 {Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321}, 910 {Tag: "unit-foo-42", Protocol: "tcp", Port: 42}, 911 }} 912 result, err := facade.OpenPort(args) 913 c.Assert(err, jc.ErrorIsNil) 914 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 915 Results: []params.ErrorResult{ 916 {apiservertesting.ErrUnauthorized}, 917 {nil}, 918 {apiservertesting.ErrUnauthorized}, 919 }, 920 }) 921 922 // Verify the wordpressUnit's port is opened. 923 openedPorts, err = s.wordpressUnit.OpenedPorts() 924 c.Assert(err, jc.ErrorIsNil) 925 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 926 {Protocol: "udp", FromPort: 4321, ToPort: 4321}, 927 }) 928 } 929 930 func (s *uniterBaseSuite) testClosePort( 931 c *gc.C, 932 facade interface { 933 ClosePort(args params.EntitiesPorts) (params.ErrorResults, error) 934 }, 935 ) { 936 // Open port udp:4321 in advance on wordpressUnit. 937 err := s.wordpressUnit.OpenPort("udp", 4321) 938 c.Assert(err, jc.ErrorIsNil) 939 openedPorts, err := s.wordpressUnit.OpenedPorts() 940 c.Assert(err, jc.ErrorIsNil) 941 c.Assert(openedPorts, gc.DeepEquals, []network.PortRange{ 942 {Protocol: "udp", FromPort: 4321, ToPort: 4321}, 943 }) 944 945 args := params.EntitiesPorts{Entities: []params.EntityPort{ 946 {Tag: "unit-mysql-0", Protocol: "tcp", Port: 1234}, 947 {Tag: "unit-wordpress-0", Protocol: "udp", Port: 4321}, 948 {Tag: "unit-foo-42", Protocol: "tcp", Port: 42}, 949 }} 950 result, err := facade.ClosePort(args) 951 c.Assert(err, jc.ErrorIsNil) 952 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 953 Results: []params.ErrorResult{ 954 {apiservertesting.ErrUnauthorized}, 955 {nil}, 956 {apiservertesting.ErrUnauthorized}, 957 }, 958 }) 959 960 // Verify the wordpressUnit's port is closed. 961 openedPorts, err = s.wordpressUnit.OpenedPorts() 962 c.Assert(err, jc.ErrorIsNil) 963 c.Assert(openedPorts, gc.HasLen, 0) 964 } 965 966 func (s *uniterBaseSuite) testWatchConfigSettings( 967 c *gc.C, 968 facade interface { 969 WatchConfigSettings(args params.Entities) (params.NotifyWatchResults, error) 970 }, 971 ) { 972 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 973 c.Assert(err, jc.ErrorIsNil) 974 975 c.Assert(s.resources.Count(), gc.Equals, 0) 976 977 args := params.Entities{Entities: []params.Entity{ 978 {Tag: "unit-mysql-0"}, 979 {Tag: "unit-wordpress-0"}, 980 {Tag: "unit-foo-42"}, 981 }} 982 result, err := facade.WatchConfigSettings(args) 983 c.Assert(err, jc.ErrorIsNil) 984 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 985 Results: []params.NotifyWatchResult{ 986 {Error: apiservertesting.ErrUnauthorized}, 987 {NotifyWatcherId: "1"}, 988 {Error: apiservertesting.ErrUnauthorized}, 989 }, 990 }) 991 992 // Verify the resource was registered and stop when done 993 c.Assert(s.resources.Count(), gc.Equals, 1) 994 resource := s.resources.Get("1") 995 defer statetesting.AssertStop(c, resource) 996 997 // Check that the Watch has consumed the initial event ("returned" in 998 // the Watch call) 999 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 1000 wc.AssertNoChange() 1001 } 1002 1003 type watchActions interface { 1004 WatchActionNotifications(args params.Entities) (params.StringsWatchResults, error) 1005 } 1006 1007 func (s *uniterBaseSuite) testWatchActionNotifications(c *gc.C, facade watchActions) { 1008 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 1009 c.Assert(err, jc.ErrorIsNil) 1010 1011 c.Assert(s.resources.Count(), gc.Equals, 0) 1012 1013 args := params.Entities{Entities: []params.Entity{ 1014 {Tag: "unit-mysql-0"}, 1015 {Tag: "unit-wordpress-0"}, 1016 {Tag: "unit-foo-42"}, 1017 }} 1018 result, err := facade.WatchActionNotifications(args) 1019 c.Assert(err, jc.ErrorIsNil) 1020 c.Assert(result, gc.DeepEquals, params.StringsWatchResults{ 1021 Results: []params.StringsWatchResult{ 1022 {Error: apiservertesting.ErrUnauthorized}, 1023 {StringsWatcherId: "1"}, 1024 {Error: apiservertesting.ErrUnauthorized}, 1025 }, 1026 }) 1027 1028 // Verify the resource was registered and stop when done 1029 c.Assert(s.resources.Count(), gc.Equals, 1) 1030 resource := s.resources.Get("1") 1031 defer statetesting.AssertStop(c, resource) 1032 1033 // Check that the Watch has consumed the initial event ("returned" in 1034 // the Watch call) 1035 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 1036 wc.AssertNoChange() 1037 1038 addedAction, err := s.wordpressUnit.AddAction("fakeaction", nil) 1039 1040 wc.AssertChange(addedAction.Id()) 1041 wc.AssertNoChange() 1042 } 1043 1044 func (s *uniterBaseSuite) testWatchPreexistingActions(c *gc.C, facade watchActions) { 1045 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 1046 c.Assert(err, jc.ErrorIsNil) 1047 1048 c.Assert(s.resources.Count(), gc.Equals, 0) 1049 1050 action1, err := s.wordpressUnit.AddAction("fakeaction", nil) 1051 c.Assert(err, jc.ErrorIsNil) 1052 action2, err := s.wordpressUnit.AddAction("fakeaction", nil) 1053 c.Assert(err, jc.ErrorIsNil) 1054 1055 args := params.Entities{Entities: []params.Entity{ 1056 {Tag: "unit-wordpress-0"}, 1057 }} 1058 1059 s.State.StartSync() 1060 results, err := facade.WatchActionNotifications(args) 1061 c.Assert(err, jc.ErrorIsNil) 1062 1063 checkUnorderedActionIdsEqual(c, []string{action1.Id(), action2.Id()}, results) 1064 1065 // Verify the resource was registered and stop when done 1066 c.Assert(s.resources.Count(), gc.Equals, 1) 1067 resource := s.resources.Get("1") 1068 defer statetesting.AssertStop(c, resource) 1069 1070 // Check that the Watch has consumed the initial event ("returned" in 1071 // the Watch call) 1072 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 1073 wc.AssertNoChange() 1074 1075 addedAction, err := s.wordpressUnit.AddAction("fakeaction", nil) 1076 c.Assert(err, jc.ErrorIsNil) 1077 wc.AssertChange(addedAction.Id()) 1078 wc.AssertNoChange() 1079 } 1080 1081 func (s *uniterBaseSuite) testWatchActionNotificationsMalformedTag(c *gc.C, facade watchActions) { 1082 args := params.Entities{Entities: []params.Entity{ 1083 {Tag: "ewenit-mysql-0"}, 1084 }} 1085 _, err := facade.WatchActionNotifications(args) 1086 c.Assert(err, gc.NotNil) 1087 c.Assert(err.Error(), gc.Equals, `"ewenit-mysql-0" is not a valid tag`) 1088 } 1089 1090 func (s *uniterBaseSuite) testWatchActionNotificationsMalformedUnitName(c *gc.C, facade watchActions) { 1091 args := params.Entities{Entities: []params.Entity{ 1092 {Tag: "unit-mysql-01"}, 1093 }} 1094 _, err := facade.WatchActionNotifications(args) 1095 c.Assert(err, gc.NotNil) 1096 c.Assert(err.Error(), gc.Equals, `"unit-mysql-01" is not a valid unit tag`) 1097 } 1098 1099 func (s *uniterBaseSuite) testWatchActionNotificationsNotUnit(c *gc.C, facade watchActions) { 1100 action, err := s.mysqlUnit.AddAction("fakeaction", nil) 1101 c.Assert(err, jc.ErrorIsNil) 1102 args := params.Entities{Entities: []params.Entity{ 1103 {Tag: action.Tag().String()}, 1104 }} 1105 _, err = facade.WatchActionNotifications(args) 1106 c.Assert(err, gc.NotNil) 1107 c.Assert(err.Error(), gc.Equals, `"action-`+action.Id()+`" is not a valid unit tag`) 1108 } 1109 1110 func (s *uniterBaseSuite) testWatchActionNotificationsPermissionDenied(c *gc.C, facade watchActions) { 1111 args := params.Entities{Entities: []params.Entity{ 1112 {Tag: "unit-nonexistentgarbage-0"}, 1113 }} 1114 results, err := facade.WatchActionNotifications(args) 1115 c.Assert(err, jc.ErrorIsNil) 1116 c.Assert(results, gc.NotNil) 1117 c.Assert(len(results.Results), gc.Equals, 1) 1118 result := results.Results[0] 1119 c.Assert(result.Error, gc.NotNil) 1120 c.Assert(result.Error.Message, gc.Equals, "permission denied") 1121 } 1122 1123 func (s *uniterBaseSuite) testConfigSettings( 1124 c *gc.C, 1125 facade interface { 1126 ConfigSettings(args params.Entities) (params.ConfigSettingsResults, error) 1127 }, 1128 ) { 1129 err := s.wordpressUnit.SetCharmURL(s.wpCharm.URL()) 1130 c.Assert(err, jc.ErrorIsNil) 1131 settings, err := s.wordpressUnit.ConfigSettings() 1132 c.Assert(err, jc.ErrorIsNil) 1133 c.Assert(settings, gc.DeepEquals, charm.Settings{"blog-title": "My Title"}) 1134 1135 args := params.Entities{Entities: []params.Entity{ 1136 {Tag: "unit-mysql-0"}, 1137 {Tag: "unit-wordpress-0"}, 1138 {Tag: "unit-foo-42"}, 1139 }} 1140 result, err := facade.ConfigSettings(args) 1141 c.Assert(err, jc.ErrorIsNil) 1142 c.Assert(result, gc.DeepEquals, params.ConfigSettingsResults{ 1143 Results: []params.ConfigSettingsResult{ 1144 {Error: apiservertesting.ErrUnauthorized}, 1145 {Settings: params.ConfigSettings{"blog-title": "My Title"}}, 1146 {Error: apiservertesting.ErrUnauthorized}, 1147 }, 1148 }) 1149 } 1150 1151 func (s *uniterBaseSuite) testWatchServiceRelations( 1152 c *gc.C, 1153 facade interface { 1154 WatchServiceRelations(args params.Entities) (params.StringsWatchResults, error) 1155 }, 1156 ) { 1157 c.Assert(s.resources.Count(), gc.Equals, 0) 1158 1159 args := params.Entities{Entities: []params.Entity{ 1160 {Tag: "service-mysql"}, 1161 {Tag: "service-wordpress"}, 1162 {Tag: "service-foo"}, 1163 }} 1164 result, err := facade.WatchServiceRelations(args) 1165 s.assertOneStringsWatcher(c, result, err) 1166 } 1167 1168 func (s *uniterBaseSuite) testCharmArchiveSha256( 1169 c *gc.C, 1170 facade interface { 1171 CharmArchiveSha256(args params.CharmURLs) (params.StringResults, error) 1172 }, 1173 ) { 1174 dummyCharm := s.AddTestingCharm(c, "dummy") 1175 1176 args := params.CharmURLs{URLs: []params.CharmURL{ 1177 {URL: "something-invalid"}, 1178 {URL: s.wpCharm.String()}, 1179 {URL: dummyCharm.String()}, 1180 }} 1181 result, err := facade.CharmArchiveSha256(args) 1182 c.Assert(err, jc.ErrorIsNil) 1183 c.Assert(result, gc.DeepEquals, params.StringResults{ 1184 Results: []params.StringResult{ 1185 {Error: apiservertesting.ErrUnauthorized}, 1186 {Result: s.wpCharm.BundleSha256()}, 1187 {Result: dummyCharm.BundleSha256()}, 1188 }, 1189 }) 1190 } 1191 1192 func (s *uniterBaseSuite) testCharmArchiveURLs( 1193 c *gc.C, 1194 facade interface { 1195 CharmArchiveURLs(args params.CharmURLs) (params.StringsResults, error) 1196 }, 1197 ) { 1198 dummyCharm := s.AddTestingCharm(c, "dummy") 1199 1200 hostPorts := [][]network.HostPort{ 1201 network.AddressesWithPort([]network.Address{ 1202 network.NewScopedAddress("1.2.3.4", network.ScopePublic), 1203 network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal), 1204 }, 1234), 1205 network.AddressesWithPort([]network.Address{ 1206 network.NewScopedAddress("1.2.3.5", network.ScopePublic), 1207 }, 1234), 1208 } 1209 err := s.State.SetAPIHostPorts(hostPorts) 1210 c.Assert(err, jc.ErrorIsNil) 1211 1212 args := params.CharmURLs{URLs: []params.CharmURL{ 1213 {URL: "something-invalid"}, 1214 {URL: s.wpCharm.String()}, 1215 {URL: dummyCharm.String()}, 1216 }} 1217 result, err := facade.CharmArchiveURLs(args) 1218 c.Assert(err, jc.ErrorIsNil) 1219 1220 wordpressURLs := []string{ 1221 fmt.Sprintf("https://0.1.2.3:1234/environment/%s/charms?file=%%2A&url=cs%%3Aquantal%%2Fwordpress-3", coretesting.EnvironmentTag.Id()), 1222 fmt.Sprintf("https://1.2.3.5:1234/environment/%s/charms?file=%%2A&url=cs%%3Aquantal%%2Fwordpress-3", coretesting.EnvironmentTag.Id()), 1223 } 1224 dummyURLs := []string{ 1225 fmt.Sprintf("https://0.1.2.3:1234/environment/%s/charms?file=%%2A&url=local%%3Aquantal%%2Fdummy-1", coretesting.EnvironmentTag.Id()), 1226 fmt.Sprintf("https://1.2.3.5:1234/environment/%s/charms?file=%%2A&url=local%%3Aquantal%%2Fdummy-1", coretesting.EnvironmentTag.Id()), 1227 } 1228 1229 c.Assert(result, jc.DeepEquals, params.StringsResults{ 1230 Results: []params.StringsResult{ 1231 {Error: apiservertesting.ErrUnauthorized}, 1232 {Result: wordpressURLs}, 1233 {Result: dummyURLs}, 1234 }, 1235 }) 1236 } 1237 1238 func (s *uniterBaseSuite) testCurrentEnvironUUID( 1239 c *gc.C, 1240 facade interface { 1241 CurrentEnvironUUID() (params.StringResult, error) 1242 }, 1243 ) { 1244 env, err := s.State.Environment() 1245 c.Assert(err, jc.ErrorIsNil) 1246 1247 result, err := facade.CurrentEnvironUUID() 1248 c.Assert(err, jc.ErrorIsNil) 1249 c.Assert(result, gc.DeepEquals, params.StringResult{Result: env.UUID()}) 1250 } 1251 1252 func (s *uniterBaseSuite) testCurrentEnvironment( 1253 c *gc.C, 1254 facade interface { 1255 CurrentEnvironment() (params.EnvironmentResult, error) 1256 }, 1257 ) { 1258 env, err := s.State.Environment() 1259 c.Assert(err, jc.ErrorIsNil) 1260 1261 result, err := facade.CurrentEnvironment() 1262 c.Assert(err, jc.ErrorIsNil) 1263 expected := params.EnvironmentResult{ 1264 Name: env.Name(), 1265 UUID: env.UUID(), 1266 } 1267 c.Assert(result, gc.DeepEquals, expected) 1268 } 1269 1270 type actions interface { 1271 Actions(args params.Entities) (params.ActionsQueryResults, error) 1272 } 1273 1274 func (s *uniterBaseSuite) testActions(c *gc.C, facade actions) { 1275 var actionTests = []struct { 1276 description string 1277 action params.ActionResult 1278 }{{ 1279 description: "A simple action.", 1280 action: params.ActionResult{ 1281 Action: ¶ms.Action{ 1282 Name: "fakeaction", 1283 Parameters: map[string]interface{}{ 1284 "outfile": "foo.txt", 1285 }}, 1286 }, 1287 }, { 1288 description: "An action with nested parameters.", 1289 action: params.ActionResult{ 1290 Action: ¶ms.Action{ 1291 Name: "fakeaction", 1292 Parameters: map[string]interface{}{ 1293 "outfile": "foo.bz2", 1294 "compression": map[string]interface{}{ 1295 "kind": "bzip", 1296 "quality": 5, 1297 }, 1298 }}, 1299 }, 1300 }} 1301 1302 for i, actionTest := range actionTests { 1303 c.Logf("test %d: %s", i, actionTest.description) 1304 1305 a, err := s.wordpressUnit.AddAction( 1306 actionTest.action.Action.Name, 1307 actionTest.action.Action.Parameters) 1308 c.Assert(err, jc.ErrorIsNil) 1309 c.Assert(names.IsValidAction(a.Id()), gc.Equals, true) 1310 actionTag := names.NewActionTag(a.Id()) 1311 c.Assert(a.ActionTag(), gc.Equals, actionTag) 1312 1313 args := params.Entities{ 1314 Entities: []params.Entity{{ 1315 Tag: actionTag.String(), 1316 }}, 1317 } 1318 results, err := facade.Actions(args) 1319 c.Assert(err, jc.ErrorIsNil) 1320 c.Assert(results.Results, gc.HasLen, 1) 1321 1322 actionsQueryResult := results.Results[0] 1323 1324 c.Assert(actionsQueryResult.Error, gc.IsNil) 1325 c.Assert(actionsQueryResult.Action, jc.DeepEquals, actionTest.action) 1326 } 1327 } 1328 1329 func (s *uniterBaseSuite) testActionsNotPresent(c *gc.C, facade actions) { 1330 uuid, err := utils.NewUUID() 1331 c.Assert(err, jc.ErrorIsNil) 1332 args := params.Entities{ 1333 Entities: []params.Entity{{ 1334 Tag: names.NewActionTag(uuid.String()).String(), 1335 }}, 1336 } 1337 results, err := facade.Actions(args) 1338 c.Assert(err, jc.ErrorIsNil) 1339 1340 c.Assert(results.Results, gc.HasLen, 1) 1341 actionsQueryResult := results.Results[0] 1342 c.Assert(actionsQueryResult.Error, gc.NotNil) 1343 c.Assert(actionsQueryResult.Error, gc.ErrorMatches, `action "[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}" not found`) 1344 } 1345 1346 func (s *uniterBaseSuite) testActionsWrongUnit( 1347 c *gc.C, 1348 factory func(_ *state.State, _ *common.Resources, _ common.Authorizer) (actions, error), 1349 ) { 1350 // Action doesn't match unit. 1351 mysqlUnitAuthorizer := apiservertesting.FakeAuthorizer{ 1352 Tag: s.mysqlUnit.Tag(), 1353 } 1354 mysqlUnitFacade, err := factory(s.State, s.resources, mysqlUnitAuthorizer) 1355 c.Assert(err, jc.ErrorIsNil) 1356 1357 action, err := s.wordpressUnit.AddAction("fakeaction", nil) 1358 c.Assert(err, jc.ErrorIsNil) 1359 args := params.Entities{ 1360 Entities: []params.Entity{{ 1361 Tag: action.Tag().String(), 1362 }}, 1363 } 1364 actions, err := mysqlUnitFacade.Actions(args) 1365 c.Assert(err, jc.ErrorIsNil) 1366 c.Assert(len(actions.Results), gc.Equals, 1) 1367 c.Assert(actions.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized) 1368 } 1369 1370 func (s *uniterBaseSuite) testActionsPermissionDenied(c *gc.C, facade actions) { 1371 action, err := s.mysqlUnit.AddAction("fakeaction", nil) 1372 c.Assert(err, jc.ErrorIsNil) 1373 args := params.Entities{ 1374 Entities: []params.Entity{{ 1375 Tag: action.Tag().String(), 1376 }}, 1377 } 1378 actions, err := facade.Actions(args) 1379 c.Assert(err, jc.ErrorIsNil) 1380 c.Assert(len(actions.Results), gc.Equals, 1) 1381 c.Assert(actions.Results[0].Error, jc.Satisfies, params.IsCodeUnauthorized) 1382 } 1383 1384 type finishActions interface { 1385 FinishActions(args params.ActionExecutionResults) (params.ErrorResults, error) 1386 } 1387 1388 func (s *uniterBaseSuite) testFinishActionsSuccess(c *gc.C, facade finishActions) { 1389 testName := "fakeaction" 1390 testOutput := map[string]interface{}{"output": "completed fakeaction successfully"} 1391 1392 results, err := s.wordpressUnit.CompletedActions() 1393 c.Assert(err, jc.ErrorIsNil) 1394 c.Assert(results, gc.DeepEquals, ([]*state.Action)(nil)) 1395 1396 action, err := s.wordpressUnit.AddAction(testName, nil) 1397 c.Assert(err, jc.ErrorIsNil) 1398 1399 actionResults := params.ActionExecutionResults{ 1400 Results: []params.ActionExecutionResult{{ 1401 ActionTag: action.ActionTag().String(), 1402 Status: params.ActionCompleted, 1403 Results: testOutput, 1404 }}, 1405 } 1406 res, err := facade.FinishActions(actionResults) 1407 c.Assert(err, jc.ErrorIsNil) 1408 c.Assert(res, gc.DeepEquals, params.ErrorResults{Results: []params.ErrorResult{{Error: nil}}}) 1409 1410 results, err = s.wordpressUnit.CompletedActions() 1411 c.Assert(err, jc.ErrorIsNil) 1412 c.Assert(len(results), gc.Equals, 1) 1413 c.Assert(results[0].Status(), gc.Equals, state.ActionCompleted) 1414 res2, errstr := results[0].Results() 1415 c.Assert(errstr, gc.Equals, "") 1416 c.Assert(res2, gc.DeepEquals, testOutput) 1417 c.Assert(results[0].Name(), gc.Equals, testName) 1418 } 1419 1420 func (s *uniterBaseSuite) testFinishActionsFailure(c *gc.C, facade finishActions) { 1421 testName := "fakeaction" 1422 testError := "fakeaction was a dismal failure" 1423 1424 results, err := s.wordpressUnit.CompletedActions() 1425 c.Assert(err, jc.ErrorIsNil) 1426 c.Assert(results, gc.DeepEquals, ([]*state.Action)(nil)) 1427 1428 action, err := s.wordpressUnit.AddAction(testName, nil) 1429 c.Assert(err, jc.ErrorIsNil) 1430 1431 actionResults := params.ActionExecutionResults{ 1432 Results: []params.ActionExecutionResult{{ 1433 ActionTag: action.ActionTag().String(), 1434 Status: params.ActionFailed, 1435 Results: nil, 1436 Message: testError, 1437 }}, 1438 } 1439 res, err := facade.FinishActions(actionResults) 1440 c.Assert(err, jc.ErrorIsNil) 1441 c.Assert(res, gc.DeepEquals, params.ErrorResults{Results: []params.ErrorResult{{Error: nil}}}) 1442 1443 results, err = s.wordpressUnit.CompletedActions() 1444 c.Assert(err, jc.ErrorIsNil) 1445 c.Assert(len(results), gc.Equals, 1) 1446 c.Assert(results[0].Status(), gc.Equals, state.ActionFailed) 1447 res2, errstr := results[0].Results() 1448 c.Assert(errstr, gc.Equals, testError) 1449 c.Assert(res2, gc.DeepEquals, map[string]interface{}{}) 1450 c.Assert(results[0].Name(), gc.Equals, testName) 1451 } 1452 1453 func (s *uniterBaseSuite) testFinishActionsAuthAccess(c *gc.C, facade finishActions) { 1454 good, err := s.wordpressUnit.AddAction("fakeaction", nil) 1455 c.Assert(err, jc.ErrorIsNil) 1456 1457 bad, err := s.mysqlUnit.AddAction("fakeaction", nil) 1458 c.Assert(err, jc.ErrorIsNil) 1459 1460 var tests = []struct { 1461 actionTag names.ActionTag 1462 err error 1463 }{ 1464 {actionTag: good.ActionTag(), err: nil}, 1465 {actionTag: bad.ActionTag(), err: common.ErrPerm}, 1466 } 1467 1468 // Queue up actions from tests 1469 actionResults := params.ActionExecutionResults{Results: make([]params.ActionExecutionResult, len(tests))} 1470 for i, test := range tests { 1471 actionResults.Results[i] = params.ActionExecutionResult{ 1472 ActionTag: test.actionTag.String(), 1473 Status: params.ActionCompleted, 1474 Results: map[string]interface{}{}, 1475 } 1476 } 1477 1478 // Invoke FinishActions 1479 res, err := facade.FinishActions(actionResults) 1480 c.Assert(err, jc.ErrorIsNil) 1481 1482 // Verify permissions errors for actions queued on different unit 1483 for i, result := range res.Results { 1484 expected := tests[i].err 1485 if expected != nil { 1486 c.Assert(result.Error, gc.NotNil) 1487 c.Assert(result.Error.Error(), gc.Equals, expected.Error()) 1488 } else { 1489 c.Assert(result.Error, gc.IsNil) 1490 } 1491 } 1492 } 1493 1494 type beginActions interface { 1495 BeginActions(args params.Entities) (params.ErrorResults, error) 1496 } 1497 1498 func (s *uniterBaseSuite) testBeginActions(c *gc.C, facade beginActions) { 1499 ten_seconds_ago := time.Now().Add(-10 * time.Second) 1500 good, err := s.wordpressUnit.AddAction("fakeaction", nil) 1501 c.Assert(err, jc.ErrorIsNil) 1502 1503 running, err := s.wordpressUnit.RunningActions() 1504 c.Assert(err, jc.ErrorIsNil) 1505 c.Assert(len(running), gc.Equals, 0, gc.Commentf("expected no running actions, got %d", len(running))) 1506 1507 args := params.Entities{Entities: []params.Entity{{Tag: good.ActionTag().String()}}} 1508 res, err := facade.BeginActions(args) 1509 c.Assert(err, jc.ErrorIsNil) 1510 c.Assert(len(res.Results), gc.Equals, 1) 1511 c.Assert(res.Results[0].Error, gc.IsNil) 1512 1513 running, err = s.wordpressUnit.RunningActions() 1514 c.Assert(err, jc.ErrorIsNil) 1515 c.Assert(len(running), gc.Equals, 1, gc.Commentf("expected one running action, got %d", len(running))) 1516 c.Assert(running[0].ActionTag(), gc.Equals, good.ActionTag()) 1517 enqueued, started := running[0].Enqueued(), running[0].Started() 1518 c.Assert(ten_seconds_ago.Before(enqueued), jc.IsTrue, gc.Commentf("enqueued time should be after 10 seconds ago")) 1519 c.Assert(ten_seconds_ago.Before(started), jc.IsTrue, gc.Commentf("started time should be after 10 seconds ago")) 1520 c.Assert(started.After(enqueued) || started.Equal(enqueued), jc.IsTrue, gc.Commentf("started should be after or equal to enqueued time")) 1521 } 1522 1523 func (s *uniterBaseSuite) testRelation( 1524 c *gc.C, 1525 facade interface { 1526 Relation(args params.RelationUnits) (params.RelationResults, error) 1527 }, 1528 ) { 1529 rel := s.addRelation(c, "wordpress", "mysql") 1530 wpEp, err := rel.Endpoint("wordpress") 1531 c.Assert(err, jc.ErrorIsNil) 1532 1533 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1534 {Relation: "relation-42", Unit: "unit-foo-0"}, 1535 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1536 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1537 {Relation: rel.Tag().String(), Unit: "unit-foo-0"}, 1538 {Relation: "relation-blah", Unit: "unit-wordpress-0"}, 1539 {Relation: "service-foo", Unit: "user-foo"}, 1540 {Relation: "foo", Unit: "bar"}, 1541 {Relation: "unit-wordpress-0", Unit: rel.Tag().String()}, 1542 }} 1543 result, err := facade.Relation(args) 1544 c.Assert(err, jc.ErrorIsNil) 1545 c.Assert(result, gc.DeepEquals, params.RelationResults{ 1546 Results: []params.RelationResult{ 1547 {Error: apiservertesting.ErrUnauthorized}, 1548 { 1549 Id: rel.Id(), 1550 Key: rel.String(), 1551 Life: params.Life(rel.Life().String()), 1552 Endpoint: multiwatcher.Endpoint{ 1553 ServiceName: wpEp.ServiceName, 1554 Relation: wpEp.Relation, 1555 }, 1556 }, 1557 {Error: apiservertesting.ErrUnauthorized}, 1558 {Error: apiservertesting.ErrUnauthorized}, 1559 {Error: apiservertesting.ErrUnauthorized}, 1560 {Error: apiservertesting.ErrUnauthorized}, 1561 {Error: apiservertesting.ErrUnauthorized}, 1562 {Error: apiservertesting.ErrUnauthorized}, 1563 }, 1564 }) 1565 } 1566 1567 func (s *uniterBaseSuite) testRelationById( 1568 c *gc.C, 1569 facade interface { 1570 RelationById(args params.RelationIds) (params.RelationResults, error) 1571 }, 1572 ) { 1573 rel := s.addRelation(c, "wordpress", "mysql") 1574 c.Assert(rel.Id(), gc.Equals, 0) 1575 wpEp, err := rel.Endpoint("wordpress") 1576 c.Assert(err, jc.ErrorIsNil) 1577 1578 // Add another relation to mysql service, so we can see we can't 1579 // get it. 1580 otherRel, _, _ := s.addRelatedService(c, "mysql", "logging", s.mysqlUnit) 1581 1582 args := params.RelationIds{ 1583 RelationIds: []int{-1, rel.Id(), otherRel.Id(), 42, 234}, 1584 } 1585 result, err := facade.RelationById(args) 1586 c.Assert(err, jc.ErrorIsNil) 1587 c.Assert(result, gc.DeepEquals, params.RelationResults{ 1588 Results: []params.RelationResult{ 1589 {Error: apiservertesting.ErrUnauthorized}, 1590 { 1591 Id: rel.Id(), 1592 Key: rel.String(), 1593 Life: params.Life(rel.Life().String()), 1594 Endpoint: multiwatcher.Endpoint{ 1595 ServiceName: wpEp.ServiceName, 1596 Relation: wpEp.Relation, 1597 }, 1598 }, 1599 {Error: apiservertesting.ErrUnauthorized}, 1600 {Error: apiservertesting.ErrUnauthorized}, 1601 {Error: apiservertesting.ErrUnauthorized}, 1602 }, 1603 }) 1604 } 1605 1606 func (s *uniterBaseSuite) testProviderType( 1607 c *gc.C, 1608 facade interface { 1609 ProviderType() (params.StringResult, error) 1610 }, 1611 ) { 1612 cfg, err := s.State.EnvironConfig() 1613 c.Assert(err, jc.ErrorIsNil) 1614 1615 result, err := facade.ProviderType() 1616 c.Assert(err, jc.ErrorIsNil) 1617 c.Assert(result, gc.DeepEquals, params.StringResult{Result: cfg.Type()}) 1618 } 1619 1620 func (s *uniterBaseSuite) testEnterScope( 1621 c *gc.C, 1622 facade interface { 1623 EnterScope(args params.RelationUnits) (params.ErrorResults, error) 1624 }, 1625 ) { 1626 // Set wordpressUnit's private address first. 1627 err := s.machine0.SetProviderAddresses( 1628 network.NewScopedAddress("1.2.3.4", network.ScopeCloudLocal), 1629 ) 1630 c.Assert(err, jc.ErrorIsNil) 1631 1632 rel := s.addRelation(c, "wordpress", "mysql") 1633 relUnit, err := rel.Unit(s.wordpressUnit) 1634 c.Assert(err, jc.ErrorIsNil) 1635 s.assertInScope(c, relUnit, false) 1636 1637 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1638 {Relation: "relation-42", Unit: "unit-foo-0"}, 1639 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1640 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1641 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1642 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 1643 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1644 {Relation: "foo", Unit: "bar"}, 1645 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1646 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1647 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1648 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1649 }} 1650 result, err := facade.EnterScope(args) 1651 c.Assert(err, jc.ErrorIsNil) 1652 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1653 Results: []params.ErrorResult{ 1654 {apiservertesting.ErrUnauthorized}, 1655 {nil}, 1656 {nil}, 1657 {apiservertesting.ErrUnauthorized}, 1658 {apiservertesting.ErrUnauthorized}, 1659 {apiservertesting.ErrUnauthorized}, 1660 {apiservertesting.ErrUnauthorized}, 1661 {apiservertesting.ErrUnauthorized}, 1662 {apiservertesting.ErrUnauthorized}, 1663 {apiservertesting.ErrUnauthorized}, 1664 {apiservertesting.ErrUnauthorized}, 1665 }, 1666 }) 1667 1668 // Verify the scope changes and settings. 1669 s.assertInScope(c, relUnit, true) 1670 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1671 c.Assert(err, jc.ErrorIsNil) 1672 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 1673 "private-address": "1.2.3.4", 1674 }) 1675 } 1676 1677 func (s *uniterBaseSuite) testLeaveScope( 1678 c *gc.C, 1679 facade interface { 1680 LeaveScope(args params.RelationUnits) (params.ErrorResults, error) 1681 }, 1682 ) { 1683 rel := s.addRelation(c, "wordpress", "mysql") 1684 relUnit, err := rel.Unit(s.wordpressUnit) 1685 c.Assert(err, jc.ErrorIsNil) 1686 settings := map[string]interface{}{ 1687 "some": "settings", 1688 } 1689 err = relUnit.EnterScope(settings) 1690 c.Assert(err, jc.ErrorIsNil) 1691 s.assertInScope(c, relUnit, true) 1692 1693 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1694 {Relation: "relation-42", Unit: "unit-foo-0"}, 1695 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1696 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1697 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1698 {Relation: "relation-foo", Unit: "unit-wordpress-0"}, 1699 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1700 {Relation: "foo", Unit: "bar"}, 1701 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1702 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1703 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1704 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1705 }} 1706 result, err := facade.LeaveScope(args) 1707 c.Assert(err, jc.ErrorIsNil) 1708 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 1709 Results: []params.ErrorResult{ 1710 {apiservertesting.ErrUnauthorized}, 1711 {nil}, 1712 {nil}, 1713 {apiservertesting.ErrUnauthorized}, 1714 {apiservertesting.ErrUnauthorized}, 1715 {apiservertesting.ErrUnauthorized}, 1716 {apiservertesting.ErrUnauthorized}, 1717 {apiservertesting.ErrUnauthorized}, 1718 {apiservertesting.ErrUnauthorized}, 1719 {apiservertesting.ErrUnauthorized}, 1720 {apiservertesting.ErrUnauthorized}, 1721 }, 1722 }) 1723 1724 // Verify the scope changes. 1725 s.assertInScope(c, relUnit, false) 1726 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 1727 c.Assert(err, jc.ErrorIsNil) 1728 c.Assert(readSettings, gc.DeepEquals, settings) 1729 } 1730 1731 func (s *uniterBaseSuite) testJoinedRelations( 1732 c *gc.C, 1733 facade interface { 1734 JoinedRelations(args params.Entities) (params.StringsResults, error) 1735 }, 1736 ) { 1737 rel := s.addRelation(c, "wordpress", "mysql") 1738 relUnit, err := rel.Unit(s.wordpressUnit) 1739 c.Assert(err, jc.ErrorIsNil) 1740 err = relUnit.EnterScope(nil) 1741 c.Assert(err, jc.ErrorIsNil) 1742 1743 args := params.Entities{ 1744 Entities: []params.Entity{ 1745 {s.wordpressUnit.Tag().String()}, 1746 {s.mysqlUnit.Tag().String()}, 1747 {"unit-unknown-1"}, 1748 {"service-wordpress"}, 1749 {"machine-0"}, 1750 {rel.Tag().String()}, 1751 }, 1752 } 1753 expect := params.StringsResults{ 1754 Results: []params.StringsResult{ 1755 {Result: []string{rel.Tag().String()}}, 1756 {Error: apiservertesting.ErrUnauthorized}, 1757 {Error: apiservertesting.ErrUnauthorized}, 1758 {Error: apiservertesting.ErrUnauthorized}, 1759 {Error: apiservertesting.ErrUnauthorized}, 1760 {Error: apiservertesting.ErrUnauthorized}, 1761 }, 1762 } 1763 check := func() { 1764 result, err := facade.JoinedRelations(args) 1765 c.Assert(err, jc.ErrorIsNil) 1766 c.Assert(result, gc.DeepEquals, expect) 1767 } 1768 check() 1769 err = relUnit.PrepareLeaveScope() 1770 c.Assert(err, jc.ErrorIsNil) 1771 check() 1772 } 1773 1774 type readSettings interface { 1775 ReadSettings(args params.RelationUnits) (params.SettingsResults, error) 1776 } 1777 1778 func (s *uniterBaseSuite) testReadSettings(c *gc.C, facade readSettings) { 1779 rel := s.addRelation(c, "wordpress", "mysql") 1780 relUnit, err := rel.Unit(s.wordpressUnit) 1781 c.Assert(err, jc.ErrorIsNil) 1782 settings := map[string]interface{}{ 1783 "some": "settings", 1784 } 1785 err = relUnit.EnterScope(settings) 1786 c.Assert(err, jc.ErrorIsNil) 1787 s.assertInScope(c, relUnit, true) 1788 1789 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1790 {Relation: "relation-42", Unit: "unit-foo-0"}, 1791 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1792 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1793 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 1794 {Relation: "relation-foo", Unit: ""}, 1795 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 1796 {Relation: "foo", Unit: "bar"}, 1797 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 1798 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 1799 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 1800 {Relation: rel.Tag().String(), Unit: "user-foo"}, 1801 }} 1802 result, err := facade.ReadSettings(args) 1803 c.Assert(err, jc.ErrorIsNil) 1804 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1805 Results: []params.SettingsResult{ 1806 {Error: apiservertesting.ErrUnauthorized}, 1807 {Settings: params.Settings{ 1808 "some": "settings", 1809 }}, 1810 {Error: apiservertesting.ErrUnauthorized}, 1811 {Error: apiservertesting.ErrUnauthorized}, 1812 {Error: apiservertesting.ErrUnauthorized}, 1813 {Error: apiservertesting.ErrUnauthorized}, 1814 {Error: apiservertesting.ErrUnauthorized}, 1815 {Error: apiservertesting.ErrUnauthorized}, 1816 {Error: apiservertesting.ErrUnauthorized}, 1817 {Error: apiservertesting.ErrUnauthorized}, 1818 {Error: apiservertesting.ErrUnauthorized}, 1819 }, 1820 }) 1821 } 1822 1823 func (s *uniterBaseSuite) testReadSettingsWithNonStringValuesFails(c *gc.C, facade readSettings) { 1824 rel := s.addRelation(c, "wordpress", "mysql") 1825 relUnit, err := rel.Unit(s.wordpressUnit) 1826 c.Assert(err, jc.ErrorIsNil) 1827 settings := map[string]interface{}{ 1828 "other": "things", 1829 "invalid-bool": false, 1830 } 1831 err = relUnit.EnterScope(settings) 1832 c.Assert(err, jc.ErrorIsNil) 1833 s.assertInScope(c, relUnit, true) 1834 1835 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 1836 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 1837 }} 1838 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1839 result, err := facade.ReadSettings(args) 1840 c.Assert(err, jc.ErrorIsNil) 1841 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1842 Results: []params.SettingsResult{ 1843 {Error: ¶ms.Error{Message: expectErr}}, 1844 }, 1845 }) 1846 } 1847 1848 type readRemoteSettings interface { 1849 ReadRemoteSettings(args params.RelationUnitPairs) (params.SettingsResults, error) 1850 } 1851 1852 func (s *uniterBaseSuite) testReadRemoteSettings(c *gc.C, facade readRemoteSettings) { 1853 rel := s.addRelation(c, "wordpress", "mysql") 1854 relUnit, err := rel.Unit(s.wordpressUnit) 1855 c.Assert(err, jc.ErrorIsNil) 1856 settings := map[string]interface{}{ 1857 "some": "settings", 1858 } 1859 err = relUnit.EnterScope(settings) 1860 c.Assert(err, jc.ErrorIsNil) 1861 s.assertInScope(c, relUnit, true) 1862 1863 // First test most of the invalid args tests and try to read the 1864 // (unset) remote unit settings. 1865 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{ 1866 {Relation: "relation-42", LocalUnit: "unit-foo-0", RemoteUnit: "foo"}, 1867 {Relation: rel.Tag().String(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-wordpress-0"}, 1868 {Relation: rel.Tag().String(), LocalUnit: "unit-wordpress-0", RemoteUnit: "unit-mysql-0"}, 1869 {Relation: "relation-42", LocalUnit: "unit-wordpress-0", RemoteUnit: ""}, 1870 {Relation: "relation-foo", LocalUnit: "", RemoteUnit: ""}, 1871 {Relation: "service-wordpress", LocalUnit: "unit-foo-0", RemoteUnit: "user-foo"}, 1872 {Relation: "foo", LocalUnit: "bar", RemoteUnit: "baz"}, 1873 {Relation: rel.Tag().String(), LocalUnit: "unit-mysql-0", RemoteUnit: "unit-wordpress-0"}, 1874 {Relation: rel.Tag().String(), LocalUnit: "service-wordpress", RemoteUnit: "service-mysql"}, 1875 {Relation: rel.Tag().String(), LocalUnit: "service-mysql", RemoteUnit: "foo"}, 1876 {Relation: rel.Tag().String(), LocalUnit: "user-foo", RemoteUnit: "unit-wordpress-0"}, 1877 }} 1878 result, err := facade.ReadRemoteSettings(args) 1879 1880 // We don't set the remote unit settings on purpose to test the error. 1881 expectErr := `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings` 1882 c.Assert(err, jc.ErrorIsNil) 1883 c.Assert(result, jc.DeepEquals, params.SettingsResults{ 1884 Results: []params.SettingsResult{ 1885 {Error: apiservertesting.ErrUnauthorized}, 1886 {Error: apiservertesting.ErrUnauthorized}, 1887 {Error: apiservertesting.NotFoundError(expectErr)}, 1888 {Error: apiservertesting.ErrUnauthorized}, 1889 {Error: apiservertesting.ErrUnauthorized}, 1890 {Error: apiservertesting.ErrUnauthorized}, 1891 {Error: apiservertesting.ErrUnauthorized}, 1892 {Error: apiservertesting.ErrUnauthorized}, 1893 {Error: apiservertesting.ErrUnauthorized}, 1894 {Error: apiservertesting.ErrUnauthorized}, 1895 {Error: apiservertesting.ErrUnauthorized}, 1896 }, 1897 }) 1898 1899 // Now leave the mysqlUnit and re-enter with new settings. 1900 relUnit, err = rel.Unit(s.mysqlUnit) 1901 c.Assert(err, jc.ErrorIsNil) 1902 settings = map[string]interface{}{ 1903 "other": "things", 1904 } 1905 err = relUnit.LeaveScope() 1906 c.Assert(err, jc.ErrorIsNil) 1907 s.assertInScope(c, relUnit, false) 1908 err = relUnit.EnterScope(settings) 1909 c.Assert(err, jc.ErrorIsNil) 1910 s.assertInScope(c, relUnit, true) 1911 1912 // Test the remote unit settings can be read. 1913 args = params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1914 Relation: rel.Tag().String(), 1915 LocalUnit: "unit-wordpress-0", 1916 RemoteUnit: "unit-mysql-0", 1917 }}} 1918 expect := params.SettingsResults{ 1919 Results: []params.SettingsResult{ 1920 {Settings: params.Settings{ 1921 "other": "things", 1922 }}, 1923 }, 1924 } 1925 result, err = facade.ReadRemoteSettings(args) 1926 c.Assert(err, jc.ErrorIsNil) 1927 c.Assert(result, gc.DeepEquals, expect) 1928 1929 // Now destroy the remote unit, and check its settings can still be read. 1930 err = s.mysqlUnit.Destroy() 1931 c.Assert(err, jc.ErrorIsNil) 1932 err = s.mysqlUnit.EnsureDead() 1933 c.Assert(err, jc.ErrorIsNil) 1934 err = s.mysqlUnit.Remove() 1935 c.Assert(err, jc.ErrorIsNil) 1936 result, err = facade.ReadRemoteSettings(args) 1937 c.Assert(err, jc.ErrorIsNil) 1938 c.Assert(result, gc.DeepEquals, expect) 1939 } 1940 1941 func (s *uniterBaseSuite) testReadRemoteSettingsWithNonStringValuesFails(c *gc.C, facade readRemoteSettings) { 1942 rel := s.addRelation(c, "wordpress", "mysql") 1943 relUnit, err := rel.Unit(s.mysqlUnit) 1944 c.Assert(err, jc.ErrorIsNil) 1945 settings := map[string]interface{}{ 1946 "other": "things", 1947 "invalid-bool": false, 1948 } 1949 err = relUnit.EnterScope(settings) 1950 c.Assert(err, jc.ErrorIsNil) 1951 s.assertInScope(c, relUnit, true) 1952 1953 args := params.RelationUnitPairs{RelationUnitPairs: []params.RelationUnitPair{{ 1954 Relation: rel.Tag().String(), 1955 LocalUnit: "unit-wordpress-0", 1956 RemoteUnit: "unit-mysql-0", 1957 }}} 1958 expectErr := `unexpected relation setting "invalid-bool": expected string, got bool` 1959 result, err := facade.ReadRemoteSettings(args) 1960 c.Assert(err, jc.ErrorIsNil) 1961 c.Assert(result, gc.DeepEquals, params.SettingsResults{ 1962 Results: []params.SettingsResult{ 1963 {Error: ¶ms.Error{Message: expectErr}}, 1964 }, 1965 }) 1966 } 1967 1968 func (s *uniterBaseSuite) testUpdateSettings( 1969 c *gc.C, 1970 facade interface { 1971 UpdateSettings(args params.RelationUnitsSettings) (params.ErrorResults, error) 1972 }, 1973 ) { 1974 rel := s.addRelation(c, "wordpress", "mysql") 1975 relUnit, err := rel.Unit(s.wordpressUnit) 1976 c.Assert(err, jc.ErrorIsNil) 1977 settings := map[string]interface{}{ 1978 "some": "settings", 1979 "other": "stuff", 1980 } 1981 err = relUnit.EnterScope(settings) 1982 s.assertInScope(c, relUnit, true) 1983 1984 newSettings := params.Settings{ 1985 "some": "different", 1986 "other": "", 1987 } 1988 1989 args := params.RelationUnitsSettings{RelationUnits: []params.RelationUnitSettings{ 1990 {Relation: "relation-42", Unit: "unit-foo-0", Settings: nil}, 1991 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0", Settings: newSettings}, 1992 {Relation: "relation-42", Unit: "unit-wordpress-0", Settings: nil}, 1993 {Relation: "relation-foo", Unit: "unit-wordpress-0", Settings: nil}, 1994 {Relation: "service-wordpress", Unit: "unit-foo-0", Settings: nil}, 1995 {Relation: "foo", Unit: "bar", Settings: nil}, 1996 {Relation: rel.Tag().String(), Unit: "unit-mysql-0", Settings: nil}, 1997 {Relation: rel.Tag().String(), Unit: "service-wordpress", Settings: nil}, 1998 {Relation: rel.Tag().String(), Unit: "service-mysql", Settings: nil}, 1999 {Relation: rel.Tag().String(), Unit: "user-foo", Settings: nil}, 2000 }} 2001 result, err := facade.UpdateSettings(args) 2002 c.Assert(err, jc.ErrorIsNil) 2003 c.Assert(result, gc.DeepEquals, params.ErrorResults{ 2004 Results: []params.ErrorResult{ 2005 {apiservertesting.ErrUnauthorized}, 2006 {nil}, 2007 {apiservertesting.ErrUnauthorized}, 2008 {apiservertesting.ErrUnauthorized}, 2009 {apiservertesting.ErrUnauthorized}, 2010 {apiservertesting.ErrUnauthorized}, 2011 {apiservertesting.ErrUnauthorized}, 2012 {apiservertesting.ErrUnauthorized}, 2013 {apiservertesting.ErrUnauthorized}, 2014 {apiservertesting.ErrUnauthorized}, 2015 }, 2016 }) 2017 2018 // Verify the settings were saved. 2019 s.assertInScope(c, relUnit, true) 2020 readSettings, err := relUnit.ReadSettings(s.wordpressUnit.Name()) 2021 c.Assert(err, jc.ErrorIsNil) 2022 c.Assert(readSettings, gc.DeepEquals, map[string]interface{}{ 2023 "some": "different", 2024 }) 2025 } 2026 2027 func (s *uniterBaseSuite) testWatchRelationUnits( 2028 c *gc.C, 2029 facade interface { 2030 WatchRelationUnits(args params.RelationUnits) (params.RelationUnitsWatchResults, error) 2031 }, 2032 ) { 2033 // Add a relation between wordpress and mysql and enter scope with 2034 // mysqlUnit. 2035 rel := s.addRelation(c, "wordpress", "mysql") 2036 myRelUnit, err := rel.Unit(s.mysqlUnit) 2037 c.Assert(err, jc.ErrorIsNil) 2038 err = myRelUnit.EnterScope(nil) 2039 c.Assert(err, jc.ErrorIsNil) 2040 s.assertInScope(c, myRelUnit, true) 2041 2042 c.Assert(s.resources.Count(), gc.Equals, 0) 2043 2044 args := params.RelationUnits{RelationUnits: []params.RelationUnit{ 2045 {Relation: "relation-42", Unit: "unit-foo-0"}, 2046 {Relation: rel.Tag().String(), Unit: "unit-wordpress-0"}, 2047 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 2048 {Relation: "relation-42", Unit: "unit-wordpress-0"}, 2049 {Relation: "relation-foo", Unit: ""}, 2050 {Relation: "service-wordpress", Unit: "unit-foo-0"}, 2051 {Relation: "foo", Unit: "bar"}, 2052 {Relation: rel.Tag().String(), Unit: "unit-mysql-0"}, 2053 {Relation: rel.Tag().String(), Unit: "service-wordpress"}, 2054 {Relation: rel.Tag().String(), Unit: "service-mysql"}, 2055 {Relation: rel.Tag().String(), Unit: "user-foo"}, 2056 }} 2057 result, err := facade.WatchRelationUnits(args) 2058 c.Assert(err, jc.ErrorIsNil) 2059 // UnitSettings versions are volatile, so we don't check them. 2060 // We just make sure the keys of the Changed field are as 2061 // expected. 2062 c.Assert(result.Results, gc.HasLen, len(args.RelationUnits)) 2063 mysqlChanges := result.Results[1].Changes 2064 c.Assert(mysqlChanges, gc.NotNil) 2065 changed, ok := mysqlChanges.Changed["mysql/0"] 2066 c.Assert(ok, jc.IsTrue) 2067 expectChanges := multiwatcher.RelationUnitsChange{ 2068 Changed: map[string]multiwatcher.UnitSettings{"mysql/0": changed}, 2069 } 2070 c.Assert(result, gc.DeepEquals, params.RelationUnitsWatchResults{ 2071 Results: []params.RelationUnitsWatchResult{ 2072 {Error: apiservertesting.ErrUnauthorized}, 2073 { 2074 RelationUnitsWatcherId: "1", 2075 Changes: expectChanges, 2076 }, 2077 {Error: apiservertesting.ErrUnauthorized}, 2078 {Error: apiservertesting.ErrUnauthorized}, 2079 {Error: apiservertesting.ErrUnauthorized}, 2080 {Error: apiservertesting.ErrUnauthorized}, 2081 {Error: apiservertesting.ErrUnauthorized}, 2082 {Error: apiservertesting.ErrUnauthorized}, 2083 {Error: apiservertesting.ErrUnauthorized}, 2084 {Error: apiservertesting.ErrUnauthorized}, 2085 {Error: apiservertesting.ErrUnauthorized}, 2086 }, 2087 }) 2088 2089 // Verify the resource was registered and stop when done 2090 c.Assert(s.resources.Count(), gc.Equals, 1) 2091 resource := s.resources.Get("1") 2092 defer statetesting.AssertStop(c, resource) 2093 2094 // Check that the Watch has consumed the initial event ("returned" in 2095 // the Watch call) 2096 wc := statetesting.NewRelationUnitsWatcherC(c, s.State, resource.(state.RelationUnitsWatcher)) 2097 wc.AssertNoChange() 2098 2099 // Leave scope with mysqlUnit and check it's detected. 2100 err = myRelUnit.LeaveScope() 2101 c.Assert(err, jc.ErrorIsNil) 2102 s.assertInScope(c, myRelUnit, false) 2103 2104 wc.AssertChange(nil, []string{"mysql/0"}) 2105 } 2106 2107 func (s *uniterBaseSuite) testAPIAddresses( 2108 c *gc.C, 2109 facade interface { 2110 APIAddresses() (params.StringsResult, error) 2111 }, 2112 ) { 2113 hostPorts := [][]network.HostPort{ 2114 network.NewHostPorts(1234, "0.1.2.3"), 2115 } 2116 err := s.State.SetAPIHostPorts(hostPorts) 2117 c.Assert(err, jc.ErrorIsNil) 2118 2119 result, err := facade.APIAddresses() 2120 c.Assert(err, jc.ErrorIsNil) 2121 c.Assert(result, gc.DeepEquals, params.StringsResult{ 2122 Result: []string{"0.1.2.3:1234"}, 2123 }) 2124 } 2125 2126 func (s *uniterBaseSuite) testWatchUnitAddresses( 2127 c *gc.C, 2128 facade interface { 2129 WatchUnitAddresses(args params.Entities) (params.NotifyWatchResults, error) 2130 }, 2131 ) { 2132 c.Assert(s.resources.Count(), gc.Equals, 0) 2133 2134 args := params.Entities{Entities: []params.Entity{ 2135 {Tag: "unit-mysql-0"}, 2136 {Tag: "unit-wordpress-0"}, 2137 {Tag: "unit-foo-42"}, 2138 {Tag: "machine-0"}, 2139 {Tag: "service-wordpress"}, 2140 }} 2141 result, err := facade.WatchUnitAddresses(args) 2142 c.Assert(err, jc.ErrorIsNil) 2143 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 2144 Results: []params.NotifyWatchResult{ 2145 {Error: apiservertesting.ErrUnauthorized}, 2146 {NotifyWatcherId: "1"}, 2147 {Error: apiservertesting.ErrUnauthorized}, 2148 {Error: apiservertesting.ErrUnauthorized}, 2149 {Error: apiservertesting.ErrUnauthorized}, 2150 }, 2151 }) 2152 2153 // Verify the resource was registered and stop when done 2154 c.Assert(s.resources.Count(), gc.Equals, 1) 2155 resource := s.resources.Get("1") 2156 defer statetesting.AssertStop(c, resource) 2157 2158 // Check that the Watch has consumed the initial event ("returned" in 2159 // the Watch call) 2160 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 2161 wc.AssertNoChange() 2162 } 2163 2164 type getMeterStatus interface { 2165 GetMeterStatus(args params.Entities) (params.MeterStatusResults, error) 2166 } 2167 2168 func (s *uniterBaseSuite) testGetMeterStatus(c *gc.C, facade getMeterStatus) { 2169 args := params.Entities{Entities: []params.Entity{{Tag: s.wordpressUnit.Tag().String()}}} 2170 result, err := facade.GetMeterStatus(args) 2171 c.Assert(err, jc.ErrorIsNil) 2172 c.Assert(result.Results, gc.HasLen, 1) 2173 c.Assert(result.Results[0].Error, gc.IsNil) 2174 c.Assert(result.Results[0].Code, gc.Equals, "AMBER") 2175 c.Assert(result.Results[0].Info, gc.Equals, "not set") 2176 2177 newCode := "GREEN" 2178 newInfo := "All is ok." 2179 2180 err = s.wordpressUnit.SetMeterStatus(newCode, newInfo) 2181 c.Assert(err, jc.ErrorIsNil) 2182 2183 result, err = facade.GetMeterStatus(args) 2184 c.Assert(err, jc.ErrorIsNil) 2185 c.Assert(result.Results, gc.HasLen, 1) 2186 c.Assert(result.Results[0].Error, gc.IsNil) 2187 c.Assert(result.Results[0].Code, gc.DeepEquals, newCode) 2188 c.Assert(result.Results[0].Info, gc.DeepEquals, newInfo) 2189 } 2190 2191 func (s *uniterBaseSuite) testGetMeterStatusUnauthenticated(c *gc.C, facade getMeterStatus) { 2192 args := params.Entities{Entities: []params.Entity{{s.mysqlUnit.Tag().String()}}} 2193 result, err := facade.GetMeterStatus(args) 2194 c.Assert(err, jc.ErrorIsNil) 2195 c.Assert(result.Results, gc.HasLen, 1) 2196 c.Assert(result.Results[0].Error, gc.ErrorMatches, "permission denied") 2197 c.Assert(result.Results[0].Code, gc.Equals, "") 2198 c.Assert(result.Results[0].Info, gc.Equals, "") 2199 } 2200 2201 func (s *uniterBaseSuite) testGetMeterStatusBadTag(c *gc.C, facade getMeterStatus) { 2202 tags := []string{ 2203 "user-admin", 2204 "unit-nosuchunit", 2205 "thisisnotatag", 2206 "machine-0", 2207 "environment-blah", 2208 } 2209 args := params.Entities{Entities: make([]params.Entity, len(tags))} 2210 for i, tag := range tags { 2211 args.Entities[i] = params.Entity{Tag: tag} 2212 } 2213 result, err := facade.GetMeterStatus(args) 2214 c.Assert(err, jc.ErrorIsNil) 2215 c.Assert(result.Results, gc.HasLen, len(tags)) 2216 for i, result := range result.Results { 2217 c.Logf("checking result %d", i) 2218 c.Assert(result.Code, gc.Equals, "") 2219 c.Assert(result.Info, gc.Equals, "") 2220 c.Assert(result.Error, gc.ErrorMatches, "permission denied") 2221 } 2222 } 2223 2224 func (s *uniterBaseSuite) testWatchMeterStatus( 2225 c *gc.C, 2226 facade interface { 2227 WatchMeterStatus(args params.Entities) (params.NotifyWatchResults, error) 2228 }, 2229 ) { 2230 c.Assert(s.resources.Count(), gc.Equals, 0) 2231 2232 args := params.Entities{Entities: []params.Entity{ 2233 {Tag: "unit-mysql-0"}, 2234 {Tag: "unit-wordpress-0"}, 2235 {Tag: "unit-foo-42"}, 2236 }} 2237 result, err := facade.WatchMeterStatus(args) 2238 c.Assert(err, jc.ErrorIsNil) 2239 c.Assert(result, gc.DeepEquals, params.NotifyWatchResults{ 2240 Results: []params.NotifyWatchResult{ 2241 {Error: apiservertesting.ErrUnauthorized}, 2242 {NotifyWatcherId: "1"}, 2243 {Error: apiservertesting.ErrUnauthorized}, 2244 }, 2245 }) 2246 2247 // Verify the resource was registered and stop when done 2248 c.Assert(s.resources.Count(), gc.Equals, 1) 2249 resource := s.resources.Get("1") 2250 defer statetesting.AssertStop(c, resource) 2251 2252 // Check that the Watch has consumed the initial event ("returned" in 2253 // the Watch call) 2254 wc := statetesting.NewNotifyWatcherC(c, s.State, resource.(state.NotifyWatcher)) 2255 wc.AssertNoChange() 2256 2257 err = s.wordpressUnit.SetMeterStatus("GREEN", "No additional information.") 2258 c.Assert(err, jc.ErrorIsNil) 2259 wc.AssertOneChange() 2260 } 2261 2262 func (s *uniterBaseSuite) assertOneStringsWatcher(c *gc.C, result params.StringsWatchResults, err error) { 2263 c.Assert(err, jc.ErrorIsNil) 2264 c.Assert(result.Results, gc.HasLen, 3) 2265 c.Assert(result.Results[0].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 2266 c.Assert(result.Results[1].StringsWatcherId, gc.Equals, "1") 2267 c.Assert(result.Results[1].Changes, gc.NotNil) 2268 c.Assert(result.Results[1].Error, gc.IsNil) 2269 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 2270 2271 // Verify the resource was registered and stop when done 2272 c.Assert(s.resources.Count(), gc.Equals, 1) 2273 resource := s.resources.Get("1") 2274 defer statetesting.AssertStop(c, resource) 2275 2276 // Check that the Watch has consumed the initial event ("returned" in 2277 // the Watch call) 2278 wc := statetesting.NewStringsWatcherC(c, s.State, resource.(state.StringsWatcher)) 2279 wc.AssertNoChange() 2280 } 2281 2282 func (s *uniterBaseSuite) assertInScope(c *gc.C, relUnit *state.RelationUnit, inScope bool) { 2283 ok, err := relUnit.InScope() 2284 c.Assert(err, jc.ErrorIsNil) 2285 c.Assert(ok, gc.Equals, inScope) 2286 } 2287 2288 func (s *uniterBaseSuite) addRelation(c *gc.C, first, second string) *state.Relation { 2289 eps, err := s.State.InferEndpoints(first, second) 2290 c.Assert(err, jc.ErrorIsNil) 2291 rel, err := s.State.AddRelation(eps...) 2292 c.Assert(err, jc.ErrorIsNil) 2293 return rel 2294 } 2295 2296 func (s *uniterBaseSuite) addRelatedService(c *gc.C, firstSvc, relatedSvc string, unit *state.Unit) (*state.Relation, *state.Service, *state.Unit) { 2297 relatedService := s.AddTestingService(c, relatedSvc, s.AddTestingCharm(c, relatedSvc)) 2298 rel := s.addRelation(c, firstSvc, relatedSvc) 2299 relUnit, err := rel.Unit(unit) 2300 c.Assert(err, jc.ErrorIsNil) 2301 err = relUnit.EnterScope(nil) 2302 c.Assert(err, jc.ErrorIsNil) 2303 relatedUnit, err := s.State.Unit(relatedSvc + "/0") 2304 c.Assert(err, jc.ErrorIsNil) 2305 return rel, relatedService, relatedUnit 2306 } 2307 2308 func checkUnorderedActionIdsEqual(c *gc.C, ids []string, results params.StringsWatchResults) { 2309 c.Assert(results, gc.NotNil) 2310 content := results.Results 2311 c.Assert(len(content), gc.Equals, 1) 2312 result := content[0] 2313 c.Assert(result.StringsWatcherId, gc.Equals, "1") 2314 obtainedIds := map[string]int{} 2315 expectedIds := map[string]int{} 2316 for _, id := range ids { 2317 expectedIds[id]++ 2318 } 2319 // The count of each ID that has been seen. 2320 for _, change := range result.Changes { 2321 obtainedIds[change]++ 2322 } 2323 c.Check(obtainedIds, jc.DeepEquals, expectedIds) 2324 }