@@ -61,7 +61,7 @@ func TestWalkToRoot(t *testing.T) {
61
61
}
62
62
63
63
var lockTestDurations = []time.Duration {
64
- - 1 , // A negative duration means to never expire.
64
+ infiniteTimeout , // infiniteTimeout means to never expire.
65
65
0 , // A zero duration means to expire immediately.
66
66
100 * time .Hour , // A very large duration will not expire in these tests.
67
67
}
@@ -102,7 +102,7 @@ func TestMemLSCanCreate(t *testing.T) {
102
102
for _ , name := range lockTestNames {
103
103
_ , err := m .Create (now , LockDetails {
104
104
Root : name ,
105
- Duration : - 1 ,
105
+ Duration : infiniteTimeout ,
106
106
ZeroDepth : lockTestZeroDepth (name ),
107
107
})
108
108
if err != nil {
@@ -155,6 +155,147 @@ func TestMemLSCanCreate(t *testing.T) {
155
155
check (0 , "/" )
156
156
}
157
157
158
+ func TestMemLSLookup (t * testing.T ) {
159
+ now := time .Unix (0 , 0 )
160
+ m := NewMemLS ().(* memLS )
161
+
162
+ badToken := m .nextToken ()
163
+ t .Logf ("badToken=%q" , badToken )
164
+
165
+ for _ , name := range lockTestNames {
166
+ token , err := m .Create (now , LockDetails {
167
+ Root : name ,
168
+ Duration : infiniteTimeout ,
169
+ ZeroDepth : lockTestZeroDepth (name ),
170
+ })
171
+ if err != nil {
172
+ t .Fatalf ("creating lock for %q: %v" , name , err )
173
+ }
174
+ t .Logf ("%-15q -> node=%p token=%q" , name , m .byName [name ], token )
175
+ }
176
+
177
+ baseNames := append ([]string {"/a" , "/b/c" }, lockTestNames ... )
178
+ for _ , baseName := range baseNames {
179
+ for _ , suffix := range []string {"" , "/0" , "/1/2/3" } {
180
+ name := baseName + suffix
181
+
182
+ goodToken := ""
183
+ base := m .byName [baseName ]
184
+ if base != nil && (suffix == "" || ! lockTestZeroDepth (baseName )) {
185
+ goodToken = base .token
186
+ }
187
+
188
+ for _ , token := range []string {badToken , goodToken } {
189
+ if token == "" {
190
+ continue
191
+ }
192
+
193
+ got := m .lookup (name , Condition {Token : token })
194
+ want := base
195
+ if token == badToken {
196
+ want = nil
197
+ }
198
+ if got != want {
199
+ t .Errorf ("name=%-20qtoken=%q (bad=%t): got %p, want %p" ,
200
+ name , token , token == badToken , got , want )
201
+ }
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ func TestMemLSConfirm (t * testing.T ) {
208
+ now := time .Unix (0 , 0 )
209
+ m := NewMemLS ().(* memLS )
210
+ alice , err := m .Create (now , LockDetails {
211
+ Root : "/alice" ,
212
+ Duration : infiniteTimeout ,
213
+ ZeroDepth : false ,
214
+ })
215
+ tweedle , err := m .Create (now , LockDetails {
216
+ Root : "/tweedle" ,
217
+ Duration : infiniteTimeout ,
218
+ ZeroDepth : false ,
219
+ })
220
+ if err != nil {
221
+ t .Fatalf ("Create: %v" , err )
222
+ }
223
+ if err := m .consistent (); err != nil {
224
+ t .Fatalf ("Create: inconsistent state: %v" , err )
225
+ }
226
+
227
+ // Test a mismatch between name and condition.
228
+ _ , err = m .Confirm (now , "/tweedle/dee" , "" , Condition {Token : alice })
229
+ if err != ErrConfirmationFailed {
230
+ t .Fatalf ("Confirm (mismatch): got %v, want ErrConfirmationFailed" , err )
231
+ }
232
+ if err := m .consistent (); err != nil {
233
+ t .Fatalf ("Confirm (mismatch): inconsistent state: %v" , err )
234
+ }
235
+
236
+ // Test two names (that fall under the same lock) in the one Confirm call.
237
+ release , err := m .Confirm (now , "/tweedle/dee" , "/tweedle/dum" , Condition {Token : tweedle })
238
+ if err != nil {
239
+ t .Fatalf ("Confirm (twins): %v" , err )
240
+ }
241
+ if err := m .consistent (); err != nil {
242
+ t .Fatalf ("Confirm (twins): inconsistent state: %v" , err )
243
+ }
244
+ release ()
245
+ if err := m .consistent (); err != nil {
246
+ t .Fatalf ("release (twins): inconsistent state: %v" , err )
247
+ }
248
+
249
+ // Test the same two names in overlapping Confirm / release calls.
250
+ releaseDee , err := m .Confirm (now , "/tweedle/dee" , "" , Condition {Token : tweedle })
251
+ if err != nil {
252
+ t .Fatalf ("Confirm (sequence #0): %v" , err )
253
+ }
254
+ if err := m .consistent (); err != nil {
255
+ t .Fatalf ("Confirm (sequence #0): inconsistent state: %v" , err )
256
+ }
257
+
258
+ _ , err = m .Confirm (now , "/tweedle/dum" , "" , Condition {Token : tweedle })
259
+ if err != ErrConfirmationFailed {
260
+ t .Fatalf ("Confirm (sequence #1): got %v, want ErrConfirmationFailed" , err )
261
+ }
262
+ if err := m .consistent (); err != nil {
263
+ t .Fatalf ("Confirm (sequence #1): inconsistent state: %v" , err )
264
+ }
265
+
266
+ releaseDee ()
267
+ if err := m .consistent (); err != nil {
268
+ t .Fatalf ("release (sequence #2): inconsistent state: %v" , err )
269
+ }
270
+
271
+ releaseDum , err := m .Confirm (now , "/tweedle/dum" , "" , Condition {Token : tweedle })
272
+ if err != nil {
273
+ t .Fatalf ("Confirm (sequence #3): %v" , err )
274
+ }
275
+ if err := m .consistent (); err != nil {
276
+ t .Fatalf ("Confirm (sequence #3): inconsistent state: %v" , err )
277
+ }
278
+
279
+ // Test that you can't unlock a held lock.
280
+ err = m .Unlock (now , tweedle )
281
+ if err != ErrLocked {
282
+ t .Fatalf ("Unlock (sequence #4): got %v, want ErrLocked" , err )
283
+ }
284
+
285
+ releaseDum ()
286
+ if err := m .consistent (); err != nil {
287
+ t .Fatalf ("release (sequence #5): inconsistent state: %v" , err )
288
+ }
289
+
290
+ err = m .Unlock (now , tweedle )
291
+ if err != nil {
292
+ t .Fatalf ("Unlock (sequence #6): %v" , err )
293
+ }
294
+ if err := m .consistent (); err != nil {
295
+ t .Fatalf ("Unlock (sequence #6): inconsistent state: %v" , err )
296
+ }
297
+ }
298
+
158
299
func TestMemLSNonCanonicalRoot (t * testing.T ) {
159
300
now := time .Unix (0 , 0 )
160
301
m := NewMemLS ().(* memLS )
@@ -304,29 +445,43 @@ func TestMemLSExpiry(t *testing.T) {
304
445
}
305
446
}
306
447
307
- func TestMemLSCreateRefreshUnlock (t * testing.T ) {
448
+ func TestMemLS (t * testing.T ) {
308
449
now := time .Unix (0 , 0 )
309
450
m := NewMemLS ().(* memLS )
310
451
rng := rand .New (rand .NewSource (0 ))
311
452
tokens := map [string ]string {}
312
- nCreate , nRefresh , nUnlock := 0 , 0 , 0
453
+ nConfirm , nCreate , nRefresh , nUnlock := 0 , 0 , 0 , 0
313
454
const N = 2000
314
455
315
456
for i := 0 ; i < N ; i ++ {
316
457
name := lockTestNames [rng .Intn (len (lockTestNames ))]
317
458
duration := lockTestDurations [rng .Intn (len (lockTestDurations ))]
318
- unlocked := false
459
+ confirmed , unlocked := false , false
319
460
320
- // If the name was already locked, there's a 50-50 chance that
321
- // we refresh or unlock it. Otherwise, we create a lock.
461
+ // If the name was already locked, we randomly confirm/release, refresh
462
+ // or unlock it. Otherwise, we create a lock.
322
463
token := tokens [name ]
323
464
if token != "" {
324
- if rng .Intn (2 ) == 0 {
465
+ switch rng .Intn (3 ) {
466
+ case 0 :
467
+ confirmed = true
468
+ nConfirm ++
469
+ release , err := m .Confirm (now , name , "" , Condition {Token : token })
470
+ if err != nil {
471
+ t .Fatalf ("iteration #%d: Confirm %q: %v" , i , name , err )
472
+ }
473
+ if err := m .consistent (); err != nil {
474
+ t .Fatalf ("iteration #%d: inconsistent state: %v" , i , err )
475
+ }
476
+ release ()
477
+
478
+ case 1 :
325
479
nRefresh ++
326
480
if _ , err := m .Refresh (now , token , duration ); err != nil {
327
481
t .Fatalf ("iteration #%d: Refresh %q: %v" , i , name , err )
328
482
}
329
- } else {
483
+
484
+ case 2 :
330
485
unlocked = true
331
486
nUnlock ++
332
487
if err := m .Unlock (now , token ); err != nil {
@@ -347,19 +502,24 @@ func TestMemLSCreateRefreshUnlock(t *testing.T) {
347
502
}
348
503
}
349
504
350
- if duration == 0 || unlocked {
351
- // A zero-duration lock should expire immediately and is
352
- // effectively equivalent to being unlocked.
353
- tokens [name ] = ""
354
- } else {
355
- tokens [name ] = token
505
+ if ! confirmed {
506
+ if duration == 0 || unlocked {
507
+ // A zero-duration lock should expire immediately and is
508
+ // effectively equivalent to being unlocked.
509
+ tokens [name ] = ""
510
+ } else {
511
+ tokens [name ] = token
512
+ }
356
513
}
357
514
358
515
if err := m .consistent (); err != nil {
359
516
t .Fatalf ("iteration #%d: inconsistent state: %v" , i , err )
360
517
}
361
518
}
362
519
520
+ if nConfirm < N / 10 {
521
+ t .Fatalf ("too few Confirm calls: got %d, want >= %d" , nConfirm , N / 10 )
522
+ }
363
523
if nCreate < N / 10 {
364
524
t .Fatalf ("too few Create calls: got %d, want >= %d" , nCreate , N / 10 )
365
525
}
@@ -464,6 +624,11 @@ func (m *memLS) consistent() error {
464
624
if _ , ok := m .byName [n .details .Root ]; ! ok {
465
625
return fmt .Errorf ("node at name %q in m.byExpiry but not in m.byName" , n .details .Root )
466
626
}
627
+
628
+ // No node in m.byExpiry should be held.
629
+ if n .held {
630
+ return fmt .Errorf ("node at name %q in m.byExpiry is held" , n .details .Root )
631
+ }
467
632
}
468
633
return nil
469
634
}
0 commit comments