github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/state/watcher/watcher_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package watcher_test 5 6 import ( 7 stdtesting "testing" 8 "time" 9 10 gitjujutesting "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/mgo.v2" 14 "gopkg.in/mgo.v2/txn" 15 "gopkg.in/tomb.v2" 16 17 "github.com/juju/juju/mongo" 18 "github.com/juju/juju/state/watcher" 19 "github.com/juju/juju/testing" 20 ) 21 22 // Test tuning parameters. 23 const ( 24 // worstCase is used for timeouts when timing out 25 // will fail the test. Raising this value should 26 // not affect the overall running time of the tests 27 // unless they fail. 28 worstCase = testing.LongWait 29 30 // justLongEnough is used for timeouts that 31 // are expected to happen for a test to complete 32 // successfully. Reducing this value will make 33 // the tests run faster at the expense of making them 34 // fail more often on heavily loaded or slow hardware. 35 justLongEnough = testing.ShortWait 36 37 // fastPeriod specifies the period of the watcher for 38 // tests where the timing is not critical. 39 fastPeriod = 10 * time.Millisecond 40 41 // slowPeriod specifies the period of the watcher 42 // for tests where the timing is important. 43 slowPeriod = 1 * time.Second 44 ) 45 46 func TestPackage(t *stdtesting.T) { 47 testing.MgoTestPackage(t) 48 } 49 50 type watcherSuite struct { 51 gitjujutesting.MgoSuite 52 testing.BaseSuite 53 54 log *mgo.Collection 55 stash *mgo.Collection 56 runner *txn.Runner 57 w *watcher.Watcher 58 ch chan watcher.Change 59 oldPeriod time.Duration 60 iteratorFunc func() mongo.Iterator 61 } 62 63 // FastPeriodSuite implements tests that should 64 // work regardless of the watcher refresh period. 65 type FastPeriodSuite struct { 66 watcherSuite 67 } 68 69 func (s *FastPeriodSuite) SetUpSuite(c *gc.C) { 70 s.watcherSuite.SetUpSuite(c) 71 watcher.Period = fastPeriod 72 } 73 74 var _ = gc.Suite(&FastPeriodSuite{}) 75 76 func (s *watcherSuite) SetUpSuite(c *gc.C) { 77 s.BaseSuite.SetUpSuite(c) 78 s.MgoSuite.SetUpSuite(c) 79 s.oldPeriod = watcher.Period 80 } 81 82 func (s *watcherSuite) TearDownSuite(c *gc.C) { 83 s.MgoSuite.TearDownSuite(c) 84 s.BaseSuite.TearDownSuite(c) 85 watcher.Period = s.oldPeriod 86 } 87 88 func (s *watcherSuite) SetUpTest(c *gc.C) { 89 s.BaseSuite.SetUpTest(c) 90 s.MgoSuite.SetUpTest(c) 91 92 db := s.MgoSuite.Session.DB("juju") 93 s.log = db.C("txnlog") 94 s.log.Create(&mgo.CollectionInfo{ 95 Capped: true, 96 MaxBytes: 1000000, 97 }) 98 s.stash = db.C("txn.stash") 99 s.runner = txn.NewRunner(db.C("txn")) 100 s.runner.ChangeLog(s.log) 101 s.w = watcher.NewTestWatcher(s.log, s.iteratorFunc) 102 s.ch = make(chan watcher.Change) 103 } 104 105 func (s *watcherSuite) TearDownTest(c *gc.C) { 106 c.Assert(s.w.Stop(), gc.IsNil) 107 108 s.MgoSuite.TearDownTest(c) 109 s.BaseSuite.TearDownTest(c) 110 } 111 112 type M map[string]interface{} 113 114 func assertChange(c *gc.C, watch <-chan watcher.Change, want watcher.Change) { 115 select { 116 case got := <-watch: 117 if got != want { 118 c.Fatalf("watch reported %v, want %v", got, want) 119 } 120 case <-time.After(worstCase): 121 c.Fatalf("watch reported nothing, want %v", want) 122 } 123 } 124 125 func assertNoChange(c *gc.C, watch <-chan watcher.Change) { 126 select { 127 case got := <-watch: 128 c.Fatalf("watch reported %v, want nothing", got) 129 case <-time.After(justLongEnough): 130 } 131 } 132 133 func assertOrder(c *gc.C, revnos ...int64) { 134 last := int64(-2) 135 for _, revno := range revnos { 136 if revno <= last { 137 c.Fatalf("got bad revno sequence: %v", revnos) 138 } 139 last = revno 140 } 141 } 142 143 func (s *watcherSuite) revno(c string, id interface{}) (revno int64) { 144 var doc struct { 145 Revno int64 `bson:"txn-revno"` 146 } 147 err := s.log.Database.C(c).FindId(id).One(&doc) 148 if err != nil { 149 panic(err) 150 } 151 return doc.Revno 152 } 153 154 func (s *watcherSuite) insert(c *gc.C, coll string, id interface{}) (revno int64) { 155 ops := []txn.Op{{C: coll, Id: id, Insert: M{"n": 1}}} 156 err := s.runner.Run(ops, "", nil) 157 if err != nil { 158 panic(err) 159 } 160 revno = s.revno(coll, id) 161 c.Logf("insert(%#v, %#v) => revno %d", coll, id, revno) 162 return revno 163 } 164 165 func (s *watcherSuite) insertAll(c *gc.C, coll string, ids ...interface{}) (revnos []int64) { 166 var ops []txn.Op 167 for _, id := range ids { 168 ops = append(ops, txn.Op{C: coll, Id: id, Insert: M{"n": 1}}) 169 } 170 err := s.runner.Run(ops, "", nil) 171 if err != nil { 172 panic(err) 173 } 174 for _, id := range ids { 175 revnos = append(revnos, s.revno(coll, id)) 176 } 177 c.Logf("insertAll(%#v, %v) => revnos %v", coll, ids, revnos) 178 return revnos 179 } 180 181 func (s *watcherSuite) update(c *gc.C, coll string, id interface{}) (revno int64) { 182 ops := []txn.Op{{C: coll, Id: id, Update: M{"$inc": M{"n": 1}}}} 183 err := s.runner.Run(ops, "", nil) 184 if err != nil { 185 panic(err) 186 } 187 revno = s.revno(coll, id) 188 c.Logf("update(%#v, %#v) => revno %d", coll, id, revno) 189 return revno 190 } 191 192 func (s *watcherSuite) remove(c *gc.C, coll string, id interface{}) (revno int64) { 193 ops := []txn.Op{{C: coll, Id: id, Remove: true}} 194 err := s.runner.Run(ops, "", nil) 195 if err != nil { 196 panic(err) 197 } 198 c.Logf("remove(%#v, %#v) => revno -1", coll, id) 199 return -1 200 } 201 202 func (s *FastPeriodSuite) TestErrAndDead(c *gc.C) { 203 c.Assert(s.w.Err(), gc.Equals, tomb.ErrStillAlive) 204 select { 205 case <-s.w.Dead(): 206 c.Fatalf("Dead channel fired unexpectedly") 207 default: 208 } 209 c.Assert(s.w.Stop(), gc.IsNil) 210 c.Assert(s.w.Err(), gc.IsNil) 211 select { 212 case <-s.w.Dead(): 213 default: 214 c.Fatalf("Dead channel should have fired") 215 } 216 } 217 218 func (s *FastPeriodSuite) TestWatchBeforeKnown(c *gc.C) { 219 s.w.Watch("test", "a", s.ch) 220 assertNoChange(c, s.ch) 221 222 revno := s.insert(c, "test", "a") 223 224 s.w.StartSync() 225 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 226 assertNoChange(c, s.ch) 227 228 assertOrder(c, -1, revno) 229 } 230 231 func (s *FastPeriodSuite) TestWatchAfterKnown(c *gc.C) { 232 _ = s.insert(c, "test", "a") 233 234 s.w.StartSync() 235 236 s.w.Watch("test", "a", s.ch) 237 assertNoChange(c, s.ch) 238 revno := s.update(c, "test", "a") 239 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 240 assertNoChange(c, s.ch) 241 242 assertOrder(c, -1, revno) 243 } 244 245 func (s *FastPeriodSuite) TestWatchIgnoreUnwatched(c *gc.C) { 246 s.w.Watch("test", "a", s.ch) 247 assertNoChange(c, s.ch) 248 249 s.insert(c, "test", "b") 250 251 s.w.StartSync() 252 assertNoChange(c, s.ch) 253 } 254 255 func (s *FastPeriodSuite) TestWatchOrder(c *gc.C) { 256 s.w.StartSync() 257 for _, id := range []string{"a", "b", "c", "d"} { 258 s.w.Watch("test", id, s.ch) 259 } 260 revno1 := s.insert(c, "test", "a") 261 revno2 := s.insert(c, "test", "b") 262 revno3 := s.insert(c, "test", "c") 263 264 s.w.StartSync() 265 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 266 assertChange(c, s.ch, watcher.Change{"test", "b", revno2}) 267 assertChange(c, s.ch, watcher.Change{"test", "c", revno3}) 268 assertNoChange(c, s.ch) 269 } 270 271 func (s *FastPeriodSuite) TestTransactionWithMultiple(c *gc.C) { 272 s.w.StartSync() 273 for _, id := range []string{"a", "b", "c"} { 274 s.w.Watch("test", id, s.ch) 275 } 276 revnos := s.insertAll(c, "test", "a", "b", "c") 277 s.w.StartSync() 278 assertChange(c, s.ch, watcher.Change{"test", "a", revnos[0]}) 279 assertChange(c, s.ch, watcher.Change{"test", "b", revnos[1]}) 280 assertChange(c, s.ch, watcher.Change{"test", "c", revnos[2]}) 281 assertNoChange(c, s.ch) 282 } 283 284 func (s *FastPeriodSuite) TestWatchMultipleChannels(c *gc.C) { 285 ch1 := make(chan watcher.Change) 286 ch2 := make(chan watcher.Change) 287 ch3 := make(chan watcher.Change) 288 s.w.Watch("test1", 1, ch1) 289 s.w.Watch("test2", 2, ch2) 290 s.w.Watch("test3", 3, ch3) 291 revno1 := s.insert(c, "test1", 1) 292 revno2 := s.insert(c, "test2", 2) 293 revno3 := s.insert(c, "test3", 3) 294 s.w.StartSync() 295 s.w.Unwatch("test2", 2, ch2) 296 assertChange(c, ch1, watcher.Change{"test1", 1, revno1}) 297 _ = revno2 298 assertChange(c, ch3, watcher.Change{"test3", 3, revno3}) 299 assertNoChange(c, ch1) 300 assertNoChange(c, ch2) 301 assertNoChange(c, ch3) 302 } 303 304 func (s *FastPeriodSuite) TestIgnoreAncientHistory(c *gc.C) { 305 s.insert(c, "test", "a") 306 307 w := watcher.NewTestWatcher(s.log, s.iteratorFunc) 308 defer w.Stop() 309 w.StartSync() 310 311 w.Watch("test", "a", s.ch) 312 assertNoChange(c, s.ch) 313 } 314 315 func (s *FastPeriodSuite) TestUpdate(c *gc.C) { 316 s.w.Watch("test", "a", s.ch) 317 assertNoChange(c, s.ch) 318 319 revno1 := s.insert(c, "test", "a") 320 s.w.StartSync() 321 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 322 assertNoChange(c, s.ch) 323 324 revno2 := s.update(c, "test", "a") 325 s.w.StartSync() 326 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 327 328 assertOrder(c, -1, revno1, revno2) 329 } 330 331 func (s *FastPeriodSuite) TestRemove(c *gc.C) { 332 s.w.Watch("test", "a", s.ch) 333 assertNoChange(c, s.ch) 334 335 revno1 := s.insert(c, "test", "a") 336 s.w.StartSync() 337 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 338 assertNoChange(c, s.ch) 339 340 revno2 := s.remove(c, "test", "a") 341 s.w.StartSync() 342 assertChange(c, s.ch, watcher.Change{"test", "a", -1}) 343 assertNoChange(c, s.ch) 344 345 revno3 := s.insert(c, "test", "a") 346 s.w.StartSync() 347 assertChange(c, s.ch, watcher.Change{"test", "a", revno3}) 348 assertNoChange(c, s.ch) 349 350 assertOrder(c, revno2, revno1) 351 assertOrder(c, revno2, revno3) 352 } 353 354 func (s *FastPeriodSuite) TestWatchKnownRemove(c *gc.C) { 355 revno1 := s.insert(c, "test", "a") 356 s.w.StartSync() 357 s.w.Watch("test", "a", s.ch) 358 assertNoChange(c, s.ch) 359 revno2 := s.remove(c, "test", "a") 360 s.w.StartSync() 361 362 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 363 364 assertOrder(c, revno2, revno1) 365 } 366 367 func (s *FastPeriodSuite) TestWatchAlreadyRemoved(c *gc.C) { 368 _ = s.insert(c, "test", "a") 369 _ = s.remove(c, "test", "a") 370 s.w.StartSync() 371 372 s.w.Watch("test", "a", s.ch) 373 assertNoChange(c, s.ch) 374 // If you watch after the changes have happened, you don't get an event. 375 // If you recreate the document, you see it show up again. 376 revno3 := s.insert(c, "test", "a") 377 assertChange(c, s.ch, watcher.Change{"test", "a", revno3}) 378 revno4 := s.remove(c, "test", "a") 379 assertChange(c, s.ch, watcher.Change{"test", "a", revno4}) 380 } 381 382 func (s *FastPeriodSuite) TestWatchMultiBeforeKnown(c *gc.C) { 383 err := s.w.WatchMulti("test", []interface{}{"a", "b"}, s.ch) 384 c.Assert(err, jc.ErrorIsNil) 385 s.w.StartSync() 386 assertNoChange(c, s.ch) 387 revno1 := s.insert(c, "test", "a") 388 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 389 assertNoChange(c, s.ch) 390 } 391 392 func (s *FastPeriodSuite) TestWatchMultiDuplicateWatch(c *gc.C) { 393 s.w.Watch("test", "b", s.ch) 394 assertNoChange(c, s.ch) 395 err := s.w.WatchMulti("test", []interface{}{"a", "b"}, s.ch) 396 c.Assert(err, gc.ErrorMatches, `tried to re-add channel .* for document "b" in collection "test"`) 397 // Changes to "a" should not be watched as we had an error 398 _ = s.insert(c, "test", "a") 399 assertNoChange(c, s.ch) 400 } 401 402 func (s *FastPeriodSuite) TestWatchMultiInvalidId(c *gc.C) { 403 err := s.w.WatchMulti("test", []interface{}{"a", nil}, s.ch) 404 c.Assert(err, gc.ErrorMatches, `cannot watch a document with nil id`) 405 // Changes to "a" should not be watched as we had an error 406 _ = s.insert(c, "test", "a") 407 assertNoChange(c, s.ch) 408 409 } 410 411 func (s *FastPeriodSuite) TestWatchMultiAfterKnown(c *gc.C) { 412 s.w.Watch("test", "b", s.ch) 413 revno1 := s.insert(c, "test", "a") 414 revnob := s.insert(c, "test", "b") 415 s.w.StartSync() 416 assertChange(c, s.ch, watcher.Change{"test", "b", revnob}) 417 // Wait to start the watch until we see the change for "b", so that we know the Sync has completed 418 err := s.w.WatchMulti("test", []interface{}{"a", "c"}, s.ch) 419 c.Assert(err, jc.ErrorIsNil) 420 assertNoChange(c, s.ch) 421 // We don't see the change that occurred before we started watching, but we see any changes after that fact 422 revno2 := s.update(c, "test", "a") 423 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 424 assertNoChange(c, s.ch) 425 assertOrder(c, -1, revno1, revno2) 426 } 427 428 func (s *FastPeriodSuite) TestScale(c *gc.C) { 429 const N = 500 430 const T = 10 431 432 c.Logf("Watching all documents...") 433 for i := 0; i < N; i++ { 434 s.w.Watch("test", i, s.ch) 435 } 436 437 c.Logf("Creating %d documents, %d per transaction...", N, T) 438 ops := make([]txn.Op, T) 439 for i := 0; i < (N / T); i++ { 440 ops = ops[:0] 441 for j := 0; j < T && i*T+j < N; j++ { 442 ops = append(ops, txn.Op{C: "test", Id: i*T + j, Insert: M{"n": 1}}) 443 } 444 err := s.runner.Run(ops, "", nil) 445 c.Assert(err, jc.ErrorIsNil) 446 } 447 448 c.Logf("Forcing a refresh...") 449 s.w.StartSync() 450 451 count, err := s.Session.DB("juju").C("test").Count() 452 c.Assert(err, jc.ErrorIsNil) 453 c.Logf("Got %d documents in the collection...", count) 454 c.Assert(count, gc.Equals, N) 455 456 c.Logf("Reading all changes...") 457 seen := make(map[interface{}]bool) 458 worstTimeout := time.After(worstCase) 459 for i := 0; i < N; i++ { 460 select { 461 case change := <-s.ch: 462 seen[change.Id] = true 463 case <-worstTimeout: 464 c.Fatalf("not enough changes: got %d, want %d", len(seen), N) 465 } 466 } 467 c.Assert(len(seen), gc.Equals, N) 468 } 469 470 func (s *FastPeriodSuite) TestWatchUnwatchOnQueue(c *gc.C) { 471 const N = 10 472 s.w.StartSync() 473 for i := 0; i < N; i++ { 474 s.w.Watch("test", i, s.ch) 475 } 476 for i := 0; i < N; i++ { 477 s.insert(c, "test", i) 478 } 479 for i := 1; i < N; i += 2 { 480 s.w.Unwatch("test", i, s.ch) 481 } 482 s.w.StartSync() 483 seen := make(map[interface{}]bool) 484 for i := 0; i < N/2; i++ { 485 select { 486 case change := <-s.ch: 487 seen[change.Id] = true 488 case <-time.After(worstCase): 489 c.Fatalf("not enough changes: got %d, want %d", len(seen), N/2) 490 } 491 } 492 c.Assert(len(seen), gc.Equals, N/2) 493 assertNoChange(c, s.ch) 494 } 495 496 func (s *FastPeriodSuite) TestStartSync(c *gc.C) { 497 s.w.Watch("test", "a", s.ch) 498 499 revno := s.insert(c, "test", "a") 500 501 done := make(chan bool) 502 go func() { 503 s.w.StartSync() 504 s.w.StartSync() 505 s.w.StartSync() 506 done <- true 507 }() 508 509 select { 510 case <-done: 511 case <-time.After(worstCase): 512 c.Fatalf("StartSync failed to return") 513 } 514 515 assertChange(c, s.ch, watcher.Change{"test", "a", revno}) 516 } 517 518 func (s *FastPeriodSuite) TestWatchCollection(c *gc.C) { 519 chA1 := make(chan watcher.Change) 520 chB1 := make(chan watcher.Change) 521 chA := make(chan watcher.Change) 522 chB := make(chan watcher.Change) 523 524 s.w.Watch("testA", 1, chA1) 525 s.w.Watch("testB", 1, chB1) 526 s.w.WatchCollection("testA", chA) 527 s.w.WatchCollection("testB", chB) 528 529 revno1 := s.insert(c, "testA", 1) 530 revno2 := s.insert(c, "testA", 2) 531 revno3 := s.insert(c, "testB", 1) 532 revno4 := s.insert(c, "testB", 2) 533 534 s.w.StartSync() 535 536 seen := map[chan<- watcher.Change][]watcher.Change{} 537 timeout := time.After(testing.LongWait) 538 n := 0 539 Loop1: 540 for n < 6 { 541 select { 542 case chg := <-chA1: 543 seen[chA1] = append(seen[chA1], chg) 544 case chg := <-chB1: 545 seen[chB1] = append(seen[chB1], chg) 546 case chg := <-chA: 547 seen[chA] = append(seen[chA], chg) 548 case chg := <-chB: 549 seen[chB] = append(seen[chB], chg) 550 case <-timeout: 551 break Loop1 552 } 553 n++ 554 } 555 556 c.Check(seen[chA1], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 557 c.Check(seen[chB1], gc.DeepEquals, []watcher.Change{{"testB", 1, revno3}}) 558 c.Check(seen[chA], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}, {"testA", 2, revno2}}) 559 c.Check(seen[chB], gc.DeepEquals, []watcher.Change{{"testB", 1, revno3}, {"testB", 2, revno4}}) 560 if c.Failed() { 561 return 562 } 563 564 s.w.UnwatchCollection("testB", chB) 565 s.w.Unwatch("testB", 1, chB1) 566 567 revno1 = s.update(c, "testA", 1) 568 569 s.w.StartSync() 570 571 timeout = time.After(testing.LongWait) 572 seen = map[chan<- watcher.Change][]watcher.Change{} 573 n = 0 574 Loop2: 575 for n < 2 { 576 select { 577 case chg := <-chA1: 578 seen[chA1] = append(seen[chA1], chg) 579 case chg := <-chB1: 580 seen[chB1] = append(seen[chB1], chg) 581 case chg := <-chA: 582 seen[chA] = append(seen[chA], chg) 583 case chg := <-chB: 584 seen[chB] = append(seen[chB], chg) 585 case <-timeout: 586 break Loop2 587 } 588 n++ 589 } 590 c.Check(seen[chA1], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 591 c.Check(seen[chB1], gc.IsNil) 592 c.Check(seen[chA], gc.DeepEquals, []watcher.Change{{"testA", 1, revno1}}) 593 c.Check(seen[chB], gc.IsNil) 594 595 // Check that no extra events arrive. 596 seen = map[chan<- watcher.Change][]watcher.Change{} 597 timeout = time.After(testing.ShortWait) 598 Loop3: 599 for { 600 select { 601 case chg := <-chA1: 602 seen[chA1] = append(seen[chA1], chg) 603 case chg := <-chB1: 604 seen[chB1] = append(seen[chB1], chg) 605 case chg := <-chA: 606 seen[chA] = append(seen[chA], chg) 607 case chg := <-chB: 608 seen[chB] = append(seen[chB], chg) 609 case <-timeout: 610 break Loop3 611 } 612 } 613 c.Check(seen[chA1], gc.IsNil) 614 c.Check(seen[chB1], gc.IsNil) 615 c.Check(seen[chA], gc.IsNil) 616 c.Check(seen[chB], gc.IsNil) 617 } 618 619 func (s *FastPeriodSuite) TestUnwatchCollectionWithFilter(c *gc.C) { 620 filter := func(key interface{}) bool { 621 id := key.(int) 622 return id != 2 623 } 624 chA := make(chan watcher.Change) 625 s.w.WatchCollectionWithFilter("testA", chA, filter) 626 revnoA := s.insert(c, "testA", 1) 627 assertChange(c, chA, watcher.Change{"testA", 1, revnoA}) 628 s.insert(c, "testA", 2) 629 assertNoChange(c, chA) 630 s.insert(c, "testA", 3) 631 s.w.StartSync() 632 assertChange(c, chA, watcher.Change{"testA", 3, revnoA}) 633 } 634 635 func (s *FastPeriodSuite) TestUnwatchCollectionWithOutstandingRequest(c *gc.C) { 636 chA := make(chan watcher.Change) 637 s.w.WatchCollection("testA", chA) 638 chB := make(chan watcher.Change) 639 s.w.Watch("testB", 1, chB) 640 revnoA := s.insert(c, "testA", 1) 641 s.insert(c, "testA", 2) 642 // By inserting this *after* the testA document, we ensure that 643 // the watcher will try to send on chB after sending on chA. 644 // The original bug that this test guards against meant that the 645 // UnwatchCollection did not correctly cancel the outstanding 646 // request, so the loop would never get around to sending on 647 // chB. 648 revnoB := s.insert(c, "testB", 1) 649 s.w.StartSync() 650 // When we receive the first change on chA, we know that 651 // the watcher is trying to send changes on all the 652 // watcher channels (2 changes on chA and 1 change on chB). 653 assertChange(c, chA, watcher.Change{"testA", 1, revnoA}) 654 s.w.UnwatchCollection("testA", chA) 655 assertChange(c, chB, watcher.Change{"testB", 1, revnoB}) 656 } 657 658 func (s *FastPeriodSuite) TestNonMutatingTxn(c *gc.C) { 659 chA1 := make(chan watcher.Change) 660 chA := make(chan watcher.Change) 661 662 s.w.Watch("test", "a", chA1) 663 s.w.WatchCollection("test", chA) 664 revno1 := s.insert(c, "test", "a") 665 666 assertChange(c, chA1, watcher.Change{"test", "a", revno1}) 667 assertChange(c, chA, watcher.Change{"test", "a", revno1}) 668 669 revno2 := s.insert(c, "test", "a") 670 671 c.Assert(revno1, gc.Equals, revno2) 672 673 s.w.StartSync() 674 675 // We track what events we have published to each consumer, so a repeat on a 676 // doc is skipped 677 assertNoChange(c, chA1) 678 // We don't track individual document last-seen revno, so any document txn 679 // shows up as a change in the collection 680 assertChange(c, chA, watcher.Change{"test", "a", revno2}) 681 } 682 683 // SlowPeriodSuite implements tests 684 // that are flaky when the watcher refresh period 685 // is small. 686 type SlowPeriodSuite struct { 687 watcherSuite 688 } 689 690 func (s *SlowPeriodSuite) SetUpSuite(c *gc.C) { 691 s.watcherSuite.SetUpSuite(c) 692 watcher.Period = slowPeriod 693 } 694 695 var _ = gc.Suite(&SlowPeriodSuite{}) 696 697 func (s *SlowPeriodSuite) TestWatchBeforeRemoveKnown(c *gc.C) { 698 s.w.Watch("test", "a", s.ch) 699 revno1 := s.insert(c, "test", "a") 700 s.w.StartSync() 701 702 assertChange(c, s.ch, watcher.Change{"test", "a", revno1}) 703 revno2 := s.remove(c, "test", "a") 704 s.w.StartSync() 705 assertChange(c, s.ch, watcher.Change{"test", "a", revno2}) 706 707 assertOrder(c, revno2, revno1) 708 } 709 710 func (s *SlowPeriodSuite) TestDoubleUpdate(c *gc.C) { 711 assertNoChange(c, s.ch) 712 713 revno1 := s.insert(c, "test", "a") 714 s.w.StartSync() 715 716 revno2 := s.update(c, "test", "a") 717 revno3 := s.update(c, "test", "a") 718 719 s.w.Watch("test", "a", s.ch) 720 assertNoChange(c, s.ch) 721 722 s.w.StartSync() 723 assertChange(c, s.ch, watcher.Change{"test", "a", revno3}) 724 assertNoChange(c, s.ch) 725 726 assertOrder(c, -1, revno1, revno2, revno3) 727 } 728 729 func (s *SlowPeriodSuite) TestWatchPeriod(c *gc.C) { 730 revno1 := s.insert(c, "test", "a") 731 s.w.StartSync() 732 t0 := time.Now() 733 s.w.Watch("test", "a", s.ch) 734 revno2 := s.update(c, "test", "a") 735 736 leeway := watcher.Period / 4 737 select { 738 case got := <-s.ch: 739 gotPeriod := time.Since(t0) 740 c.Assert(got, gc.Equals, watcher.Change{"test", "a", revno2}) 741 if gotPeriod < watcher.Period-leeway { 742 c.Fatalf("watcher not waiting long enough; got %v want %v", gotPeriod, watcher.Period) 743 } 744 case <-time.After(watcher.Period + leeway): 745 gotPeriod := time.Since(t0) 746 c.Fatalf("watcher waited too long; got %v want %v", gotPeriod, watcher.Period) 747 } 748 749 assertOrder(c, -1, revno1, revno2) 750 } 751 752 func (s *SlowPeriodSuite) TestStartSyncStartsImmediately(c *gc.C) { 753 // Ensure we're at the start of a sync cycle. 754 s.w.StartSync() 755 time.Sleep(justLongEnough) 756 757 // StartSync after Watching should see the current state of affairs. 758 s.w.Watch("test", "a", s.ch) 759 revno := s.insert(c, "test", "a") 760 s.w.StartSync() 761 select { 762 case got := <-s.ch: 763 c.Assert(got.Revno, gc.Equals, revno) 764 case <-time.After(watcher.Period / 2): 765 c.Fatalf("watch after StartSync is still using old info") 766 } 767 768 s.remove(c, "test", "a") 769 s.w.StartSync() 770 ch := make(chan watcher.Change) 771 s.w.Watch("test", "a", ch) 772 select { 773 case got := <-ch: 774 c.Fatalf("got event %#v when starting watcher after doc was removed", got) 775 case <-time.After(justLongEnough): 776 } 777 } 778 779 type badIter struct { 780 *mgo.Iter 781 782 errorAfter int 783 } 784 785 func (b *badIter) Close() (err error) { 786 defer func() { 787 err2 := b.Iter.Close() 788 if err == nil { 789 err = err2 790 } 791 }() 792 793 b.errorAfter-- 794 if b.errorAfter < 0 { 795 return &mgo.QueryError{ 796 Code: 136, 797 } 798 } 799 return nil 800 } 801 802 type WatcherErrorSuite struct { 803 watcherSuite 804 } 805 806 func (s *WatcherErrorSuite) SetUpSuite(c *gc.C) { 807 s.watcherSuite.SetUpSuite(c) 808 iter := &badIter{ 809 errorAfter: 2, 810 } 811 s.iteratorFunc = func() mongo.Iterator { 812 iter.Iter = s.log.Find(nil).Batch(10).Sort("-$natural").Iter() 813 return iter 814 } 815 watcher.Period = fastPeriod 816 } 817 818 func (s *WatcherErrorSuite) TearDownTest(c *gc.C) { 819 s.MgoSuite.TearDownTest(c) 820 s.BaseSuite.TearDownTest(c) 821 } 822 823 var _ = gc.Suite(&WatcherErrorSuite{}) 824 825 func (s *WatcherErrorSuite) TestCappedCollectionError(c *gc.C) { 826 s.w.Watch("test", "a", s.ch) 827 s.w.StartSync() 828 829 s.insert(c, "test", "a") 830 for i := 1; i < 30; i++ { 831 s.update(c, "test", "a") 832 } 833 834 select { 835 case <-s.w.Dead(): 836 // the watcher will die when the iter close fails. 837 case <-time.After(worstCase): 838 c.Fatalf("watcher didn't die") 839 } 840 841 err := s.w.Stop() 842 c.Assert(err, gc.NotNil) 843 c.Assert(err, gc.ErrorMatches, "agent should be restarted") 844 }