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