github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/presence/presence_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package presence_test 5 6 import ( 7 "strconv" 8 stdtesting "testing" 9 "time" 10 11 "github.com/juju/errors" 12 gitjujutesting "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/juju/names.v2" 17 "gopkg.in/mgo.v2" 18 "gopkg.in/tomb.v1" 19 20 "github.com/juju/juju/state/presence" 21 "github.com/juju/juju/testing" 22 "github.com/juju/juju/worker" 23 ) 24 25 func TestPackage(t *stdtesting.T) { 26 testing.MgoTestPackage(t) 27 } 28 29 type PresenceSuite struct { 30 gitjujutesting.MgoSuite 31 testing.BaseSuite 32 presence *mgo.Collection 33 pings *mgo.Collection 34 modelTag names.ModelTag 35 } 36 37 var _ = gc.Suite(&PresenceSuite{}) 38 39 func (s *PresenceSuite) SetUpSuite(c *gc.C) { 40 s.BaseSuite.SetUpSuite(c) 41 s.MgoSuite.SetUpSuite(c) 42 uuid, err := utils.NewUUID() 43 c.Assert(err, jc.ErrorIsNil) 44 s.modelTag = names.NewModelTag(uuid.String()) 45 } 46 47 func (s *PresenceSuite) TearDownSuite(c *gc.C) { 48 s.MgoSuite.TearDownSuite(c) 49 s.BaseSuite.TearDownSuite(c) 50 } 51 52 func (s *PresenceSuite) SetUpTest(c *gc.C) { 53 s.BaseSuite.SetUpTest(c) 54 s.MgoSuite.SetUpTest(c) 55 56 db := s.MgoSuite.Session.DB("presence") 57 s.presence = db.C("presence") 58 s.pings = db.C("presence.pings") 59 60 presence.FakeTimeSlot(0) 61 } 62 63 func (s *PresenceSuite) TearDownTest(c *gc.C) { 64 s.MgoSuite.TearDownTest(c) 65 s.BaseSuite.TearDownTest(c) 66 67 presence.RealTimeSlot() 68 presence.RealPeriod() 69 } 70 71 func assertChange(c *gc.C, watch <-chan presence.Change, want presence.Change) { 72 select { 73 case got := <-watch: 74 if got != want { 75 c.Fatalf("watch reported %v, want %v", got, want) 76 } 77 case <-time.After(testing.LongWait): 78 c.Fatalf("watch reported nothing, want %v", want) 79 } 80 } 81 82 func assertNoChange(c *gc.C, watch <-chan presence.Change) { 83 select { 84 case got := <-watch: 85 c.Fatalf("watch reported %v, want nothing", got) 86 case <-time.After(testing.ShortWait): 87 } 88 } 89 90 func assertAlive(c *gc.C, w *presence.Watcher, key string, alive bool) { 91 alive, err := w.Alive("a") 92 c.Assert(err, jc.ErrorIsNil) 93 c.Assert(alive, gc.Equals, alive) 94 } 95 96 // assertStopped stops a worker and waits until it reports stopped. 97 // Use this method in favor of defer w.Stop() because you _must_ ensure 98 // that the worker has stopped, and thus is no longer using its mgo 99 // session before TearDownTest shuts down the connection. 100 func assertStopped(c *gc.C, w worker.Worker) { 101 c.Assert(worker.Stop(w), gc.IsNil) 102 } 103 104 func (s *PresenceSuite) TestErrAndDead(c *gc.C) { 105 w := presence.NewWatcher(s.presence, s.modelTag) 106 defer assertStopped(c, w) 107 108 c.Assert(errors.Cause(w.Err()), gc.Equals, tomb.ErrStillAlive) 109 select { 110 case <-w.Dead(): 111 c.Fatalf("Dead channel fired unexpectedly") 112 default: 113 } 114 c.Assert(w.Stop(), gc.IsNil) 115 c.Assert(w.Err(), gc.IsNil) 116 select { 117 case <-w.Dead(): 118 default: 119 c.Fatalf("Dead channel should have fired") 120 } 121 } 122 123 func (s *PresenceSuite) TestAliveError(c *gc.C) { 124 w := presence.NewWatcher(s.presence, s.modelTag) 125 c.Assert(w.Stop(), gc.IsNil) 126 127 alive, err := w.Alive("a") 128 c.Assert(err, gc.ErrorMatches, ".*: watcher is dying") 129 c.Assert(alive, jc.IsFalse) 130 w.Wait() 131 } 132 133 func (s *PresenceSuite) TestWorkflow(c *gc.C) { 134 w := presence.NewWatcher(s.presence, s.modelTag) 135 pa := presence.NewPinger(s.presence, s.modelTag, "a") 136 pb := presence.NewPinger(s.presence, s.modelTag, "b") 137 defer assertStopped(c, w) 138 defer assertStopped(c, pa) 139 defer assertStopped(c, pb) 140 141 assertAlive(c, w, "a", false) 142 assertAlive(c, w, "b", false) 143 144 // Buffer one entry to avoid blocking the watcher here. 145 cha := make(chan presence.Change, 1) 146 chb := make(chan presence.Change, 1) 147 w.Watch("a", cha) 148 w.Watch("b", chb) 149 150 // Initial events with current status. 151 assertChange(c, cha, presence.Change{"a", false}) 152 assertChange(c, chb, presence.Change{"b", false}) 153 154 w.StartSync() 155 assertNoChange(c, cha) 156 assertNoChange(c, chb) 157 158 c.Assert(pa.Start(), gc.IsNil) 159 160 w.StartSync() 161 assertChange(c, cha, presence.Change{"a", true}) 162 assertNoChange(c, cha) 163 assertNoChange(c, chb) 164 165 assertAlive(c, w, "a", true) 166 assertAlive(c, w, "b", false) 167 168 // Changes while the channel is out are not observed. 169 w.Unwatch("a", cha) 170 assertNoChange(c, cha) 171 pa.KillForTesting() 172 w.Sync() 173 pa = presence.NewPinger(s.presence, s.modelTag, "a") 174 pa.Start() 175 w.StartSync() 176 assertNoChange(c, cha) 177 178 // We can still query it manually, though. 179 assertAlive(c, w, "a", true) 180 assertAlive(c, w, "b", false) 181 182 // Initial positive event. No refresh needed. 183 w.Watch("a", cha) 184 assertChange(c, cha, presence.Change{"a", true}) 185 186 c.Assert(pb.Start(), gc.IsNil) 187 188 w.StartSync() 189 assertChange(c, chb, presence.Change{"b", true}) 190 assertNoChange(c, cha) 191 assertNoChange(c, chb) 192 193 c.Assert(pa.Stop(), gc.IsNil) 194 195 w.StartSync() 196 assertNoChange(c, cha) 197 assertNoChange(c, chb) 198 199 // pb is running, pa isn't. 200 c.Assert(pa.KillForTesting(), gc.IsNil) 201 c.Assert(pb.KillForTesting(), gc.IsNil) 202 203 w.StartSync() 204 assertChange(c, cha, presence.Change{"a", false}) 205 assertChange(c, chb, presence.Change{"b", false}) 206 207 assertStopped(c, w) 208 } 209 210 func (s *PresenceSuite) TestScale(c *gc.C) { 211 const N = 1000 212 var ps []*presence.Pinger 213 defer func() { 214 for _, p := range ps { 215 p.Stop() 216 } 217 }() 218 219 c.Logf("Starting %d pingers...", N) 220 for i := 0; i < N; i++ { 221 p := presence.NewPinger(s.presence, s.modelTag, strconv.Itoa(i)) 222 c.Assert(p.Start(), gc.IsNil) 223 ps = append(ps, p) 224 } 225 226 c.Logf("Killing odd ones...") 227 for i := 1; i < N; i += 2 { 228 c.Assert(ps[i].KillForTesting(), gc.IsNil) 229 } 230 231 c.Logf("Checking who's still alive...") 232 w := presence.NewWatcher(s.presence, s.modelTag) 233 defer assertStopped(c, w) 234 w.Sync() 235 ch := make(chan presence.Change) 236 for i := 0; i < N; i++ { 237 k := strconv.Itoa(i) 238 w.Watch(k, ch) 239 if i%2 == 0 { 240 assertChange(c, ch, presence.Change{k, true}) 241 } else { 242 assertChange(c, ch, presence.Change{k, false}) 243 } 244 } 245 } 246 247 func (s *PresenceSuite) TestExpiry(c *gc.C) { 248 w := presence.NewWatcher(s.presence, s.modelTag) 249 p := presence.NewPinger(s.presence, s.modelTag, "a") 250 defer assertStopped(c, w) 251 defer assertStopped(c, p) 252 253 ch := make(chan presence.Change) 254 w.Watch("a", ch) 255 assertChange(c, ch, presence.Change{"a", false}) 256 257 c.Assert(p.Start(), gc.IsNil) 258 w.StartSync() 259 assertChange(c, ch, presence.Change{"a", true}) 260 261 // Still alive in previous slot. 262 presence.FakeTimeSlot(1) 263 w.StartSync() 264 assertNoChange(c, ch) 265 266 // Two last slots are empty. 267 presence.FakeTimeSlot(2) 268 w.StartSync() 269 assertChange(c, ch, presence.Change{"a", false}) 270 271 // Already dead so killing isn't noticed. 272 p.KillForTesting() 273 w.StartSync() 274 assertNoChange(c, ch) 275 } 276 277 func (s *PresenceSuite) TestWatchPeriod(c *gc.C) { 278 presence.FakePeriod(1) 279 presence.RealTimeSlot() 280 281 w := presence.NewWatcher(s.presence, s.modelTag) 282 p := presence.NewPinger(s.presence, s.modelTag, "a") 283 defer assertStopped(c, w) 284 defer assertStopped(c, p) 285 286 ch := make(chan presence.Change) 287 w.Watch("a", ch) 288 assertChange(c, ch, presence.Change{"a", false}) 289 290 // A single ping. 291 c.Assert(p.Start(), gc.IsNil) 292 c.Assert(p.Stop(), gc.IsNil) 293 294 // Wait for next periodic refresh. 295 time.Sleep(1 * time.Second) 296 assertChange(c, ch, presence.Change{"a", true}) 297 } 298 299 func (s *PresenceSuite) TestWatchUnwatchOnQueue(c *gc.C) { 300 w := presence.NewWatcher(s.presence, s.modelTag) 301 defer assertStopped(c, w) 302 ch := make(chan presence.Change, 100) 303 for i := 0; i < 100; i++ { 304 key := strconv.Itoa(i) 305 c.Logf("Adding %q", key) 306 w.Watch(key, ch) 307 } 308 for i := 1; i < 100; i += 2 { 309 key := strconv.Itoa(i) 310 c.Logf("Removing %q", key) 311 w.Unwatch(key, ch) 312 } 313 alive := make(map[string]bool) 314 for i := 0; i < 50; i++ { 315 change := <-ch 316 c.Logf("Got change for %q: %v", change.Key, change.Alive) 317 alive[change.Key] = change.Alive 318 } 319 for i := 0; i < 100; i += 2 { 320 key := strconv.Itoa(i) 321 c.Logf("Checking %q...", key) 322 c.Assert(alive[key], jc.IsFalse) 323 } 324 } 325 326 func (s *PresenceSuite) TestRestartWithoutGaps(c *gc.C) { 327 p := presence.NewPinger(s.presence, s.modelTag, "a") 328 c.Assert(p.Start(), gc.IsNil) 329 defer assertStopped(c, p) 330 331 done := make(chan bool) 332 go func() { 333 stop := false 334 for !stop { 335 if !c.Check(p.Stop(), gc.IsNil) { 336 break 337 } 338 if !c.Check(p.Start(), gc.IsNil) { 339 break 340 } 341 select { 342 case stop = <-done: 343 default: 344 } 345 } 346 }() 347 go func() { 348 stop := false 349 for !stop { 350 w := presence.NewWatcher(s.presence, s.modelTag) 351 w.Sync() 352 alive, err := w.Alive("a") 353 assertStopped(c, w) 354 if !c.Check(err, jc.ErrorIsNil) || !c.Check(alive, jc.IsTrue) { 355 break 356 } 357 select { 358 case stop = <-done: 359 default: 360 } 361 } 362 }() 363 // TODO(jam): This forceful delay of 500ms sounds like a bad test, 364 // since we always sleep for the full timeout 365 time.Sleep(500 * time.Millisecond) 366 done <- true 367 done <- true 368 } 369 370 func (s *PresenceSuite) TestPingerPeriodAndResilience(c *gc.C) { 371 // This test verifies both the periodic pinging, 372 // and also a great property of the design: deaths 373 // also expire, which means erroneous scenarios are 374 // automatically recovered from. 375 376 const period = 1 377 presence.FakePeriod(period) 378 presence.RealTimeSlot() 379 380 w := presence.NewWatcher(s.presence, s.modelTag) 381 p1 := presence.NewPinger(s.presence, s.modelTag, "a") 382 p2 := presence.NewPinger(s.presence, s.modelTag, "a") 383 defer assertStopped(c, w) 384 defer assertStopped(c, p1) 385 defer assertStopped(c, p2) 386 387 // Start p1 and let it go on. 388 c.Assert(p1.Start(), gc.IsNil) 389 390 w.Sync() 391 assertAlive(c, w, "a", true) 392 393 // Start and kill p2, which will temporarily 394 // invalidate p1 and set the key as dead. 395 c.Assert(p2.Start(), gc.IsNil) 396 c.Assert(p2.KillForTesting(), gc.IsNil) 397 398 w.Sync() 399 assertAlive(c, w, "a", false) 400 401 // Wait for two periods, and check again. Since 402 // p1 is still alive, p2's death will expire and 403 // the key will come back. 404 time.Sleep(period * 2 * time.Second) 405 406 w.Sync() 407 assertAlive(c, w, "a", true) 408 } 409 410 func (s *PresenceSuite) TestStartSync(c *gc.C) { 411 w := presence.NewWatcher(s.presence, s.modelTag) 412 p := presence.NewPinger(s.presence, s.modelTag, "a") 413 defer assertStopped(c, w) 414 defer assertStopped(c, p) 415 416 ch := make(chan presence.Change) 417 w.Watch("a", ch) 418 assertChange(c, ch, presence.Change{"a", false}) 419 420 c.Assert(p.Start(), gc.IsNil) 421 422 done := make(chan bool) 423 go func() { 424 w.StartSync() 425 w.StartSync() 426 w.StartSync() 427 done <- true 428 }() 429 430 select { 431 case <-done: 432 case <-time.After(testing.LongWait): 433 c.Fatalf("StartSync failed to return") 434 } 435 436 assertChange(c, ch, presence.Change{"a", true}) 437 } 438 439 func (s *PresenceSuite) TestSync(c *gc.C) { 440 w := presence.NewWatcher(s.presence, s.modelTag) 441 p := presence.NewPinger(s.presence, s.modelTag, "a") 442 defer assertStopped(c, w) 443 defer assertStopped(c, p) 444 445 ch := make(chan presence.Change) 446 w.Watch("a", ch) 447 assertChange(c, ch, presence.Change{"a", false}) 448 449 // Nothing to do here. 450 w.Sync() 451 452 c.Assert(p.Start(), gc.IsNil) 453 454 done := make(chan bool) 455 go func() { 456 w.Sync() 457 done <- true 458 }() 459 460 select { 461 case <-done: 462 c.Fatalf("Sync returned too early") 463 // Note(jam): This used to wait 200ms to ensure that 464 // Sync was actually blocked waiting for a presence 465 // change. Is ShortWait long enough for this assurance? 466 case <-time.After(testing.ShortWait): 467 } 468 469 assertChange(c, ch, presence.Change{"a", true}) 470 471 select { 472 case <-done: 473 case <-time.After(testing.LongWait): 474 c.Fatalf("Sync failed to returned") 475 } 476 } 477 478 func (s *PresenceSuite) TestFindAllBeings(c *gc.C) { 479 w := presence.NewWatcher(s.presence, s.modelTag) 480 p := presence.NewPinger(s.presence, s.modelTag, "a") 481 defer assertStopped(c, w) 482 defer assertStopped(c, p) 483 484 ch := make(chan presence.Change) 485 w.Watch("a", ch) 486 assertChange(c, ch, presence.Change{"a", false}) 487 c.Assert(p.Start(), gc.IsNil) 488 done := make(chan bool) 489 go func() { 490 w.Sync() 491 done <- true 492 }() 493 assertChange(c, ch, presence.Change{"a", true}) 494 results, err := presence.FindAllBeings(w) 495 c.Assert(err, jc.ErrorIsNil) 496 c.Assert(results, gc.HasLen, 1) 497 select { 498 case <-done: 499 case <-time.After(testing.LongWait): 500 c.Fatalf("Sync failed to returned") 501 } 502 } 503 504 func (s *PresenceSuite) TestTwoEnvironments(c *gc.C) { 505 key := "a" 506 w1, p1, ch1 := s.setup(c, key) 507 defer assertStopped(c, w1) 508 defer assertStopped(c, p1) 509 510 w2, p2, ch2 := s.setup(c, key) 511 defer assertStopped(c, w2) 512 defer assertStopped(c, p2) 513 514 c.Assert(p1.Start(), gc.IsNil) 515 w1.StartSync() 516 w2.StartSync() 517 assertNoChange(c, ch2) 518 assertChange(c, ch1, presence.Change{"a", true}) 519 520 c.Assert(p2.Start(), gc.IsNil) 521 w1.StartSync() 522 w2.StartSync() 523 assertNoChange(c, ch1) 524 assertChange(c, ch2, presence.Change{"a", true}) 525 526 err := p1.KillForTesting() 527 c.Assert(err, jc.ErrorIsNil) 528 presence.FakeTimeSlot(1) 529 w1.StartSync() 530 w2.StartSync() 531 assertChange(c, ch1, presence.Change{"a", false}) 532 assertNoChange(c, ch2) 533 534 err = p2.KillForTesting() 535 c.Assert(err, jc.ErrorIsNil) 536 presence.FakeTimeSlot(2) 537 w1.StartSync() 538 w2.StartSync() 539 assertChange(c, ch2, presence.Change{"a", false}) 540 assertNoChange(c, ch1) 541 } 542 543 func (s *PresenceSuite) setup(c *gc.C, key string) (*presence.Watcher, *presence.Pinger, <-chan presence.Change) { 544 uuid, err := utils.NewUUID() 545 c.Assert(err, jc.ErrorIsNil) 546 modelUUID := uuid.String() 547 548 w := presence.NewWatcher(s.presence, names.NewModelTag(modelUUID)) 549 p := presence.NewPinger(s.presence, names.NewModelTag(modelUUID), key) 550 551 ch := make(chan presence.Change) 552 w.Watch(key, ch) 553 assertChange(c, ch, presence.Change{key, false}) 554 return w, p, ch 555 }