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 }