github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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  	"fmt"
     8  	"strconv"
     9  	"sync"
    10  	"sync/atomic"
    11  	stdtesting "testing"
    12  	"time"
    13  
    14  	"github.com/juju/errors"
    15  	gitjujutesting "github.com/juju/testing"
    16  	jc "github.com/juju/testing/checkers"
    17  	"github.com/juju/utils"
    18  	gc "gopkg.in/check.v1"
    19  	"gopkg.in/juju/names.v2"
    20  	"gopkg.in/juju/worker.v1"
    21  	"gopkg.in/mgo.v2"
    22  	"gopkg.in/mgo.v2/bson"
    23  	"gopkg.in/tomb.v2"
    24  
    25  	"github.com/juju/juju/state/presence"
    26  	"github.com/juju/juju/testing"
    27  )
    28  
    29  func TestPackage(t *stdtesting.T) {
    30  	testing.MgoTestPackage(t)
    31  }
    32  
    33  type PresenceSuite struct {
    34  	gitjujutesting.MgoSuite
    35  	testing.BaseSuite
    36  	presence *mgo.Collection
    37  	pings    *mgo.Collection
    38  	modelTag names.ModelTag
    39  }
    40  
    41  var _ = gc.Suite(&PresenceSuite{})
    42  
    43  func (s *PresenceSuite) SetUpSuite(c *gc.C) {
    44  	s.BaseSuite.SetUpSuite(c)
    45  	s.MgoSuite.SetUpSuite(c)
    46  	uuid, err := utils.NewUUID()
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	s.modelTag = names.NewModelTag(uuid.String())
    49  }
    50  
    51  func (s *PresenceSuite) TearDownSuite(c *gc.C) {
    52  	s.MgoSuite.TearDownSuite(c)
    53  	s.BaseSuite.TearDownSuite(c)
    54  }
    55  
    56  func (s *PresenceSuite) SetUpTest(c *gc.C) {
    57  	s.BaseSuite.SetUpTest(c)
    58  	s.MgoSuite.SetUpTest(c)
    59  
    60  	db := s.MgoSuite.Session.DB("presence")
    61  	s.presence = db.C("presence")
    62  	s.pings = db.C("presence.pings")
    63  
    64  	presence.FakeTimeSlot(0)
    65  }
    66  
    67  func (s *PresenceSuite) TearDownTest(c *gc.C) {
    68  	s.MgoSuite.TearDownTest(c)
    69  	s.BaseSuite.TearDownTest(c)
    70  
    71  	presence.RealTimeSlot()
    72  	presence.RealPeriod()
    73  }
    74  
    75  func assertChange(c *gc.C, watch <-chan presence.Change, want presence.Change) {
    76  	select {
    77  	case got := <-watch:
    78  		if got != want {
    79  			c.Fatalf("watch reported %v, want %v", got, want)
    80  		}
    81  	case <-time.After(testing.LongWait):
    82  		c.Fatalf("watch reported nothing, want %v", want)
    83  	}
    84  }
    85  
    86  func assertNoChange(c *gc.C, watch <-chan presence.Change) {
    87  	select {
    88  	case got := <-watch:
    89  		c.Fatalf("watch reported %v, want nothing", got)
    90  	case <-time.After(testing.ShortWait):
    91  	}
    92  }
    93  
    94  func assertAlive(c *gc.C, w *presence.Watcher, key string, expAlive bool) {
    95  	realAlive, err := w.Alive(key)
    96  	c.Assert(err, jc.ErrorIsNil)
    97  	c.Assert(realAlive, gc.Equals, expAlive)
    98  }
    99  
   100  // assertStopped stops a worker and waits until it reports stopped.
   101  // Use this method in favor of defer w.Stop() because you _must_ ensure
   102  // that the worker has stopped, and thus is no longer using its mgo
   103  // session before TearDownTest shuts down the connection.
   104  func assertStopped(c *gc.C, w worker.Worker) {
   105  	c.Assert(worker.Stop(w), jc.ErrorIsNil)
   106  }
   107  
   108  func (s *PresenceSuite) TestErrAndDead(c *gc.C) {
   109  	w := presence.NewWatcher(s.presence, s.modelTag)
   110  	defer assertStopped(c, w)
   111  
   112  	c.Assert(errors.Cause(w.Err()), gc.Equals, tomb.ErrStillAlive)
   113  	select {
   114  	case <-w.Dead():
   115  		c.Fatalf("Dead channel fired unexpectedly")
   116  	default:
   117  	}
   118  	c.Assert(w.Stop(), gc.IsNil)
   119  	c.Assert(w.Err(), gc.IsNil)
   120  	select {
   121  	case <-w.Dead():
   122  	default:
   123  		c.Fatalf("Dead channel should have fired")
   124  	}
   125  }
   126  
   127  func (s *PresenceSuite) getDirectRecorder() presence.PingRecorder {
   128  	return presence.DirectRecordFunc(s.presence)
   129  }
   130  
   131  func (s *PresenceSuite) TestAliveError(c *gc.C) {
   132  	w := presence.NewWatcher(s.presence, s.modelTag)
   133  	c.Assert(w.Stop(), gc.IsNil)
   134  
   135  	alive, err := w.Alive("a")
   136  	c.Assert(err, gc.ErrorMatches, ".*: watcher is dying")
   137  	c.Assert(alive, jc.IsFalse)
   138  	w.Wait()
   139  }
   140  
   141  func (s *PresenceSuite) TestWorkflow(c *gc.C) {
   142  	w := presence.NewWatcher(s.presence, s.modelTag)
   143  	pa := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   144  	pb := presence.NewPinger(s.presence, s.modelTag, "b", s.getDirectRecorder)
   145  	defer assertStopped(c, w)
   146  	defer assertStopped(c, pa)
   147  	defer assertStopped(c, pb)
   148  
   149  	assertAlive(c, w, "a", false)
   150  	assertAlive(c, w, "b", false)
   151  
   152  	// Buffer one entry to avoid blocking the watcher here.
   153  	cha := make(chan presence.Change, 1)
   154  	chb := make(chan presence.Change, 1)
   155  	w.Watch("a", cha)
   156  	w.Watch("b", chb)
   157  
   158  	// Initial events with current status.
   159  	assertChange(c, cha, presence.Change{"a", false})
   160  	assertChange(c, chb, presence.Change{"b", false})
   161  
   162  	w.StartSync()
   163  	assertNoChange(c, cha)
   164  	assertNoChange(c, chb)
   165  
   166  	c.Assert(pa.Start(), gc.IsNil)
   167  
   168  	w.StartSync()
   169  	assertChange(c, cha, presence.Change{"a", true})
   170  	assertNoChange(c, cha)
   171  	assertNoChange(c, chb)
   172  
   173  	assertAlive(c, w, "a", true)
   174  	assertAlive(c, w, "b", false)
   175  
   176  	// Changes while the channel is out are not observed.
   177  	w.Unwatch("a", cha)
   178  	assertNoChange(c, cha)
   179  	pa.KillForTesting()
   180  	w.Sync()
   181  	pa = presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   182  	pa.Start()
   183  	w.StartSync()
   184  	assertNoChange(c, cha)
   185  
   186  	// We can still query it manually, though.
   187  	assertAlive(c, w, "a", true)
   188  	assertAlive(c, w, "b", false)
   189  
   190  	// Initial positive event. No refresh needed.
   191  	w.Watch("a", cha)
   192  	assertChange(c, cha, presence.Change{"a", true})
   193  
   194  	c.Assert(pb.Start(), gc.IsNil)
   195  
   196  	w.StartSync()
   197  	assertChange(c, chb, presence.Change{"b", true})
   198  	assertNoChange(c, cha)
   199  	assertNoChange(c, chb)
   200  
   201  	c.Assert(pa.Stop(), gc.IsNil)
   202  
   203  	w.StartSync()
   204  	assertNoChange(c, cha)
   205  	assertNoChange(c, chb)
   206  
   207  	// pb is running, pa isn't.
   208  	c.Assert(pa.KillForTesting(), gc.IsNil)
   209  	c.Assert(pb.KillForTesting(), gc.IsNil)
   210  
   211  	w.StartSync()
   212  	assertChange(c, cha, presence.Change{"a", false})
   213  	assertChange(c, chb, presence.Change{"b", false})
   214  
   215  	assertStopped(c, w)
   216  }
   217  
   218  func (s *PresenceSuite) TestScale(c *gc.C) {
   219  	const N = 1000
   220  	var ps []*presence.Pinger
   221  	defer func() {
   222  		for _, p := range ps {
   223  			p.Stop()
   224  		}
   225  	}()
   226  
   227  	c.Logf("Starting %d pingers...", N)
   228  	for i := 0; i < N; i++ {
   229  		p := presence.NewPinger(s.presence, s.modelTag, strconv.Itoa(i), s.getDirectRecorder)
   230  		c.Assert(p.Start(), gc.IsNil)
   231  		ps = append(ps, p)
   232  	}
   233  
   234  	c.Logf("Killing odd ones...")
   235  	for i := 1; i < N; i += 2 {
   236  		c.Assert(ps[i].KillForTesting(), gc.IsNil)
   237  	}
   238  
   239  	c.Logf("Checking who's still alive...")
   240  	w := presence.NewWatcher(s.presence, s.modelTag)
   241  	defer assertStopped(c, w)
   242  	w.Sync()
   243  	ch := make(chan presence.Change)
   244  	for i := 0; i < N; i++ {
   245  		k := strconv.Itoa(i)
   246  		w.Watch(k, ch)
   247  		if i%2 == 0 {
   248  			assertChange(c, ch, presence.Change{k, true})
   249  		} else {
   250  			assertChange(c, ch, presence.Change{k, false})
   251  		}
   252  	}
   253  }
   254  
   255  func (s *PresenceSuite) TestExpiry(c *gc.C) {
   256  	w := presence.NewWatcher(s.presence, s.modelTag)
   257  	p := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   258  	defer assertStopped(c, w)
   259  	defer assertStopped(c, p)
   260  
   261  	ch := make(chan presence.Change)
   262  	w.Watch("a", ch)
   263  	assertChange(c, ch, presence.Change{"a", false})
   264  
   265  	c.Assert(p.Start(), gc.IsNil)
   266  	w.StartSync()
   267  	assertChange(c, ch, presence.Change{"a", true})
   268  
   269  	// Still alive in previous slot.
   270  	presence.FakeTimeSlot(1)
   271  	w.StartSync()
   272  	assertNoChange(c, ch)
   273  
   274  	// Two last slots are empty.
   275  	presence.FakeTimeSlot(2)
   276  	w.StartSync()
   277  	assertChange(c, ch, presence.Change{"a", false})
   278  
   279  	// Already dead so killing isn't noticed.
   280  	p.KillForTesting()
   281  	w.StartSync()
   282  	assertNoChange(c, ch)
   283  }
   284  
   285  func (s *PresenceSuite) TestWatchPeriod(c *gc.C) {
   286  	presence.FakePeriod(1)
   287  	presence.RealTimeSlot()
   288  
   289  	w := presence.NewWatcher(s.presence, s.modelTag)
   290  	p := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   291  	defer assertStopped(c, w)
   292  	defer assertStopped(c, p)
   293  
   294  	ch := make(chan presence.Change)
   295  	w.Watch("a", ch)
   296  	assertChange(c, ch, presence.Change{"a", false})
   297  
   298  	// A single ping.
   299  	c.Assert(p.Start(), gc.IsNil)
   300  	c.Assert(p.Stop(), gc.IsNil)
   301  
   302  	// Wait for next periodic refresh.
   303  	time.Sleep(1 * time.Second)
   304  	assertChange(c, ch, presence.Change{"a", true})
   305  }
   306  
   307  func (s *PresenceSuite) TestWatchUnwatchOnQueue(c *gc.C) {
   308  	w := presence.NewWatcher(s.presence, s.modelTag)
   309  	defer assertStopped(c, w)
   310  	ch := make(chan presence.Change, 100)
   311  	for i := 0; i < 100; i++ {
   312  		key := strconv.Itoa(i)
   313  		c.Logf("Adding %q", key)
   314  		w.Watch(key, ch)
   315  	}
   316  	for i := 1; i < 100; i += 2 {
   317  		key := strconv.Itoa(i)
   318  		c.Logf("Removing %q", key)
   319  		w.Unwatch(key, ch)
   320  	}
   321  	alive := make(map[string]bool)
   322  	for i := 0; i < 50; i++ {
   323  		change := <-ch
   324  		c.Logf("Got change for %q: %v", change.Key, change.Alive)
   325  		alive[change.Key] = change.Alive
   326  	}
   327  	for i := 0; i < 100; i += 2 {
   328  		key := strconv.Itoa(i)
   329  		c.Logf("Checking %q...", key)
   330  		c.Assert(alive[key], jc.IsFalse)
   331  	}
   332  }
   333  
   334  func (s *PresenceSuite) TestRestartWithoutGaps(c *gc.C) {
   335  	p := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   336  	c.Assert(p.Start(), gc.IsNil)
   337  	defer assertStopped(c, p)
   338  
   339  	done := make(chan bool)
   340  	go func() {
   341  		stop := false
   342  		for !stop {
   343  			if !c.Check(p.Stop(), gc.IsNil) {
   344  				break
   345  			}
   346  			if !c.Check(p.Start(), gc.IsNil) {
   347  				break
   348  			}
   349  			select {
   350  			case stop = <-done:
   351  			default:
   352  			}
   353  		}
   354  	}()
   355  	go func() {
   356  		stop := false
   357  		for !stop {
   358  			w := presence.NewWatcher(s.presence, s.modelTag)
   359  			w.Sync()
   360  			alive, err := w.Alive("a")
   361  			assertStopped(c, w)
   362  			if !c.Check(err, jc.ErrorIsNil) || !c.Check(alive, jc.IsTrue) {
   363  				break
   364  			}
   365  			select {
   366  			case stop = <-done:
   367  			default:
   368  			}
   369  		}
   370  	}()
   371  	// TODO(jam): This forceful delay of 500ms sounds like a bad test,
   372  	//  since we always sleep for the full timeout
   373  	time.Sleep(500 * time.Millisecond)
   374  	done <- true
   375  	done <- true
   376  }
   377  
   378  func (s *PresenceSuite) TestPingerPeriodAndResilience(c *gc.C) {
   379  	// This test verifies both the periodic pinging,
   380  	// and also a great property of the design: deaths
   381  	// also expire, which means erroneous scenarios are
   382  	// automatically recovered from.
   383  
   384  	const period = 1
   385  	presence.FakePeriod(period)
   386  	presence.RealTimeSlot()
   387  
   388  	w := presence.NewWatcher(s.presence, s.modelTag)
   389  	p1 := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   390  	p2 := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   391  	defer assertStopped(c, w)
   392  	defer assertStopped(c, p1)
   393  	defer assertStopped(c, p2)
   394  
   395  	// Start p1 and let it go on.
   396  	c.Assert(p1.Start(), gc.IsNil)
   397  
   398  	w.Sync()
   399  	assertAlive(c, w, "a", true)
   400  
   401  	// Start and kill p2, which will temporarily
   402  	// invalidate p1 and set the key as dead.
   403  	c.Assert(p2.Start(), gc.IsNil)
   404  	c.Assert(p2.KillForTesting(), gc.IsNil)
   405  
   406  	w.Sync()
   407  	assertAlive(c, w, "a", false)
   408  
   409  	// Wait for two periods, and check again. Since
   410  	// p1 is still alive, p2's death will expire and
   411  	// the key will come back.
   412  	time.Sleep(period * 2 * time.Second)
   413  
   414  	w.Sync()
   415  	assertAlive(c, w, "a", true)
   416  }
   417  
   418  func (s *PresenceSuite) TestStartSync(c *gc.C) {
   419  	w := presence.NewWatcher(s.presence, s.modelTag)
   420  	p := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   421  	defer assertStopped(c, w)
   422  	defer assertStopped(c, p)
   423  
   424  	ch := make(chan presence.Change)
   425  	w.Watch("a", ch)
   426  	assertChange(c, ch, presence.Change{"a", false})
   427  
   428  	c.Assert(p.Start(), gc.IsNil)
   429  
   430  	done := make(chan bool)
   431  	go func() {
   432  		w.StartSync()
   433  		w.StartSync()
   434  		w.StartSync()
   435  		done <- true
   436  	}()
   437  
   438  	select {
   439  	case <-done:
   440  	case <-time.After(testing.LongWait):
   441  		c.Fatalf("StartSync failed to return")
   442  	}
   443  
   444  	assertChange(c, ch, presence.Change{"a", true})
   445  }
   446  
   447  func (s *PresenceSuite) TestSync(c *gc.C) {
   448  	w := presence.NewWatcher(s.presence, s.modelTag)
   449  	p := presence.NewPinger(s.presence, s.modelTag, "a", s.getDirectRecorder)
   450  	defer assertStopped(c, w)
   451  	defer assertStopped(c, p)
   452  
   453  	ch := make(chan presence.Change)
   454  	w.Watch("a", ch)
   455  	assertChange(c, ch, presence.Change{"a", false})
   456  
   457  	// Nothing to do here.
   458  	w.Sync()
   459  
   460  	c.Assert(p.Start(), gc.IsNil)
   461  
   462  	done := make(chan bool)
   463  	go func() {
   464  		w.Sync()
   465  		done <- true
   466  	}()
   467  
   468  	select {
   469  	case <-done:
   470  		c.Fatalf("Sync returned too early")
   471  		// Note(jam): This used to wait 200ms to ensure that
   472  		// Sync was actually blocked waiting for a presence
   473  		// change. Is ShortWait long enough for this assurance?
   474  	case <-time.After(testing.ShortWait):
   475  	}
   476  
   477  	assertChange(c, ch, presence.Change{"a", true})
   478  
   479  	select {
   480  	case <-done:
   481  	case <-time.After(testing.LongWait):
   482  		c.Fatalf("Sync failed to returned")
   483  	}
   484  }
   485  
   486  func (s *PresenceSuite) TestTwoModels(c *gc.C) {
   487  	key := "a"
   488  	w1, p1, ch1 := s.setup(c, key)
   489  	defer assertStopped(c, w1)
   490  	defer assertStopped(c, p1)
   491  
   492  	w2, p2, ch2 := s.setup(c, key)
   493  	defer assertStopped(c, w2)
   494  	defer assertStopped(c, p2)
   495  
   496  	c.Assert(p1.Start(), gc.IsNil)
   497  	w1.StartSync()
   498  	w2.StartSync()
   499  	assertNoChange(c, ch2)
   500  	assertChange(c, ch1, presence.Change{"a", true})
   501  
   502  	c.Assert(p2.Start(), gc.IsNil)
   503  	w1.StartSync()
   504  	w2.StartSync()
   505  	assertNoChange(c, ch1)
   506  	assertChange(c, ch2, presence.Change{"a", true})
   507  
   508  	err := p1.KillForTesting()
   509  	c.Assert(err, jc.ErrorIsNil)
   510  	presence.FakeTimeSlot(1)
   511  	w1.StartSync()
   512  	w2.StartSync()
   513  	assertChange(c, ch1, presence.Change{"a", false})
   514  	assertNoChange(c, ch2)
   515  
   516  	err = p2.KillForTesting()
   517  	c.Assert(err, jc.ErrorIsNil)
   518  	presence.FakeTimeSlot(2)
   519  	w1.StartSync()
   520  	w2.StartSync()
   521  	assertChange(c, ch2, presence.Change{"a", false})
   522  	assertNoChange(c, ch1)
   523  }
   524  
   525  func newModelTag(c *gc.C) names.ModelTag {
   526  	uuid, err := utils.NewUUID()
   527  	c.Assert(err, jc.ErrorIsNil)
   528  	modelUUID := uuid.String()
   529  	return names.NewModelTag(modelUUID)
   530  }
   531  
   532  func (s *PresenceSuite) setup(c *gc.C, key string) (*presence.Watcher, *presence.Pinger, <-chan presence.Change) {
   533  	modelTag := newModelTag(c)
   534  
   535  	w := presence.NewWatcher(s.presence, modelTag)
   536  	p := presence.NewPinger(s.presence, modelTag, key, s.getDirectRecorder)
   537  
   538  	ch := make(chan presence.Change)
   539  	w.Watch(key, ch)
   540  	assertChange(c, ch, presence.Change{key, false})
   541  	return w, p, ch
   542  }
   543  
   544  func countModelIds(c *gc.C, coll *mgo.Collection, modelTag names.ModelTag) int {
   545  	count, err := coll.Find(bson.M{"_id": bson.RegEx{"^" + modelTag.Id() + ":", ""}}).Count()
   546  	// either the error is NotFound or nil
   547  	if err != nil {
   548  		c.Assert(err, gc.Equals, mgo.ErrNotFound)
   549  	}
   550  	return count
   551  }
   552  
   553  func (s *PresenceSuite) TestRemovePresenceForModel(c *gc.C) {
   554  	key := "a"
   555  
   556  	// Start a pinger in this model
   557  	w1 := presence.NewWatcher(s.presence, s.modelTag)
   558  	p1 := presence.NewPinger(s.presence, s.modelTag, key, s.getDirectRecorder)
   559  	ch1 := make(chan presence.Change)
   560  	w1.Watch(key, ch1)
   561  	assertChange(c, ch1, presence.Change{key, false})
   562  	defer assertStopped(c, w1)
   563  	defer assertStopped(c, p1)
   564  	p1.Start()
   565  	w1.StartSync()
   566  	assertChange(c, ch1, presence.Change{"a", true})
   567  
   568  	// Start a second model and pinger with the same key
   569  	modelTag2 := newModelTag(c)
   570  	w2 := presence.NewWatcher(s.presence, modelTag2)
   571  	p2 := presence.NewPinger(s.presence, modelTag2, key, s.getDirectRecorder)
   572  	ch2 := make(chan presence.Change)
   573  	w2.Watch(key, ch2)
   574  	assertChange(c, ch2, presence.Change{key, false})
   575  	defer assertStopped(c, w2)
   576  	defer assertStopped(c, p2)
   577  	// Start them, and check that we see they're alive
   578  	p2.Start()
   579  	w2.StartSync()
   580  	assertChange(c, ch2, presence.Change{"a", true})
   581  
   582  	beings := s.presence.Database.C(s.presence.Name + ".beings")
   583  	pings := s.presence.Database.C(s.presence.Name + ".pings")
   584  	seqs := s.presence.Database.C(s.presence.Name + ".seqs")
   585  	// we should have a being and pings for both pingers
   586  	c.Check(countModelIds(c, beings, s.modelTag), gc.Equals, 1)
   587  	c.Check(countModelIds(c, beings, modelTag2), gc.Equals, 1)
   588  	c.Check(countModelIds(c, pings, s.modelTag), jc.GreaterThan, 0)
   589  	c.Check(countModelIds(c, pings, modelTag2), jc.GreaterThan, 0)
   590  	c.Check(countModelIds(c, seqs, s.modelTag), gc.Equals, 1)
   591  	c.Check(countModelIds(c, seqs, modelTag2), gc.Equals, 1)
   592  
   593  	// kill everything in the first model
   594  	assertStopped(c, w1)
   595  	assertStopped(c, p1)
   596  	// And cleanup the resources
   597  	err := presence.RemovePresenceForModel(s.presence, s.modelTag)
   598  	c.Assert(err, jc.ErrorIsNil)
   599  
   600  	// Should not cause the second pinger to go dead
   601  	w2.StartSync()
   602  	assertNoChange(c, ch2)
   603  
   604  	// And we should only have the second model in the databases
   605  	c.Check(countModelIds(c, beings, s.modelTag), gc.Equals, 0)
   606  	c.Check(countModelIds(c, beings, modelTag2), gc.Equals, 1)
   607  	c.Check(countModelIds(c, pings, s.modelTag), gc.Equals, 0)
   608  	c.Check(countModelIds(c, pings, modelTag2), jc.GreaterThan, 0)
   609  	c.Check(countModelIds(c, seqs, s.modelTag), gc.Equals, 0)
   610  	c.Check(countModelIds(c, seqs, modelTag2), gc.Equals, 1)
   611  
   612  	// Removing a Model that is no longer there should not be an error
   613  	err = presence.RemovePresenceForModel(s.presence, s.modelTag)
   614  	c.Assert(err, jc.ErrorIsNil)
   615  }
   616  
   617  func (s *PresenceSuite) TestMultiplePingersForEntity(c *gc.C) {
   618  	// We should be able to track multiple sequences for a given Entity, without having to reread the database all the time
   619  	key := "a"
   620  
   621  	// Start a pinger in this model
   622  	w := presence.NewWatcher(s.presence, s.modelTag)
   623  	defer assertStopped(c, w)
   624  	p1 := presence.NewPinger(s.presence, s.modelTag, key, s.getDirectRecorder)
   625  	p1.Start()
   626  	assertStopped(c, p1)
   627  	p2 := presence.NewPinger(s.presence, s.modelTag, key, s.getDirectRecorder)
   628  	p2.Start()
   629  	assertStopped(c, p2)
   630  	p3 := presence.NewPinger(s.presence, s.modelTag, key, s.getDirectRecorder)
   631  	p3.Start()
   632  	assertStopped(c, p3)
   633  	w.Sync()
   634  	loads := w.BeingLoads()
   635  	c.Check(loads, jc.GreaterThan, uint64(0))
   636  	alive, err := w.Alive(key)
   637  	c.Assert(err, jc.ErrorIsNil)
   638  	c.Check(alive, jc.IsTrue)
   639  	// When we sync a second time, all of the above entities should already be cached, so we don't have to load them again
   640  	w.Sync()
   641  	c.Check(w.BeingLoads(), gc.Equals, loads)
   642  }
   643  
   644  func (s *PresenceSuite) TestRobustness(c *gc.C) {
   645  	// There used to be a potential condition, where during a flush() we wait for a channel send, and while we're
   646  	// waiting for it, we would handle events, which might cause us to grow our pending array, which would realloc
   647  	// the slice. If while that happened the original watch was unwatched, then we nil the channel, but the object
   648  	// we were hung pending on part of the reallocated slice.
   649  	w := presence.NewWatcher(s.presence, s.modelTag)
   650  	defer assertStopped(c, w)
   651  	// Start a watch for changes to 'key'. Never listen for actual events on that channel, though, so we know flush()
   652  	// will always be blocked, but allowing other events while waiting to send that event.
   653  	rootKey := "key"
   654  	keyChan := make(chan presence.Change, 0)
   655  	w.Watch(rootKey, keyChan)
   656  	// Whenever we successfully watch in the main loop(), it starts a flush. We should now be able to build up more
   657  	// watches while waiting. Create enough of these that we know the slice gets reallocated
   658  	var wg sync.WaitGroup
   659  	defer wg.Wait()
   660  	var observed uint32
   661  	const numKeys = 10
   662  	for i := 0; i < numKeys; i++ {
   663  		k := fmt.Sprintf("k%d", i)
   664  		kChan := make(chan presence.Change, 0)
   665  		w.Watch("key", kChan)
   666  		wg.Add(1)
   667  		go func() {
   668  			defer wg.Done()
   669  			select {
   670  			case <-kChan:
   671  				atomic.AddUint32(&observed, 1)
   672  				return
   673  			case <-time.After(testing.LongWait):
   674  				c.Fatalf("timed out waiting %s for %q to see its event", testing.LongWait, k)
   675  			}
   676  		}()
   677  	}
   678  	// None of them should actually have triggered, since the very first pending object has not been listened to
   679  	// And now we unwatch that object
   680  	time.Sleep(testing.ShortWait)
   681  	c.Check(atomic.LoadUint32(&observed), gc.Equals, uint32(0))
   682  	w.Unwatch(rootKey, keyChan)
   683  	// This should unblock all of them, and everything should go to observed
   684  	failTime := time.After(testing.LongWait)
   685  	o := atomic.LoadUint32(&observed)
   686  	for o != numKeys {
   687  		select {
   688  		case <-time.After(time.Millisecond):
   689  			o = atomic.LoadUint32(&observed)
   690  		case <-failTime:
   691  			c.Fatalf("only observed %d changes (expected %d) after %s time", atomic.LoadUint32(&observed), numKeys, testing.LongWait)
   692  		}
   693  	}
   694  	c.Check(atomic.LoadUint32(&observed), gc.Equals, uint32(numKeys))
   695  }