github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/lease/manager_claim_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lease_test 5 6 import ( 7 "sync" 8 "time" 9 10 "github.com/juju/clock/testclock" 11 "github.com/juju/errors" 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 type ClaimSuite struct { 21 testing.IsolationSuite 22 } 23 24 var _ = gc.Suite(&ClaimSuite{}) 25 26 func (s *ClaimSuite) TestClaimLease_Success(c *gc.C) { 27 fix := &Fixture{ 28 expectCalls: []call{{ 29 method: "ClaimLease", 30 args: []interface{}{ 31 corelease.Key{ 32 Namespace: "namespace", 33 ModelUUID: "modelUUID", 34 Lease: "redis", 35 }, 36 corelease.Request{"redis/0", time.Minute}, 37 }, 38 }}, 39 } 40 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 41 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 42 c.Check(err, jc.ErrorIsNil) 43 }) 44 } 45 46 func (s *ClaimSuite) TestClaimLease_Success_SameHolder(c *gc.C) { 47 fix := &Fixture{ 48 expectCalls: []call{{ 49 method: "ClaimLease", 50 args: []interface{}{ 51 corelease.Key{ 52 Namespace: "namespace", 53 ModelUUID: "modelUUID", 54 Lease: "redis", 55 }, 56 corelease.Request{"redis/0", time.Minute}, 57 }, 58 err: corelease.ErrInvalid, 59 callback: func(leases map[corelease.Key]corelease.Info) { 60 leases[key("redis")] = corelease.Info{ 61 Holder: "redis/0", 62 Expiry: offset(time.Second), 63 } 64 }, 65 }, { 66 method: "ExtendLease", 67 args: []interface{}{ 68 corelease.Key{ 69 Namespace: "namespace", 70 ModelUUID: "modelUUID", 71 Lease: "redis", 72 }, 73 corelease.Request{"redis/0", time.Minute}, 74 }, 75 }}, 76 } 77 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 78 // On the first attempt, we don't see ourselves in the leases, so we try 79 // to Claim the lease. But Primary thinks we already have the lease, so it 80 // refuses. After claiming, we wait 50ms to let the refresh happen, then 81 // we notice that we are the holder, so we Extend instead of Claim. 82 var wg sync.WaitGroup 83 wg.Add(1) 84 go func() { 85 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 86 c.Check(err, jc.ErrorIsNil) 87 wg.Done() 88 }() 89 c.Check(clock.WaitAdvance(50*time.Millisecond, testing.LongWait, 2), jc.ErrorIsNil) 90 wg.Wait() 91 }) 92 } 93 94 func (s *ClaimSuite) TestClaimLease_Failure_OtherHolder(c *gc.C) { 95 fix := &Fixture{ 96 expectCalls: []call{{ 97 method: "ClaimLease", 98 args: []interface{}{ 99 corelease.Key{ 100 Namespace: "namespace", 101 ModelUUID: "modelUUID", 102 Lease: "redis", 103 }, 104 corelease.Request{"redis/0", time.Minute}, 105 }, 106 err: corelease.ErrInvalid, 107 callback: func(leases map[corelease.Key]corelease.Info) { 108 leases[key("redis")] = corelease.Info{ 109 Holder: "redis/1", 110 Expiry: offset(time.Second), 111 } 112 }, 113 }}, 114 } 115 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 116 // When the Claim starts, it will first get a LeaseInvalid, it will then 117 // wait 50ms before trying again, since it is clear that our Leases map 118 // does not have the most up-to-date information. We then wake up again 119 // and see that our leases have expired and thus let things go. 120 var wg sync.WaitGroup 121 wg.Add(1) 122 go func() { 123 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 124 c.Check(err, gc.Equals, corelease.ErrClaimDenied) 125 wg.Done() 126 }() 127 c.Check(clock.WaitAdvance(50*time.Millisecond, testing.LongWait, 2), jc.ErrorIsNil) 128 wg.Wait() 129 }) 130 } 131 132 func (s *ClaimSuite) TestClaimLease_Failure_Error(c *gc.C) { 133 fix := &Fixture{ 134 expectCalls: []call{{ 135 method: "ClaimLease", 136 args: []interface{}{ 137 corelease.Key{ 138 Namespace: "namespace", 139 ModelUUID: "modelUUID", 140 Lease: "redis", 141 }, 142 corelease.Request{"redis/0", time.Minute}, 143 }, 144 err: errors.New("lol borken"), 145 }}, 146 expectDirty: true, 147 } 148 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 149 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 150 c.Check(err, gc.ErrorMatches, "lease manager stopped") 151 err = manager.Wait() 152 c.Check(err, gc.ErrorMatches, "lol borken") 153 }) 154 } 155 156 func (s *ClaimSuite) TestExtendLease_Success(c *gc.C) { 157 fix := &Fixture{ 158 leases: map[corelease.Key]corelease.Info{ 159 key("redis"): { 160 Holder: "redis/0", 161 Expiry: offset(time.Second), 162 }, 163 }, 164 expectCalls: []call{{ 165 method: "ExtendLease", 166 args: []interface{}{ 167 corelease.Key{ 168 Namespace: "namespace", 169 ModelUUID: "modelUUID", 170 Lease: "redis", 171 }, 172 corelease.Request{"redis/0", time.Minute}, 173 }, 174 }}, 175 } 176 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 177 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 178 c.Check(err, jc.ErrorIsNil) 179 }) 180 } 181 182 func (s *ClaimSuite) TestExtendLease_Success_Expired(c *gc.C) { 183 fix := &Fixture{ 184 leases: map[corelease.Key]corelease.Info{ 185 key("redis"): { 186 Holder: "redis/0", 187 Expiry: offset(time.Second), 188 }, 189 }, 190 expectCalls: []call{{ 191 method: "ExtendLease", 192 args: []interface{}{ 193 corelease.Key{ 194 Namespace: "namespace", 195 ModelUUID: "modelUUID", 196 Lease: "redis", 197 }, 198 corelease.Request{"redis/0", time.Minute}, 199 }, 200 err: corelease.ErrInvalid, 201 callback: func(leases map[corelease.Key]corelease.Info) { 202 delete(leases, key("redis")) 203 }, 204 }, { 205 method: "ClaimLease", 206 args: []interface{}{ 207 corelease.Key{ 208 Namespace: "namespace", 209 ModelUUID: "modelUUID", 210 Lease: "redis", 211 }, 212 corelease.Request{"redis/0", time.Minute}, 213 }, 214 }}, 215 } 216 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 217 // On the first attempt, we think we are the holder, but Primary says "nope". 218 // So we wait 50ms for the Leases to get updated. At which point, we have 219 // reloaded our Leases and see that *nobody* is the holder. So then we try 220 // again and successfully Claim the lease. 221 var wg sync.WaitGroup 222 wg.Add(1) 223 go func() { 224 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 225 c.Check(err, jc.ErrorIsNil) 226 wg.Done() 227 }() 228 c.Check(clock.WaitAdvance(50*time.Millisecond, testing.LongWait, 2), jc.ErrorIsNil) 229 wg.Wait() 230 }) 231 } 232 233 func (s *ClaimSuite) TestExtendLease_Failure_OtherHolder(c *gc.C) { 234 fix := &Fixture{ 235 leases: map[corelease.Key]corelease.Info{ 236 key("redis"): { 237 Holder: "redis/0", 238 Expiry: offset(time.Second), 239 }, 240 }, 241 expectCalls: []call{{ 242 method: "ExtendLease", 243 args: []interface{}{ 244 corelease.Key{ 245 Namespace: "namespace", 246 ModelUUID: "modelUUID", 247 Lease: "redis", 248 }, 249 corelease.Request{"redis/0", time.Minute}, 250 }, 251 err: corelease.ErrInvalid, 252 callback: func(leases map[corelease.Key]corelease.Info) { 253 leases[key("redis")] = corelease.Info{ 254 Holder: "redis/1", 255 Expiry: offset(time.Second), 256 } 257 }, 258 }}, 259 } 260 fix.RunTest(c, func(manager *lease.Manager, clock *testclock.Clock) { 261 // When the Claim starts, it will first get a LeaseInvalid, it will then 262 // wait 50ms before trying again, since it is clear that our Leases map 263 // does not have the most up-to-date information. We then wake up again 264 // and see that our leases have expired and thus let things go. 265 var wg sync.WaitGroup 266 wg.Add(1) 267 go func() { 268 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 269 c.Check(err, gc.Equals, corelease.ErrClaimDenied) 270 wg.Done() 271 }() 272 c.Check(clock.WaitAdvance(50*time.Millisecond, testing.LongWait, 2), jc.ErrorIsNil) 273 wg.Wait() 274 }) 275 } 276 277 func (s *ClaimSuite) TestExtendLease_Failure_Error(c *gc.C) { 278 fix := &Fixture{ 279 leases: map[corelease.Key]corelease.Info{ 280 key("redis"): { 281 Holder: "redis/0", 282 Expiry: offset(time.Second), 283 }, 284 }, 285 expectCalls: []call{{ 286 method: "ExtendLease", 287 args: []interface{}{ 288 key("redis"), 289 corelease.Request{"redis/0", time.Minute}, 290 }, 291 err: errors.New("boom splat"), 292 }}, 293 expectDirty: true, 294 } 295 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 296 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 297 c.Check(err, gc.ErrorMatches, "lease manager stopped") 298 err = manager.Wait() 299 c.Check(err, gc.ErrorMatches, "boom splat") 300 }) 301 } 302 303 func (s *ClaimSuite) TestOtherHolder_Failure(c *gc.C) { 304 fix := &Fixture{ 305 leases: map[corelease.Key]corelease.Info{ 306 key("redis"): { 307 Holder: "redis/1", 308 Expiry: offset(time.Second), 309 }, 310 }, 311 } 312 fix.RunTest(c, func(manager *lease.Manager, _ *testclock.Clock) { 313 err := getClaimer(c, manager).Claim("redis", "redis/0", time.Minute) 314 c.Check(err, gc.Equals, corelease.ErrClaimDenied) 315 }) 316 } 317 318 func getClaimer(c *gc.C, manager *lease.Manager) corelease.Claimer { 319 claimer, err := manager.Claimer("namespace", "modelUUID") 320 c.Assert(err, jc.ErrorIsNil) 321 return claimer 322 }