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