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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/errors"
    10  	jujutesting "github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/mgo.v2/txn"
    14  
    15  	"github.com/juju/juju/core/leadership"
    16  	coretesting "github.com/juju/juju/testing"
    17  )
    18  
    19  type LeadershipSuite struct {
    20  	ConnSuite
    21  	clock   *jujutesting.Clock
    22  	checker leadership.Checker
    23  	claimer leadership.Claimer
    24  }
    25  
    26  var _ = gc.Suite(&LeadershipSuite{})
    27  
    28  func (s *LeadershipSuite) SetUpTest(c *gc.C) {
    29  	s.ConnSuite.SetUpTest(c)
    30  	s.clock = jujutesting.NewClock(time.Now())
    31  	err := s.State.SetClockForTesting(s.clock)
    32  	c.Assert(err, jc.ErrorIsNil)
    33  	s.checker = s.State.LeadershipChecker()
    34  	s.claimer = s.State.LeadershipClaimer()
    35  }
    36  
    37  func (s *LeadershipSuite) TestClaimValidatesApplicationname(c *gc.C) {
    38  	err := s.claimer.ClaimLeadership("not/a/service", "u/0", time.Minute)
    39  	c.Check(err, gc.ErrorMatches, `cannot claim lease "not/a/service": not an application name`)
    40  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    41  }
    42  
    43  func (s *LeadershipSuite) TestClaimValidatesUnitName(c *gc.C) {
    44  	err := s.claimer.ClaimLeadership("application", "not/a/unit", time.Minute)
    45  	c.Check(err, gc.ErrorMatches, `cannot claim lease for holder "not/a/unit": not a unit name`)
    46  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    47  }
    48  
    49  func (s *LeadershipSuite) TestClaimValidateDuration(c *gc.C) {
    50  	err := s.claimer.ClaimLeadership("application", "u/0", 0)
    51  	c.Check(err, gc.ErrorMatches, `cannot claim lease for 0s?: non-positive`)
    52  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    53  }
    54  
    55  func (s *LeadershipSuite) TestCheckValidatesApplicationname(c *gc.C) {
    56  	token := s.checker.LeadershipCheck("not/a/service", "u/0")
    57  	err := token.Check(nil)
    58  	c.Check(err, gc.ErrorMatches, `cannot check lease "not/a/service": not an application name`)
    59  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    60  }
    61  
    62  func (s *LeadershipSuite) TestCheckValidatesUnitName(c *gc.C) {
    63  	token := s.checker.LeadershipCheck("application", "not/a/unit")
    64  	err := token.Check(nil)
    65  	c.Check(err, gc.ErrorMatches, `cannot check holder "not/a/unit": not a unit name`)
    66  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    67  }
    68  
    69  func (s *LeadershipSuite) TestBlockValidatesApplicationname(c *gc.C) {
    70  	err := s.claimer.BlockUntilLeadershipReleased("not/a/service")
    71  	c.Check(err, gc.ErrorMatches, `cannot wait for lease "not/a/service" expiry: not an application name`)
    72  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    73  }
    74  
    75  func (s *LeadershipSuite) TestClaimExpire(c *gc.C) {
    76  
    77  	// Claim on behalf of one unit.
    78  	err := s.claimer.ClaimLeadership("application", "application/0", time.Minute)
    79  	c.Assert(err, jc.ErrorIsNil)
    80  
    81  	// Claim on behalf of another.
    82  	err = s.claimer.ClaimLeadership("application", "service/1", time.Minute)
    83  	c.Check(err, gc.Equals, leadership.ErrClaimDenied)
    84  
    85  	// Allow the first claim to expire.
    86  	s.expire(c, "application")
    87  
    88  	// Reclaim on behalf of another.
    89  	err = s.claimer.ClaimLeadership("application", "service/1", time.Minute)
    90  	c.Assert(err, jc.ErrorIsNil)
    91  }
    92  
    93  func (s *LeadershipSuite) TestCheck(c *gc.C) {
    94  
    95  	// Create a single token for use by the whole test.
    96  	token := s.checker.LeadershipCheck("application", "application/0")
    97  
    98  	// Claim leadership.
    99  	err := s.claimer.ClaimLeadership("application", "application/0", time.Minute)
   100  	c.Assert(err, jc.ErrorIsNil)
   101  
   102  	// Check token reports current leadership state.
   103  	var ops []txn.Op
   104  	err = token.Check(&ops)
   105  	c.Check(err, jc.ErrorIsNil)
   106  	c.Check(ops, gc.HasLen, 1)
   107  
   108  	// Allow leadership to expire.
   109  	s.expire(c, "application")
   110  
   111  	// Check leadership still reported accurately.
   112  	var ops2 []txn.Op
   113  	err = token.Check(&ops2)
   114  	c.Check(err, gc.ErrorMatches, `"application/0" is not leader of "application"`)
   115  	c.Check(ops2, gc.IsNil)
   116  }
   117  
   118  func (s *LeadershipSuite) TestHackLeadershipUnblocksClaimer(c *gc.C) {
   119  	err := s.claimer.ClaimLeadership("blah", "blah/0", time.Minute)
   120  	c.Assert(err, jc.ErrorIsNil)
   121  
   122  	s.State.HackLeadership()
   123  	select {
   124  	case err := <-s.expiryChan("blah"):
   125  		c.Check(err, gc.ErrorMatches, "lease manager stopped")
   126  	case <-time.After(coretesting.LongWait):
   127  		c.Fatalf("timed out while waiting for unblock")
   128  	}
   129  }
   130  
   131  func (s *LeadershipSuite) TestApplicationLeaders(c *gc.C) {
   132  	err := s.claimer.ClaimLeadership("blah", "blah/0", time.Minute)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  	err = s.claimer.ClaimLeadership("application", "application/1", time.Minute)
   135  	c.Assert(err, jc.ErrorIsNil)
   136  
   137  	leaders, err := s.State.ApplicationLeaders()
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	c.Assert(leaders, jc.DeepEquals, map[string]string{
   140  		"application": "application/1",
   141  		"blah":        "blah/0",
   142  	})
   143  }
   144  
   145  func (s *LeadershipSuite) expire(c *gc.C, applicationname string) {
   146  	s.clock.Advance(time.Hour)
   147  	s.Session.Fsync(false)
   148  	select {
   149  	case err := <-s.expiryChan(applicationname):
   150  		c.Assert(err, jc.ErrorIsNil)
   151  	case <-time.After(coretesting.LongWait):
   152  		c.Fatalf("never unblocked")
   153  	}
   154  }
   155  
   156  func (s *LeadershipSuite) expiryChan(applicationname string) <-chan error {
   157  	expired := make(chan error, 1)
   158  	go func() {
   159  		expired <- s.claimer.BlockUntilLeadershipReleased("blah")
   160  	}()
   161  	return expired
   162  }