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