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