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  }