github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/lease/manager_cross_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lease_test 5 6 import ( 7 "time" 8 9 "github.com/juju/clock/testclock" 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 corelease "github.com/juju/juju/core/lease" 17 "github.com/juju/juju/worker/lease" 18 ) 19 20 // Tests that check the manager handles leases across namespaces and 21 // models correctly. 22 23 type CrossSuite struct { 24 testing.IsolationSuite 25 } 26 27 var _ = gc.Suite(&CrossSuite{}) 28 29 func (s *CrossSuite) testClaims(c *gc.C, lease1, lease2 corelease.Key) { 30 fix := Fixture{ 31 expectCalls: []call{{ 32 method: "ClaimLease", 33 args: []interface{}{ 34 lease1, 35 corelease.Request{"sgt-howie", time.Minute}, 36 }, 37 callback: func(leases map[corelease.Key]corelease.Info) { 38 leases[lease1] = corelease.Info{ 39 Holder: "sgt-howie", 40 Expiry: offset(time.Second), 41 } 42 }, 43 }, { 44 method: "ClaimLease", 45 args: []interface{}{ 46 lease2, 47 corelease.Request{"rowan", time.Minute}, 48 }, 49 callback: func(leases map[corelease.Key]corelease.Info) { 50 leases[lease2] = corelease.Info{ 51 Holder: "rowan", 52 Expiry: offset(time.Second), 53 } 54 }, 55 }}, 56 } 57 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 58 claimer1, err := manager.Claimer(lease1.Namespace, lease1.ModelUUID) 59 c.Assert(err, jc.ErrorIsNil) 60 claimer2, err := manager.Claimer(lease2.Namespace, lease2.ModelUUID) 61 c.Assert(err, jc.ErrorIsNil) 62 63 err = claimer1.Claim(lease1.Lease, "sgt-howie", time.Minute) 64 c.Assert(err, jc.ErrorIsNil) 65 err = claimer2.Claim(lease2.Lease, "rowan", time.Minute) 66 c.Assert(err, jc.ErrorIsNil) 67 68 err = claimer1.Claim(lease1.Lease, "lord-summerisle", time.Minute) 69 c.Assert(err, gc.Equals, corelease.ErrClaimDenied) 70 }) 71 } 72 73 func (s *CrossSuite) TestClaimAcrossNamespaces(c *gc.C) { 74 s.testClaims(c, 75 key("ns1", "model", "summerisle"), 76 key("ns2", "model", "summerisle"), 77 ) 78 } 79 80 func (s *CrossSuite) TestClaimAcrossModels(c *gc.C) { 81 s.testClaims(c, 82 key("ns", "model1", "summerisle"), 83 key("ns", "model2", "summerisle"), 84 ) 85 } 86 87 func (s *CrossSuite) testWaits(c *gc.C, lease1, lease2 corelease.Key) { 88 fix := Fixture{ 89 leases: map[corelease.Key]corelease.Info{ 90 lease1: { 91 Holder: "sgt-howie", 92 Expiry: offset(time.Second), 93 }, 94 lease2: { 95 Holder: "willow", 96 Expiry: offset(time.Minute), 97 }, 98 }, 99 expectCalls: []call{{ 100 method: "Refresh", 101 }, { 102 method: "ExpireLease", 103 args: []interface{}{lease1}, 104 callback: func(leases map[corelease.Key]corelease.Info) { 105 delete(leases, lease1) 106 }, 107 }}, 108 } 109 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 110 b1 := newBlockTest(c, manager, lease1) 111 b2 := newBlockTest(c, manager, lease2) 112 113 b1.assertBlocked(c) 114 b2.assertBlocked(c) 115 116 clock.Advance(time.Second) 117 118 err := b1.assertUnblocked(c) 119 c.Assert(err, jc.ErrorIsNil) 120 b2.assertBlocked(c) 121 }) 122 } 123 124 func (s *CrossSuite) TestWaitAcrossNamespaces(c *gc.C) { 125 s.testWaits(c, 126 key("ns1", "model", "summerisle"), 127 key("ns2", "model", "summerisle"), 128 ) 129 } 130 131 func (s *CrossSuite) TestWaitAcrossModels(c *gc.C) { 132 s.testWaits(c, 133 key("ns", "model1", "summerisle"), 134 key("ns", "model2", "summerisle"), 135 ) 136 } 137 138 func (s *CrossSuite) testChecks(c *gc.C, lease1, lease2 corelease.Key) { 139 fix := Fixture{ 140 leases: map[corelease.Key]corelease.Info{ 141 lease1: { 142 Holder: "sgt-howie", 143 Expiry: offset(time.Second), 144 Trapdoor: corelease.LockedTrapdoor, 145 }, 146 }, 147 expectCalls: []call{{ 148 method: "Refresh", 149 }}, 150 } 151 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 152 checker1, err := manager.Checker(lease1.Namespace, lease1.ModelUUID) 153 c.Assert(err, jc.ErrorIsNil) 154 checker2, err := manager.Checker(lease2.Namespace, lease2.ModelUUID) 155 c.Assert(err, jc.ErrorIsNil) 156 157 t1 := checker1.Token(lease1.Lease, "sgt-howie") 158 c.Assert(t1.Check(0, nil), gc.Equals, nil) 159 160 t2 := checker2.Token(lease2.Lease, "sgt-howie") 161 err = t2.Check(0, nil) 162 c.Assert(errors.Cause(err), gc.Equals, corelease.ErrNotHeld) 163 }) 164 } 165 166 func (s *CrossSuite) TestCheckAcrossNamespaces(c *gc.C) { 167 s.testChecks(c, 168 key("ns1", "model", "summerisle"), 169 key("ns2", "model", "summerisle"), 170 ) 171 } 172 173 func (s *CrossSuite) TestCheckAcrossModels(c *gc.C) { 174 s.testChecks(c, 175 key("ns", "model1", "summerisle"), 176 key("ns", "model2", "summerisle"), 177 ) 178 } 179 180 func (s *CrossSuite) TestDifferentNamespaceValidation(c *gc.C) { 181 clock := testclock.NewClock(defaultClockStart) 182 store := NewStore(false, nil, nil) 183 manager, err := lease.NewManager(lease.ManagerConfig{ 184 Clock: clock, 185 Store: store, 186 Secretary: func(namespace string) (lease.Secretary, error) { 187 switch namespace { 188 case "ns1": 189 return Secretary{}, nil 190 case "ns2": 191 return OtherSecretary{}, nil 192 default: 193 return nil, errors.Errorf("bad namespace!") 194 } 195 }, 196 MaxSleep: defaultMaxSleep, 197 Logger: loggo.GetLogger("lease_test"), 198 PrometheusRegisterer: noopRegisterer{}, 199 }) 200 c.Assert(err, jc.ErrorIsNil) 201 defer func() { 202 manager.Kill() 203 err := manager.Wait() 204 c.Check(err, jc.ErrorIsNil) 205 }() 206 defer store.Wait(c) 207 208 _, err = manager.Claimer("something-else", "model") 209 c.Assert(err, gc.ErrorMatches, "bad namespace!") 210 211 c1, err := manager.Claimer("ns1", "model") 212 c.Assert(err, jc.ErrorIsNil) 213 err = c1.Claim("INVALID", "sgt-howie", time.Minute) 214 c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": name not valid`) 215 216 c2, err := manager.Claimer("ns2", "model") 217 c.Assert(err, jc.ErrorIsNil) 218 err = c2.Claim("INVALID", "sgt-howie", time.Minute) 219 c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": lease name not valid`) 220 } 221 222 type OtherSecretary struct{} 223 224 // CheckLease is part of the lease.Secretary interface. 225 func (OtherSecretary) CheckLease(key corelease.Key) error { 226 return errors.NotValidf("lease name") 227 } 228 229 // CheckHolder is part of the lease.Secretary interface. 230 func (OtherSecretary) CheckHolder(name string) error { 231 return errors.NotValidf("holder name") 232 } 233 234 // CheckDuration is part of the lease.Secretary interface. 235 func (OtherSecretary) CheckDuration(duration time.Duration) error { 236 if duration != time.Hour { 237 return errors.NotValidf("time") 238 } 239 return nil 240 }