github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/presence/presence_test.go (about)

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