github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/relationunit_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "fmt" 8 "sort" 9 "strconv" 10 "time" 11 12 "github.com/juju/errors" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v6-unstable" 16 17 "github.com/juju/juju/network" 18 "github.com/juju/juju/state" 19 "github.com/juju/juju/state/testing" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type RUs []*state.RelationUnit 24 25 type RelationUnitSuite struct { 26 ConnSuite 27 } 28 29 var _ = gc.Suite(&RelationUnitSuite{}) 30 31 func assertInScope(c *gc.C, ru *state.RelationUnit) { 32 ok, err := ru.InScope() 33 c.Assert(err, jc.ErrorIsNil) 34 c.Assert(ok, jc.IsTrue) 35 } 36 37 func assertNotInScope(c *gc.C, ru *state.RelationUnit) { 38 assertNotJoined(c, ru) 39 ok, err := ru.InScope() 40 c.Assert(err, jc.ErrorIsNil) 41 c.Assert(ok, jc.IsFalse) 42 } 43 44 func assertJoined(c *gc.C, ru *state.RelationUnit) { 45 assertInScope(c, ru) 46 ok, err := ru.Joined() 47 c.Assert(err, jc.ErrorIsNil) 48 c.Assert(ok, jc.IsTrue) 49 } 50 51 func assertNotJoined(c *gc.C, ru *state.RelationUnit) { 52 ok, err := ru.Joined() 53 c.Assert(err, jc.ErrorIsNil) 54 c.Assert(ok, jc.IsFalse) 55 } 56 57 func (s *RelationUnitSuite) TestReadSettingsErrors(c *gc.C) { 58 riak := s.AddTestingService(c, "riak", s.AddTestingCharm(c, "riak")) 59 u0, err := riak.AddUnit() 60 c.Assert(err, jc.ErrorIsNil) 61 riakEP, err := riak.Endpoint("ring") 62 c.Assert(err, jc.ErrorIsNil) 63 rel, err := s.State.EndpointsRelation(riakEP) 64 c.Assert(err, jc.ErrorIsNil) 65 ru0, err := rel.Unit(u0) 66 c.Assert(err, jc.ErrorIsNil) 67 68 _, err = ru0.ReadSettings("nonsense") 69 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "nonsense" in relation "riak:ring": "nonsense" is not a valid unit name`) 70 _, err = ru0.ReadSettings("unknown/0") 71 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "unknown/0" in relation "riak:ring": application "unknown" is not a member of "riak:ring"`) 72 _, err = ru0.ReadSettings("riak/pressure") 73 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/pressure" in relation "riak:ring": "riak/pressure" is not a valid unit name`) 74 _, err = ru0.ReadSettings("riak/1") 75 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/1" in relation "riak:ring": settings not found`) 76 } 77 78 func (s *RelationUnitSuite) TestPeerSettings(c *gc.C) { 79 pr := NewPeerRelation(c, s.State) 80 rus := RUs{pr.ru0, pr.ru1} 81 82 // Check missing settings cannot be read by any RU. 83 for _, ru := range rus { 84 _, err := ru.ReadSettings("riak/0") 85 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": settings not found`) 86 } 87 88 // Add settings for one RU. 89 assertNotInScope(c, pr.ru0) 90 err := pr.ru0.EnterScope(map[string]interface{}{"gene": "kelly"}) 91 c.Assert(err, jc.ErrorIsNil) 92 node, err := pr.ru0.Settings() 93 c.Assert(err, jc.ErrorIsNil) 94 node.Set("meme", "socially-awkward-penguin") 95 _, err = node.Write() 96 c.Assert(err, jc.ErrorIsNil) 97 normal := map[string]interface{}{ 98 "gene": "kelly", 99 "meme": "socially-awkward-penguin", 100 } 101 102 // Check settings can be read by every RU. 103 assertSettings := func(u *state.Unit, expect map[string]interface{}) { 104 for _, ru := range rus { 105 m, err := ru.ReadSettings(u.Name()) 106 c.Assert(err, jc.ErrorIsNil) 107 c.Assert(m, gc.DeepEquals, expect) 108 } 109 } 110 assertSettings(pr.u0, normal) 111 assertJoined(c, pr.ru0) 112 113 // Check that EnterScope when scope already entered does not touch 114 // settings at all. 115 changed := map[string]interface{}{"foo": "bar"} 116 err = pr.ru0.EnterScope(changed) 117 c.Assert(err, jc.ErrorIsNil) 118 assertSettings(pr.u0, normal) 119 assertJoined(c, pr.ru0) 120 121 // Leave scope, check settings are still as accessible as before. 122 err = pr.ru0.LeaveScope() 123 c.Assert(err, jc.ErrorIsNil) 124 assertSettings(pr.u0, normal) 125 assertNotInScope(c, pr.ru0) 126 127 // Re-enter scope wih changed settings, and check they completely overwrite 128 // the old ones. 129 err = pr.ru0.EnterScope(changed) 130 c.Assert(err, jc.ErrorIsNil) 131 assertSettings(pr.u0, changed) 132 assertJoined(c, pr.ru0) 133 134 // Leave and re-enter with nil nettings, and check they overwrite to become 135 // an empty map. 136 err = pr.ru0.LeaveScope() 137 c.Assert(err, jc.ErrorIsNil) 138 assertNotInScope(c, pr.ru0) 139 err = pr.ru0.EnterScope(nil) 140 c.Assert(err, jc.ErrorIsNil) 141 assertSettings(pr.u0, map[string]interface{}{}) 142 assertJoined(c, pr.ru0) 143 144 // Check that entering scope for the first time with nil settings works correctly. 145 assertNotInScope(c, pr.ru1) 146 err = pr.ru1.EnterScope(nil) 147 c.Assert(err, jc.ErrorIsNil) 148 assertSettings(pr.u1, map[string]interface{}{}) 149 assertJoined(c, pr.ru1) 150 } 151 152 func (s *RelationUnitSuite) TestProReqSettings(c *gc.C) { 153 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal) 154 rus := RUs{prr.pru0, prr.pru1, prr.rru0, prr.rru1} 155 156 // Check missing settings cannot be read by any RU. 157 for _, ru := range rus { 158 _, err := ru.ReadSettings("mysql/0") 159 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "mysql/0" in relation "wordpress:db mysql:server": settings not found`) 160 } 161 162 // Add settings for one RU. 163 assertNotInScope(c, prr.pru0) 164 err := prr.pru0.EnterScope(map[string]interface{}{"gene": "simmons"}) 165 c.Assert(err, jc.ErrorIsNil) 166 node, err := prr.pru0.Settings() 167 c.Assert(err, jc.ErrorIsNil) 168 node.Set("meme", "foul-bachelor-frog") 169 _, err = node.Write() 170 c.Assert(err, jc.ErrorIsNil) 171 assertJoined(c, prr.pru0) 172 173 // Check settings can be read by every RU. 174 for _, ru := range rus { 175 m, err := ru.ReadSettings("mysql/0") 176 c.Assert(err, jc.ErrorIsNil) 177 c.Assert(m["gene"], gc.Equals, "simmons") 178 c.Assert(m["meme"], gc.Equals, "foul-bachelor-frog") 179 } 180 } 181 182 func (s *RelationUnitSuite) TestContainerSettings(c *gc.C) { 183 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeContainer) 184 rus := RUs{prr.pru0, prr.pru1, prr.rru0, prr.rru1} 185 186 // Check missing settings cannot be read by any RU. 187 for _, ru := range rus { 188 _, err := ru.ReadSettings("logging/0") 189 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "logging/0" in relation "logging:info mysql:juju-info": settings not found`) 190 } 191 192 // Add settings for one RU. 193 assertNotInScope(c, prr.pru0) 194 err := prr.pru0.EnterScope(map[string]interface{}{"gene": "hackman"}) 195 c.Assert(err, jc.ErrorIsNil) 196 node, err := prr.pru0.Settings() 197 c.Assert(err, jc.ErrorIsNil) 198 node.Set("meme", "foul-bachelor-frog") 199 _, err = node.Write() 200 c.Assert(err, jc.ErrorIsNil) 201 assertJoined(c, prr.pru0) 202 203 // Check settings can be read by RUs in the same container. 204 rus0 := RUs{prr.pru0, prr.rru0} 205 for _, ru := range rus0 { 206 m, err := ru.ReadSettings("mysql/0") 207 c.Assert(err, jc.ErrorIsNil) 208 c.Assert(m["gene"], gc.Equals, "hackman") 209 c.Assert(m["meme"], gc.Equals, "foul-bachelor-frog") 210 } 211 212 // Check settings are still inaccessible to RUs outside that container 213 rus1 := RUs{prr.pru1, prr.rru1} 214 for _, ru := range rus1 { 215 _, err := ru.ReadSettings("mysql/0") 216 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "mysql/0" in relation "logging:info mysql:juju-info": settings not found`) 217 } 218 } 219 220 func (s *RelationUnitSuite) TestContainerCreateSubordinate(c *gc.C) { 221 psvc := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 222 rsvc := s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 223 eps, err := s.State.InferEndpoints("mysql", "logging") 224 c.Assert(err, jc.ErrorIsNil) 225 rel, err := s.State.AddRelation(eps...) 226 c.Assert(err, jc.ErrorIsNil) 227 punit, err := psvc.AddUnit() 228 c.Assert(err, jc.ErrorIsNil) 229 pru, err := rel.Unit(punit) 230 c.Assert(err, jc.ErrorIsNil) 231 232 // Check that no units of the subordinate service exist. 233 assertSubCount := func(expect int) []*state.Unit { 234 runits, err := rsvc.AllUnits() 235 c.Assert(err, jc.ErrorIsNil) 236 c.Assert(runits, gc.HasLen, expect) 237 return runits 238 } 239 assertSubCount(0) 240 241 // Enter principal's scope and check a subordinate was created. 242 assertNotInScope(c, pru) 243 err = pru.EnterScope(nil) 244 c.Assert(err, jc.ErrorIsNil) 245 assertSubCount(1) 246 assertJoined(c, pru) 247 248 // Enter principal scope again and check no more subordinates created. 249 err = pru.EnterScope(nil) 250 c.Assert(err, jc.ErrorIsNil) 251 assertSubCount(1) 252 assertJoined(c, pru) 253 254 // Leave principal scope, then re-enter, and check that still no further 255 // subordinates are created. 256 err = pru.LeaveScope() 257 c.Assert(err, jc.ErrorIsNil) 258 assertNotInScope(c, pru) 259 err = pru.EnterScope(nil) 260 c.Assert(err, jc.ErrorIsNil) 261 runits := assertSubCount(1) 262 assertJoined(c, pru) 263 264 // Set the subordinate to Dying, and enter scope again; because the scope 265 // is already entered, no error is returned. 266 runit := runits[0] 267 err = runit.Destroy() 268 c.Assert(err, jc.ErrorIsNil) 269 err = pru.EnterScope(nil) 270 c.Assert(err, jc.ErrorIsNil) 271 assertJoined(c, pru) 272 273 // Leave scope, then try to enter again with the Dying subordinate. 274 err = pru.LeaveScope() 275 c.Assert(err, jc.ErrorIsNil) 276 assertNotInScope(c, pru) 277 err = pru.EnterScope(nil) 278 c.Assert(err, gc.Equals, state.ErrCannotEnterScopeYet) 279 assertNotInScope(c, pru) 280 281 // Remove the subordinate, and enter scope again; this should work, and 282 // create a new subordinate. 283 err = runit.EnsureDead() 284 c.Assert(err, jc.ErrorIsNil) 285 err = runit.Remove() 286 c.Assert(err, jc.ErrorIsNil) 287 assertSubCount(0) 288 assertNotInScope(c, pru) 289 err = pru.EnterScope(nil) 290 c.Assert(err, jc.ErrorIsNil) 291 assertSubCount(1) 292 assertJoined(c, pru) 293 } 294 295 func (s *RelationUnitSuite) TestDestroyRelationWithUnitsInScope(c *gc.C) { 296 pr := NewPeerRelation(c, s.State) 297 rel := pr.ru0.Relation() 298 299 // Enter two units, and check that Destroying the service sets the 300 // relation to Dying (rather than removing it directly). 301 assertNotInScope(c, pr.ru0) 302 err := pr.ru0.EnterScope(map[string]interface{}{"some": "settings"}) 303 c.Assert(err, jc.ErrorIsNil) 304 assertJoined(c, pr.ru0) 305 assertNotInScope(c, pr.ru1) 306 err = pr.ru1.EnterScope(nil) 307 c.Assert(err, jc.ErrorIsNil) 308 assertJoined(c, pr.ru1) 309 err = pr.svc.Destroy() 310 c.Assert(err, jc.ErrorIsNil) 311 err = rel.Refresh() 312 c.Assert(err, jc.ErrorIsNil) 313 c.Assert(rel.Life(), gc.Equals, state.Dying) 314 315 // Check that we can't add a new unit now. 316 assertNotInScope(c, pr.ru2) 317 err = pr.ru2.EnterScope(nil) 318 c.Assert(err, gc.Equals, state.ErrCannotEnterScope) 319 assertNotInScope(c, pr.ru2) 320 321 // Check that we created no settings for the unit we failed to add. 322 _, err = pr.ru0.ReadSettings("riak/2") 323 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/2" in relation "riak:ring": settings not found`) 324 325 // ru0 leaves the scope; check that service Destroy is still a no-op. 326 assertJoined(c, pr.ru0) 327 err = pr.ru0.LeaveScope() 328 c.Assert(err, jc.ErrorIsNil) 329 assertNotInScope(c, pr.ru0) 330 err = pr.svc.Destroy() 331 c.Assert(err, jc.ErrorIsNil) 332 333 // Check that unit settings for the original unit still exist, and have 334 // not yet been marked for deletion. 335 err = s.State.Cleanup() 336 c.Assert(err, jc.ErrorIsNil) 337 assertSettings := func() { 338 settings, err := pr.ru1.ReadSettings("riak/0") 339 c.Assert(err, jc.ErrorIsNil) 340 c.Assert(settings, gc.DeepEquals, map[string]interface{}{"some": "settings"}) 341 } 342 assertSettings() 343 344 // The final unit leaves the scope, and cleans up after itself. 345 assertJoined(c, pr.ru1) 346 err = pr.ru1.LeaveScope() 347 c.Assert(err, jc.ErrorIsNil) 348 assertNotInScope(c, pr.ru1) 349 err = rel.Refresh() 350 c.Assert(err, jc.Satisfies, errors.IsNotFound) 351 352 // The settings were not themselves actually deleted yet... 353 assertSettings() 354 355 // ...but they were scheduled for deletion. 356 err = s.State.Cleanup() 357 c.Assert(err, jc.ErrorIsNil) 358 _, err = pr.ru1.ReadSettings("riak/0") 359 c.Assert(err, gc.ErrorMatches, `cannot read settings for unit "riak/0" in relation "riak:ring": settings not found`) 360 } 361 362 func (s *RelationUnitSuite) TestAliveRelationScope(c *gc.C) { 363 pr := NewPeerRelation(c, s.State) 364 rel := pr.ru0.Relation() 365 366 // Two units enter... 367 assertNotInScope(c, pr.ru0) 368 err := pr.ru0.EnterScope(nil) 369 c.Assert(err, jc.ErrorIsNil) 370 assertJoined(c, pr.ru0) 371 assertNotInScope(c, pr.ru1) 372 err = pr.ru1.EnterScope(nil) 373 c.Assert(err, jc.ErrorIsNil) 374 assertJoined(c, pr.ru1) 375 376 // One unit becomes Dying, then re-enters the scope; this is not an error, 377 // because the state is already as requested. 378 err = pr.u0.Destroy() 379 c.Assert(err, jc.ErrorIsNil) 380 err = pr.ru0.EnterScope(nil) 381 c.Assert(err, jc.ErrorIsNil) 382 assertJoined(c, pr.ru0) 383 384 // Two units leave... 385 err = pr.ru0.LeaveScope() 386 c.Assert(err, jc.ErrorIsNil) 387 assertNotInScope(c, pr.ru0) 388 err = pr.ru1.LeaveScope() 389 c.Assert(err, jc.ErrorIsNil) 390 assertNotInScope(c, pr.ru1) 391 392 // The relation scope is empty, but the relation is still alive... 393 err = rel.Refresh() 394 c.Assert(err, jc.ErrorIsNil) 395 c.Assert(rel.Life(), gc.Equals, state.Alive) 396 397 // ...and new units can still join it... 398 assertNotInScope(c, pr.ru2) 399 err = pr.ru2.EnterScope(nil) 400 c.Assert(err, jc.ErrorIsNil) 401 assertJoined(c, pr.ru2) 402 403 // ...but Dying units cannot. 404 err = pr.u3.Destroy() 405 c.Assert(err, jc.ErrorIsNil) 406 assertNotInScope(c, pr.ru3) 407 err = pr.ru3.EnterScope(nil) 408 c.Assert(err, gc.Equals, state.ErrCannotEnterScope) 409 assertNotInScope(c, pr.ru3) 410 } 411 412 func (s *StateSuite) TestWatchWatchScopeDiesOnStateClose(c *gc.C) { 413 testWatcherDiesWhenStateCloses(c, s.modelTag, s.State.ControllerTag(), func(c *gc.C, st *state.State) waiter { 414 pr := NewPeerRelation(c, st) 415 w := pr.ru0.WatchScope() 416 <-w.Changes() 417 return w 418 }) 419 } 420 421 func (s *RelationUnitSuite) TestPeerWatchScope(c *gc.C) { 422 pr := NewPeerRelation(c, s.State) 423 424 // Test empty initial event. 425 w0 := pr.ru0.WatchScope() 426 defer testing.AssertStop(c, w0) 427 s.assertScopeChange(c, w0, nil, nil) 428 s.assertNoScopeChange(c, w0) 429 430 // ru0 enters; check no change, but settings written. 431 assertNotInScope(c, pr.ru0) 432 err := pr.ru0.EnterScope(map[string]interface{}{"foo": "bar"}) 433 c.Assert(err, jc.ErrorIsNil) 434 s.assertNoScopeChange(c, w0) 435 node, err := pr.ru0.Settings() 436 c.Assert(err, jc.ErrorIsNil) 437 c.Assert(node.Map(), gc.DeepEquals, map[string]interface{}{"foo": "bar"}) 438 assertJoined(c, pr.ru0) 439 440 // ru1 enters; check change is observed. 441 assertNotInScope(c, pr.ru1) 442 err = pr.ru1.EnterScope(nil) 443 c.Assert(err, jc.ErrorIsNil) 444 s.assertScopeChange(c, w0, []string{"riak/1"}, nil) 445 s.assertNoScopeChange(c, w0) 446 assertJoined(c, pr.ru1) 447 448 // ru1 enters again, check no problems and no changes. 449 err = pr.ru1.EnterScope(nil) 450 c.Assert(err, jc.ErrorIsNil) 451 s.assertNoScopeChange(c, w0) 452 assertJoined(c, pr.ru1) 453 454 // Stop watching; ru2 enters. 455 testing.AssertStop(c, w0) 456 assertNotInScope(c, pr.ru2) 457 err = pr.ru2.EnterScope(nil) 458 c.Assert(err, jc.ErrorIsNil) 459 assertJoined(c, pr.ru2) 460 461 // Start watch again, check initial event. 462 w0 = pr.ru0.WatchScope() 463 defer testing.AssertStop(c, w0) 464 s.assertScopeChange(c, w0, []string{"riak/1", "riak/2"}, nil) 465 s.assertNoScopeChange(c, w0) 466 467 // ru1 leaves; check event. 468 assertJoined(c, pr.ru1) 469 err = pr.ru1.LeaveScope() 470 c.Assert(err, jc.ErrorIsNil) 471 s.assertScopeChange(c, w0, nil, []string{"riak/1"}) 472 s.assertNoScopeChange(c, w0) 473 assertNotInScope(c, pr.ru1) 474 475 // ru1 leaves again; check no problems and no changes. 476 err = pr.ru1.LeaveScope() 477 c.Assert(err, jc.ErrorIsNil) 478 s.assertNoScopeChange(c, w0) 479 assertNotInScope(c, pr.ru1) 480 } 481 482 func (s *RelationUnitSuite) TestProReqWatchScope(c *gc.C) { 483 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal) 484 485 // Test empty initial events for all RUs. 486 ws := prr.watches() 487 for _, w := range ws { 488 defer testing.AssertStop(c, w) 489 } 490 for _, w := range ws { 491 s.assertScopeChange(c, w, nil, nil) 492 } 493 s.assertNoScopeChange(c, ws...) 494 495 // pru0 enters; check detected only by req RUs. 496 assertNotInScope(c, prr.pru0) 497 err := prr.pru0.EnterScope(nil) 498 c.Assert(err, jc.ErrorIsNil) 499 rws := func() []*state.RelationScopeWatcher { 500 return []*state.RelationScopeWatcher{ws[2], ws[3]} 501 } 502 for _, w := range rws() { 503 s.assertScopeChange(c, w, []string{"mysql/0"}, nil) 504 } 505 s.assertNoScopeChange(c, ws...) 506 assertJoined(c, prr.pru0) 507 508 // req0 enters; check detected only by pro RUs. 509 assertNotInScope(c, prr.rru0) 510 err = prr.rru0.EnterScope(nil) 511 c.Assert(err, jc.ErrorIsNil) 512 pws := func() []*state.RelationScopeWatcher { 513 return []*state.RelationScopeWatcher{ws[0], ws[1]} 514 } 515 for _, w := range pws() { 516 s.assertScopeChange(c, w, []string{"wordpress/0"}, nil) 517 } 518 s.assertNoScopeChange(c, ws...) 519 assertJoined(c, prr.rru0) 520 521 // Stop watches; remaining RUs enter. 522 for _, w := range ws { 523 testing.AssertStop(c, w) 524 } 525 assertNotInScope(c, prr.pru1) 526 err = prr.pru1.EnterScope(nil) 527 c.Assert(err, jc.ErrorIsNil) 528 assertJoined(c, prr.pru1) 529 assertNotInScope(c, prr.rru1) 530 err = prr.rru1.EnterScope(nil) 531 c.Assert(err, jc.ErrorIsNil) 532 assertJoined(c, prr.rru0) 533 534 // Start new watches, check initial events. 535 ws = prr.watches() 536 for _, w := range ws { 537 defer testing.AssertStop(c, w) 538 } 539 for _, w := range pws() { 540 s.assertScopeChange(c, w, []string{"wordpress/0", "wordpress/1"}, nil) 541 } 542 for _, w := range rws() { 543 s.assertScopeChange(c, w, []string{"mysql/0", "mysql/1"}, nil) 544 } 545 s.assertNoScopeChange(c, ws...) 546 547 // pru0 leaves; check detected only by req RUs. 548 assertJoined(c, prr.pru0) 549 err = prr.pru0.LeaveScope() 550 c.Assert(err, jc.ErrorIsNil) 551 for _, w := range rws() { 552 s.assertScopeChange(c, w, nil, []string{"mysql/0"}) 553 } 554 s.assertNoScopeChange(c, ws...) 555 assertNotInScope(c, prr.pru0) 556 557 // rru0 leaves; check detected only by pro RUs. 558 assertJoined(c, prr.rru0) 559 err = prr.rru0.LeaveScope() 560 c.Assert(err, jc.ErrorIsNil) 561 for _, w := range pws() { 562 s.assertScopeChange(c, w, nil, []string{"wordpress/0"}) 563 } 564 s.assertNoScopeChange(c, ws...) 565 assertNotInScope(c, prr.rru0) 566 } 567 568 func (s *RelationUnitSuite) TestContainerWatchScope(c *gc.C) { 569 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeContainer) 570 571 // Test empty initial events for all RUs. 572 ws := prr.watches() 573 for _, w := range ws { 574 defer testing.AssertStop(c, w) 575 } 576 for _, w := range ws { 577 s.assertScopeChange(c, w, nil, nil) 578 } 579 s.assertNoScopeChange(c, ws...) 580 581 // pru0 enters; check detected only by same-container req. 582 assertNotInScope(c, prr.pru0) 583 err := prr.pru0.EnterScope(nil) 584 c.Assert(err, jc.ErrorIsNil) 585 s.assertScopeChange(c, ws[2], []string{"mysql/0"}, nil) 586 s.assertNoScopeChange(c, ws...) 587 assertJoined(c, prr.pru0) 588 589 // req1 enters; check detected only by same-container pro. 590 assertNotInScope(c, prr.rru1) 591 err = prr.rru1.EnterScope(nil) 592 c.Assert(err, jc.ErrorIsNil) 593 s.assertScopeChange(c, ws[1], []string{"logging/1"}, nil) 594 s.assertNoScopeChange(c, ws...) 595 assertJoined(c, prr.rru1) 596 597 // Stop watches; remaining RUs enter scope. 598 for _, w := range ws { 599 testing.AssertStop(c, w) 600 } 601 assertNotInScope(c, prr.pru1) 602 err = prr.pru1.EnterScope(nil) 603 c.Assert(err, jc.ErrorIsNil) 604 assertNotInScope(c, prr.rru0) 605 err = prr.rru0.EnterScope(nil) 606 c.Assert(err, jc.ErrorIsNil) 607 608 // Start new watches, check initial events. 609 ws = prr.watches() 610 for _, w := range ws { 611 defer testing.AssertStop(c, w) 612 } 613 s.assertScopeChange(c, ws[0], []string{"logging/0"}, nil) 614 s.assertScopeChange(c, ws[1], []string{"logging/1"}, nil) 615 s.assertScopeChange(c, ws[2], []string{"mysql/0"}, nil) 616 s.assertScopeChange(c, ws[3], []string{"mysql/1"}, nil) 617 s.assertNoScopeChange(c, ws...) 618 assertJoined(c, prr.pru1) 619 assertJoined(c, prr.rru0) 620 621 // pru0 leaves; check detected only by same-container req. 622 assertJoined(c, prr.pru0) 623 err = prr.pru0.LeaveScope() 624 c.Assert(err, jc.ErrorIsNil) 625 s.assertScopeChange(c, ws[2], nil, []string{"mysql/0"}) 626 s.assertNoScopeChange(c, ws...) 627 assertNotInScope(c, prr.pru0) 628 629 // rru0 leaves; check detected only by same-container pro. 630 assertJoined(c, prr.rru0) 631 err = prr.rru0.LeaveScope() 632 c.Assert(err, jc.ErrorIsNil) 633 s.assertScopeChange(c, ws[0], nil, []string{"logging/0"}) 634 s.assertNoScopeChange(c, ws...) 635 assertNotInScope(c, prr.rru0) 636 } 637 638 func (s *RelationUnitSuite) TestCoalesceWatchScope(c *gc.C) { 639 pr := NewPeerRelation(c, s.State) 640 641 // Test empty initial event. 642 w0 := pr.ru0.WatchScope() 643 defer testing.AssertStop(c, w0) 644 s.assertScopeChange(c, w0, nil, nil) 645 s.assertNoScopeChange(c, w0) 646 647 // ru1 and ru2 enter; check changes observed together. 648 err := pr.ru1.EnterScope(nil) 649 c.Assert(err, jc.ErrorIsNil) 650 err = pr.ru2.EnterScope(nil) 651 c.Assert(err, jc.ErrorIsNil) 652 653 s.assertScopeChange(c, w0, []string{"riak/1", "riak/2"}, nil) 654 s.assertNoScopeChange(c, w0) 655 656 // ru1 leaves and re-enters; check no change observed. 657 err = pr.ru1.LeaveScope() 658 c.Assert(err, jc.ErrorIsNil) 659 err = pr.ru1.EnterScope(nil) 660 c.Assert(err, jc.ErrorIsNil) 661 s.assertNoScopeChange(c, w0) 662 663 // ru1 and ru2 leave; check changes observed together. 664 err = pr.ru1.LeaveScope() 665 c.Assert(err, jc.ErrorIsNil) 666 err = pr.ru2.LeaveScope() 667 c.Assert(err, jc.ErrorIsNil) 668 s.assertScopeChange(c, w0, nil, []string{"riak/1", "riak/2"}) 669 s.assertNoScopeChange(c, w0) 670 } 671 672 func (s *RelationUnitSuite) TestPrepareLeaveScope(c *gc.C) { 673 prr := NewProReqRelation(c, &s.ConnSuite, charm.ScopeGlobal) 674 675 // Test empty initial event. 676 w0 := prr.pru0.WatchScope() 677 defer testing.AssertStop(c, w0) 678 s.assertScopeChange(c, w0, nil, nil) 679 s.assertNoScopeChange(c, w0) 680 681 // rru0 and rru1 enter; check changes. 682 err := prr.rru0.EnterScope(nil) 683 c.Assert(err, jc.ErrorIsNil) 684 err = prr.rru1.EnterScope(nil) 685 c.Assert(err, jc.ErrorIsNil) 686 s.assertScopeChange(c, w0, []string{"wordpress/0", "wordpress/1"}, nil) 687 s.assertNoScopeChange(c, w0) 688 689 // rru0 notifies that it will leave soon; it's reported as departed by the 690 // watcher, but InScope remains accurate. 691 err = prr.rru0.PrepareLeaveScope() 692 c.Assert(err, jc.ErrorIsNil) 693 s.assertScopeChange(c, w0, nil, []string{"wordpress/0"}) 694 s.assertNoScopeChange(c, w0) 695 assertInScope(c, prr.rru0) 696 assertNotJoined(c, prr.rru0) 697 698 // rru1 leaves, and the relation is destroyed; it's not removed, because 699 // rru0 keeps it alive until it really leaves scope. 700 err = prr.rru1.LeaveScope() 701 c.Assert(err, jc.ErrorIsNil) 702 s.assertScopeChange(c, w0, nil, []string{"wordpress/1"}) 703 s.assertNoScopeChange(c, w0) 704 err = prr.rel.Destroy() 705 c.Assert(err, jc.ErrorIsNil) 706 err = prr.rel.Refresh() 707 c.Assert(err, jc.ErrorIsNil) 708 709 // rru0 really leaves; the relation is cleaned up. 710 err = prr.rru0.LeaveScope() 711 c.Assert(err, jc.ErrorIsNil) 712 err = prr.rel.Destroy() 713 c.Assert(err, jc.ErrorIsNil) 714 s.assertNoScopeChange(c, w0) 715 err = prr.rel.Refresh() 716 c.Assert(err, jc.Satisfies, errors.IsNotFound) 717 } 718 719 func (s *RelationUnitSuite) assertScopeChange(c *gc.C, w *state.RelationScopeWatcher, entered, left []string) { 720 s.State.StartSync() 721 select { 722 case ch, ok := <-w.Changes(): 723 c.Assert(ok, jc.IsTrue) 724 sort.Strings(entered) 725 sort.Strings(ch.Entered) 726 c.Assert(ch.Entered, gc.DeepEquals, entered) 727 sort.Strings(left) 728 sort.Strings(ch.Left) 729 c.Assert(ch.Left, gc.DeepEquals, left) 730 case <-time.After(coretesting.LongWait): 731 c.Fatalf("no change") 732 } 733 } 734 735 func (s *RelationUnitSuite) assertNoScopeChange(c *gc.C, ws ...*state.RelationScopeWatcher) { 736 s.State.StartSync() 737 for _, w := range ws { 738 select { 739 case ch, ok := <-w.Changes(): 740 c.Fatalf("got unwanted change: %#v, %t", ch, ok) 741 case <-time.After(coretesting.ShortWait): 742 } 743 } 744 } 745 746 type PeerRelation struct { 747 rel *state.Relation 748 svc *state.Application 749 u0, u1, u2, u3 *state.Unit 750 ru0, ru1, ru2, ru3 *state.RelationUnit 751 } 752 753 func NewPeerRelation(c *gc.C, st *state.State) *PeerRelation { 754 svc := state.AddTestingService(c, st, "riak", state.AddTestingCharm(c, st, "riak")) 755 ep, err := svc.Endpoint("ring") 756 c.Assert(err, jc.ErrorIsNil) 757 rel, err := st.EndpointsRelation(ep) 758 c.Assert(err, jc.ErrorIsNil) 759 pr := &PeerRelation{rel: rel, svc: svc} 760 pr.u0, pr.ru0 = addRU(c, svc, rel, nil) 761 pr.u1, pr.ru1 = addRU(c, svc, rel, nil) 762 pr.u2, pr.ru2 = addRU(c, svc, rel, nil) 763 pr.u3, pr.ru3 = addRU(c, svc, rel, nil) 764 return pr 765 } 766 767 type ProReqRelation struct { 768 rel *state.Relation 769 psvc, rsvc *state.Application 770 pu0, pu1, ru0, ru1 *state.Unit 771 pru0, pru1, rru0, rru1 *state.RelationUnit 772 } 773 774 func NewProReqRelation(c *gc.C, s *ConnSuite, scope charm.RelationScope) *ProReqRelation { 775 psvc := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 776 var rsvc *state.Application 777 if scope == charm.ScopeGlobal { 778 rsvc = s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 779 } else { 780 rsvc = s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 781 } 782 eps, err := s.State.InferEndpoints("mysql", rsvc.Name()) 783 c.Assert(err, jc.ErrorIsNil) 784 rel, err := s.State.AddRelation(eps...) 785 c.Assert(err, jc.ErrorIsNil) 786 prr := &ProReqRelation{rel: rel, psvc: psvc, rsvc: rsvc} 787 prr.pu0, prr.pru0 = addRU(c, psvc, rel, nil) 788 prr.pu1, prr.pru1 = addRU(c, psvc, rel, nil) 789 if scope == charm.ScopeGlobal { 790 prr.ru0, prr.rru0 = addRU(c, rsvc, rel, nil) 791 prr.ru1, prr.rru1 = addRU(c, rsvc, rel, nil) 792 } else { 793 prr.ru0, prr.rru0 = addRU(c, rsvc, rel, prr.pu0) 794 prr.ru1, prr.rru1 = addRU(c, rsvc, rel, prr.pu1) 795 } 796 return prr 797 } 798 799 func (prr *ProReqRelation) watches() []*state.RelationScopeWatcher { 800 return []*state.RelationScopeWatcher{ 801 prr.pru0.WatchScope(), prr.pru1.WatchScope(), 802 prr.rru0.WatchScope(), prr.rru1.WatchScope(), 803 } 804 } 805 806 func addRU(c *gc.C, svc *state.Application, rel *state.Relation, principal *state.Unit) (*state.Unit, *state.RelationUnit) { 807 // Given the service svc in the relation rel, add a unit of svc and create 808 // a RelationUnit with rel. If principal is supplied, svc is assumed to be 809 // subordinate and the unit will be created by temporarily entering the 810 // relation's scope as the principal. 811 var u *state.Unit 812 if principal == nil { 813 unit, err := svc.AddUnit() 814 c.Assert(err, jc.ErrorIsNil) 815 u = unit 816 } else { 817 origUnits, err := svc.AllUnits() 818 c.Assert(err, jc.ErrorIsNil) 819 pru, err := rel.Unit(principal) 820 c.Assert(err, jc.ErrorIsNil) 821 err = pru.EnterScope(nil) // to create the subordinate 822 c.Assert(err, jc.ErrorIsNil) 823 err = pru.LeaveScope() // to reset to initial expected state 824 c.Assert(err, jc.ErrorIsNil) 825 newUnits, err := svc.AllUnits() 826 c.Assert(err, jc.ErrorIsNil) 827 for _, unit := range newUnits { 828 found := false 829 for _, old := range origUnits { 830 if unit.Name() == old.Name() { 831 found = true 832 break 833 } 834 } 835 if !found { 836 u = unit 837 break 838 } 839 } 840 c.Assert(u, gc.NotNil) 841 } 842 preventUnitDestroyRemove(c, u) 843 ru, err := rel.Unit(u) 844 c.Assert(err, jc.ErrorIsNil) 845 return u, ru 846 } 847 848 type WatchScopeSuite struct { 849 ConnSuite 850 } 851 852 var _ = gc.Suite(&WatchScopeSuite{}) 853 854 func (s *WatchScopeSuite) TestPeer(c *gc.C) { 855 // Create a service and get a peer relation. 856 riak := s.AddTestingService(c, "riak", s.AddTestingCharm(c, "riak")) 857 riakEP, err := riak.Endpoint("ring") 858 c.Assert(err, jc.ErrorIsNil) 859 rels, err := riak.Relations() 860 c.Assert(err, jc.ErrorIsNil) 861 c.Assert(rels, gc.HasLen, 1) 862 rel := rels[0] 863 864 // Add some units to the service and set their private addresses; get 865 // the relevant RelationUnits. 866 // (Private addresses should be set by their unit agents on 867 // startup; this test does not include that, but Join expects 868 // the information to be available, and uses it to populate the 869 // relation settings node.) 870 addUnit := func(i int) *state.RelationUnit { 871 unit, err := riak.AddUnit() 872 c.Assert(err, jc.ErrorIsNil) 873 err = unit.AssignToNewMachine() 874 c.Assert(err, jc.ErrorIsNil) 875 mId, err := unit.AssignedMachineId() 876 c.Assert(err, jc.ErrorIsNil) 877 machine, err := s.State.Machine(mId) 878 c.Assert(err, jc.ErrorIsNil) 879 privateAddr := network.NewScopedAddress( 880 fmt.Sprintf("riak%d.example.com", i), 881 network.ScopeCloudLocal, 882 ) 883 machine.SetProviderAddresses(privateAddr) 884 ru, err := rel.Unit(unit) 885 c.Assert(err, jc.ErrorIsNil) 886 c.Assert(ru.Endpoint(), gc.Equals, riakEP) 887 return ru 888 } 889 ru0 := addUnit(0) 890 ru1 := addUnit(1) 891 ru2 := addUnit(2) 892 893 // ---------- Single unit ---------- 894 895 // Start watching the relation from the perspective of the first unit. 896 w0 := ru0.Watch() 897 defer testing.AssertStop(c, w0) 898 w0c := testing.NewRelationUnitsWatcherC(c, s.State, w0) 899 w0c.AssertChange(nil, nil) 900 w0c.AssertNoChange() 901 902 // Join the first unit to the relation, and change the settings, and 903 // check that nothing apparently happens. 904 err = ru0.EnterScope(nil) 905 c.Assert(err, jc.ErrorIsNil) 906 changeSettings(c, ru0) 907 w0c.AssertNoChange() 908 909 // ---------- Two units ---------- 910 911 // Now join another unit to the relation... 912 err = ru1.EnterScope(nil) 913 c.Assert(err, jc.ErrorIsNil) 914 915 // ...and check that the first relation unit sees the change. 916 expectChanged := []string{"riak/1"} 917 w0c.AssertChange(expectChanged, nil) 918 w0c.AssertNoChange() 919 920 // Join again, check it's a no-op. 921 err = ru1.EnterScope(nil) 922 c.Assert(err, jc.ErrorIsNil) 923 w0c.AssertNoChange() 924 925 // Start watching the relation from the perspective of the second unit, 926 // and check that it sees the right state. 927 w1 := ru1.Watch() 928 defer testing.AssertStop(c, w1) 929 w1c := testing.NewRelationUnitsWatcherC(c, s.State, w1) 930 expectChanged = []string{"riak/0"} 931 w1c.AssertChange(expectChanged, nil) 932 w1c.AssertNoChange() 933 934 // ---------- Three units ---------- 935 936 // Whoa, it works. Ok, check the third unit's opinion of the state. 937 w2 := ru2.Watch() 938 defer testing.AssertStop(c, w2) 939 w2c := testing.NewRelationUnitsWatcherC(c, s.State, w2) 940 expectChanged = []string{"riak/0", "riak/1"} 941 w2c.AssertChange(expectChanged, nil) 942 w2c.AssertNoChange() 943 944 // Join the third unit, and check the first and second units see it. 945 err = ru2.EnterScope(nil) 946 c.Assert(err, jc.ErrorIsNil) 947 expectChanged = []string{"riak/2"} 948 w0c.AssertChange(expectChanged, nil) 949 w0c.AssertNoChange() 950 w1c.AssertChange(expectChanged, nil) 951 w1c.AssertNoChange() 952 953 // Change the second unit's settings, and check that only 954 // the first and third see changes. 955 changeSettings(c, ru1) 956 w1c.AssertNoChange() 957 expectChanged = []string{"riak/1"} 958 w0c.AssertChange(expectChanged, nil) 959 w0c.AssertNoChange() 960 w2c.AssertChange(expectChanged, nil) 961 w2c.AssertNoChange() 962 963 // ---------- Two units again ---------- 964 965 // Depart the second unit, and check that the first and third detect it. 966 err = ru1.LeaveScope() 967 c.Assert(err, jc.ErrorIsNil) 968 expectDeparted := []string{"riak/1"} 969 w0c.AssertChange(nil, expectDeparted) 970 w0c.AssertNoChange() 971 w2c.AssertChange(nil, expectDeparted) 972 w2c.AssertNoChange() 973 974 // Change its settings, and check the others don't observe anything. 975 changeSettings(c, ru1) 976 w0c.AssertNoChange() 977 w2c.AssertNoChange() 978 979 // Check no spurious events showed up on the second unit's watch, and check 980 // it closes cleanly. 981 w1c.AssertNoChange() 982 testing.AssertStop(c, w1) 983 984 // OK, we're done here. Cleanup, and error detection during same, 985 // will be handled by the deferred kill/stop calls. Phew. 986 } 987 988 func (s *WatchScopeSuite) TestProviderRequirerGlobal(c *gc.C) { 989 // Create a pair of services and a relation between them. 990 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 991 mysqlEP, err := mysql.Endpoint("server") 992 c.Assert(err, jc.ErrorIsNil) 993 wordpress := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 994 wordpressEP, err := wordpress.Endpoint("db") 995 c.Assert(err, jc.ErrorIsNil) 996 rel, err := s.State.AddRelation(mysqlEP, wordpressEP) 997 c.Assert(err, jc.ErrorIsNil) 998 999 // Add some units to the services and set their private addresses. 1000 addUnit := func(srv *state.Application, sub string, ep state.Endpoint) *state.RelationUnit { 1001 unit, err := srv.AddUnit() 1002 c.Assert(err, jc.ErrorIsNil) 1003 ru, err := rel.Unit(unit) 1004 c.Assert(err, jc.ErrorIsNil) 1005 c.Assert(ru.Endpoint(), gc.Equals, ep) 1006 return ru 1007 } 1008 msru0 := addUnit(mysql, "ms0", mysqlEP) 1009 msru1 := addUnit(mysql, "ms1", mysqlEP) 1010 wpru0 := addUnit(wordpress, "wp0", wordpressEP) 1011 wpru1 := addUnit(wordpress, "wp1", wordpressEP) 1012 1013 // ---------- Single role active ---------- 1014 1015 // Watch the relation from the perspective of the first provider unit and 1016 // check initial event. 1017 msw0 := msru0.Watch() 1018 defer testing.AssertStop(c, msw0) 1019 msw0c := testing.NewRelationUnitsWatcherC(c, s.State, msw0) 1020 msw0c.AssertChange(nil, nil) 1021 msw0c.AssertNoChange() 1022 1023 // Join the unit to the relation, change its settings, and check that 1024 // nothing apparently happens. 1025 err = msru0.EnterScope(nil) 1026 c.Assert(err, jc.ErrorIsNil) 1027 changeSettings(c, msru0) 1028 msw0c.AssertNoChange() 1029 1030 // Join the second provider unit, start its watch, and check what it thinks the 1031 // state of the relation is. 1032 err = msru1.EnterScope(nil) 1033 c.Assert(err, jc.ErrorIsNil) 1034 msw1 := msru1.Watch() 1035 defer testing.AssertStop(c, msw1) 1036 msw1c := testing.NewRelationUnitsWatcherC(c, s.State, msw1) 1037 msw1c.AssertChange(nil, nil) 1038 msw1c.AssertNoChange() 1039 1040 // Change the unit's settings, and check that neither provider unit 1041 // observes any change. 1042 changeSettings(c, msru1) 1043 msw1c.AssertNoChange() 1044 msw0c.AssertNoChange() 1045 1046 // ---------- Two roles active ---------- 1047 1048 // Start watches from both requirer units' perspectives, and check that 1049 // they see the provider units. 1050 expectChanged := []string{"mysql/0", "mysql/1"} 1051 wpw0 := wpru0.Watch() 1052 defer testing.AssertStop(c, wpw0) 1053 wpw0c := testing.NewRelationUnitsWatcherC(c, s.State, wpw0) 1054 wpw0c.AssertChange(expectChanged, nil) 1055 wpw0c.AssertNoChange() 1056 wpw1 := wpru1.Watch() 1057 defer testing.AssertStop(c, wpw1) 1058 wpw1c := testing.NewRelationUnitsWatcherC(c, s.State, wpw1) 1059 wpw1c.AssertChange(expectChanged, nil) 1060 wpw1c.AssertNoChange() 1061 1062 // Join the first requirer unit, and check the provider units see it. 1063 err = wpru0.EnterScope(nil) 1064 c.Assert(err, jc.ErrorIsNil) 1065 expectChanged = []string{"wordpress/0"} 1066 msw0c.AssertChange(expectChanged, nil) 1067 msw0c.AssertNoChange() 1068 msw1c.AssertChange(expectChanged, nil) 1069 msw1c.AssertNoChange() 1070 1071 // Join again, check no-op. 1072 err = wpru0.EnterScope(nil) 1073 c.Assert(err, jc.ErrorIsNil) 1074 msw0c.AssertNoChange() 1075 msw1c.AssertNoChange() 1076 1077 // Join the second requirer, and check the provider units see the change. 1078 err = wpru1.EnterScope(nil) 1079 c.Assert(err, jc.ErrorIsNil) 1080 expectChanged = []string{"wordpress/1"} 1081 msw0c.AssertChange(expectChanged, nil) 1082 msw0c.AssertNoChange() 1083 msw1c.AssertChange(expectChanged, nil) 1084 msw1c.AssertNoChange() 1085 1086 // Verify that neither requirer has observed any change to the relation. 1087 wpw0c.AssertNoChange() 1088 wpw1c.AssertNoChange() 1089 1090 // Change settings for the first requirer, check providers see it... 1091 changeSettings(c, wpru0) 1092 expectChanged = []string{"wordpress/0"} 1093 msw0c.AssertChange(expectChanged, nil) 1094 msw0c.AssertNoChange() 1095 msw1c.AssertChange(expectChanged, nil) 1096 msw1c.AssertNoChange() 1097 1098 // ...and requirers don't. 1099 wpw0c.AssertNoChange() 1100 wpw1c.AssertNoChange() 1101 1102 // Depart the second requirer and check the providers see it... 1103 err = wpru1.LeaveScope() 1104 c.Assert(err, jc.ErrorIsNil) 1105 expectDeparted := []string{"wordpress/1"} 1106 msw0c.AssertChange(nil, expectDeparted) 1107 msw0c.AssertNoChange() 1108 msw1c.AssertChange(nil, expectDeparted) 1109 msw1c.AssertNoChange() 1110 1111 // ...and the requirers don't. 1112 wpw0c.AssertNoChange() 1113 wpw1c.AssertNoChange() 1114 1115 // Cleanup handled by defers as before. 1116 } 1117 1118 func (s *WatchScopeSuite) TestProviderRequirerContainer(c *gc.C) { 1119 // Create a pair of services and a relation between them. 1120 mysql := s.AddTestingService(c, "mysql", s.AddTestingCharm(c, "mysql")) 1121 mysqlEP, err := mysql.Endpoint("juju-info") 1122 c.Assert(err, jc.ErrorIsNil) 1123 logging := s.AddTestingService(c, "logging", s.AddTestingCharm(c, "logging")) 1124 loggingEP, err := logging.Endpoint("info") 1125 c.Assert(err, jc.ErrorIsNil) 1126 rel, err := s.State.AddRelation(mysqlEP, loggingEP) 1127 c.Assert(err, jc.ErrorIsNil) 1128 1129 // Change mysqlEP to match the endpoint that will actually be used by the relation. 1130 mysqlEP.Scope = charm.ScopeContainer 1131 1132 // Add some units to the services and set their private addresses. 1133 addUnits := func(i int) (*state.RelationUnit, *state.RelationUnit) { 1134 msu, err := mysql.AddUnit() 1135 c.Assert(err, jc.ErrorIsNil) 1136 msru, err := rel.Unit(msu) 1137 c.Assert(err, jc.ErrorIsNil) 1138 c.Assert(msru.Endpoint(), gc.Equals, mysqlEP) 1139 err = msru.EnterScope(nil) 1140 c.Assert(err, jc.ErrorIsNil) 1141 err = msru.LeaveScope() 1142 c.Assert(err, jc.ErrorIsNil) 1143 lgu, err := s.State.Unit("logging/" + strconv.Itoa(i)) 1144 c.Assert(err, jc.ErrorIsNil) 1145 lgru, err := rel.Unit(lgu) 1146 c.Assert(err, jc.ErrorIsNil) 1147 c.Assert(lgru.Endpoint(), gc.Equals, loggingEP) 1148 return msru, lgru 1149 } 1150 msru0, lgru0 := addUnits(0) 1151 msru1, lgru1 := addUnits(1) 1152 1153 // ---------- Single role active ---------- 1154 1155 // Start watching the relation from the perspective of the first unit, and 1156 // check the initial event. 1157 msw0 := msru0.Watch() 1158 defer testing.AssertStop(c, msw0) 1159 msw0c := testing.NewRelationUnitsWatcherC(c, s.State, msw0) 1160 msw0c.AssertChange(nil, nil) 1161 msw0c.AssertNoChange() 1162 1163 // Join the unit to the relation, change its settings, and check that 1164 // nothing apparently happens. 1165 err = msru0.EnterScope(nil) 1166 c.Assert(err, jc.ErrorIsNil) 1167 changeSettings(c, msru0) 1168 msw0c.AssertNoChange() 1169 1170 // Watch the relation from the perspective of the second provider, and 1171 // check initial event. 1172 msw1 := msru1.Watch() 1173 defer testing.AssertStop(c, msw1) 1174 msw1c := testing.NewRelationUnitsWatcherC(c, s.State, msw1) 1175 msw1c.AssertChange(nil, nil) 1176 msw1c.AssertNoChange() 1177 1178 // Join the second provider unit to the relation, and check that neither 1179 // watching unit observes any change. 1180 err = msru1.EnterScope(nil) 1181 c.Assert(err, jc.ErrorIsNil) 1182 msw1c.AssertNoChange() 1183 msw0c.AssertNoChange() 1184 1185 // Change the unit's settings, and check that nothing apparently happens. 1186 changeSettings(c, msru1) 1187 msw1c.AssertNoChange() 1188 msw0c.AssertNoChange() 1189 1190 // ---------- Two roles active ---------- 1191 1192 // Start a watch from the first requirer unit's perspective, and check it 1193 // only sees the first provider (with which it shares a container). 1194 lgw0 := lgru0.Watch() 1195 defer testing.AssertStop(c, lgw0) 1196 lgw0c := testing.NewRelationUnitsWatcherC(c, s.State, lgw0) 1197 expectChanged := []string{"mysql/0"} 1198 lgw0c.AssertChange(expectChanged, nil) 1199 lgw0c.AssertNoChange() 1200 1201 // Join the first requirer unit, and check that only the first provider 1202 // observes the change. 1203 err = lgru0.EnterScope(nil) 1204 c.Assert(err, jc.ErrorIsNil) 1205 expectChanged = []string{"logging/0"} 1206 msw0c.AssertChange(expectChanged, nil) 1207 msw0c.AssertNoChange() 1208 msw1c.AssertNoChange() 1209 lgw0c.AssertNoChange() 1210 1211 // Watch from the second requirer's perspective, and check it only sees the 1212 // second provider. 1213 lgw1 := lgru1.Watch() 1214 defer testing.AssertStop(c, lgw1) 1215 lgw1c := testing.NewRelationUnitsWatcherC(c, s.State, lgw1) 1216 expectChanged = []string{"mysql/1"} 1217 lgw1c.AssertChange(expectChanged, nil) 1218 lgw1c.AssertNoChange() 1219 1220 // Join the second requirer, and check that the first provider observes it... 1221 err = lgru1.EnterScope(nil) 1222 c.Assert(err, jc.ErrorIsNil) 1223 expectChanged = []string{"logging/1"} 1224 msw1c.AssertChange(expectChanged, nil) 1225 msw1c.AssertNoChange() 1226 1227 // ...and that nothing else sees anything. 1228 msw0c.AssertNoChange() 1229 lgw0c.AssertNoChange() 1230 lgw1c.AssertNoChange() 1231 1232 // Change the second provider's settings and check that the second 1233 // requirer notices... 1234 changeSettings(c, msru1) 1235 expectChanged = []string{"mysql/1"} 1236 lgw1c.AssertChange(expectChanged, nil) 1237 lgw1c.AssertNoChange() 1238 1239 // ...but that nothing else does. 1240 msw0c.AssertNoChange() 1241 msw1c.AssertNoChange() 1242 msw0c.AssertNoChange() 1243 1244 // Finally, depart the first provider, and check that only the first 1245 // requirer observes any change. 1246 err = msru0.LeaveScope() 1247 c.Assert(err, jc.ErrorIsNil) 1248 expectDeparted := []string{"mysql/0"} 1249 lgw0c.AssertChange(nil, expectDeparted) 1250 lgw0c.AssertNoChange() 1251 lgw1c.AssertNoChange() 1252 msw0c.AssertNoChange() 1253 msw1c.AssertNoChange() 1254 1255 // Again, I think we're done, and can be comfortable that the appropriate 1256 // connections are in place. 1257 } 1258 1259 func changeSettings(c *gc.C, ru *state.RelationUnit) { 1260 node, err := ru.Settings() 1261 c.Assert(err, jc.ErrorIsNil) 1262 value, _ := node.Get("value") 1263 v, _ := value.(int) 1264 node.Set("value", v+1) 1265 _, err = node.Write() 1266 c.Assert(err, jc.ErrorIsNil) 1267 }