github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/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{Holder: "sgt-howie", Duration: 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{Holder: "rowan", Duration: 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 } 100 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 101 b1 := newBlockTest(c, manager, lease1) 102 b2 := newBlockTest(c, manager, lease2) 103 104 b1.assertBlocked(c) 105 b2.assertBlocked(c) 106 107 clock.Advance(2 * time.Second) 108 109 err := b1.assertUnblocked(c) 110 c.Assert(err, jc.ErrorIsNil) 111 b2.assertBlocked(c) 112 }) 113 } 114 115 func (s *CrossSuite) TestWaitAcrossNamespaces(c *gc.C) { 116 s.testWaits(c, 117 key("ns1", "model", "summerisle"), 118 key("ns2", "model", "summerisle"), 119 ) 120 } 121 122 func (s *CrossSuite) TestWaitAcrossModels(c *gc.C) { 123 s.testWaits(c, 124 key("ns", "model1", "summerisle"), 125 key("ns", "model2", "summerisle"), 126 ) 127 } 128 129 func (s *CrossSuite) testChecks(c *gc.C, lease1, lease2 corelease.Key) { 130 fix := Fixture{ 131 leases: map[corelease.Key]corelease.Info{ 132 lease1: { 133 Holder: "sgt-howie", 134 Expiry: offset(time.Second), 135 }, 136 }, 137 } 138 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 139 checker1, err := manager.Checker(lease1.Namespace, lease1.ModelUUID) 140 c.Assert(err, jc.ErrorIsNil) 141 checker2, err := manager.Checker(lease2.Namespace, lease2.ModelUUID) 142 c.Assert(err, jc.ErrorIsNil) 143 144 t1 := checker1.Token(lease1.Lease, "sgt-howie") 145 c.Assert(t1.Check(), gc.Equals, nil) 146 147 t2 := checker2.Token(lease2.Lease, "sgt-howie") 148 err = t2.Check() 149 c.Assert(errors.Cause(err), gc.Equals, corelease.ErrNotHeld) 150 }) 151 } 152 153 func (s *CrossSuite) TestCheckAcrossNamespaces(c *gc.C) { 154 s.testChecks(c, 155 key("ns1", "model", "summerisle"), 156 key("ns2", "model", "summerisle"), 157 ) 158 } 159 160 func (s *CrossSuite) TestCheckAcrossModels(c *gc.C) { 161 s.testChecks(c, 162 key("ns", "model1", "summerisle"), 163 key("ns", "model2", "summerisle"), 164 ) 165 } 166 167 func (s *CrossSuite) TestDifferentNamespaceValidation(c *gc.C) { 168 clock := testclock.NewClock(defaultClockStart) 169 store := NewStore(nil, nil, clock) 170 manager, err := lease.NewManager(lease.ManagerConfig{ 171 Clock: clock, 172 Store: store, 173 Secretary: func(namespace string) (lease.Secretary, error) { 174 switch namespace { 175 case "ns1": 176 return Secretary{}, nil 177 case "ns2": 178 return OtherSecretary{}, nil 179 default: 180 return nil, errors.Errorf("bad namespace!") 181 } 182 }, 183 MaxSleep: defaultMaxSleep, 184 Logger: loggo.GetLogger("lease_test"), 185 PrometheusRegisterer: noopRegisterer{}, 186 }) 187 c.Assert(err, jc.ErrorIsNil) 188 defer func() { 189 manager.Kill() 190 err := manager.Wait() 191 c.Check(err, jc.ErrorIsNil) 192 }() 193 defer store.Wait(c) 194 195 _, err = manager.Claimer("something-else", "model") 196 c.Assert(err, gc.ErrorMatches, "bad namespace!") 197 198 c1, err := manager.Claimer("ns1", "model") 199 c.Assert(err, jc.ErrorIsNil) 200 err = c1.Claim("INVALID", "sgt-howie", time.Minute) 201 c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": name not valid`) 202 203 c2, err := manager.Claimer("ns2", "model") 204 c.Assert(err, jc.ErrorIsNil) 205 err = c2.Claim("INVALID", "sgt-howie", time.Minute) 206 c.Assert(err, gc.ErrorMatches, `cannot claim lease "INVALID": lease name not valid`) 207 } 208 209 type OtherSecretary struct{} 210 211 // CheckLease is part of the lease.Secretary interface. 212 func (OtherSecretary) CheckLease(_ corelease.Key) error { 213 return errors.NotValidf("lease name") 214 } 215 216 // CheckHolder is part of the lease.Secretary interface. 217 func (OtherSecretary) CheckHolder(_ string) error { 218 return errors.NotValidf("holder name") 219 } 220 221 // CheckDuration is part of the lease.Secretary interface. 222 func (OtherSecretary) CheckDuration(duration time.Duration) error { 223 if duration != time.Hour { 224 return errors.NotValidf("time") 225 } 226 return nil 227 }