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