Browse code

IPAM tests

Added tests for swarm mode and also some new parallel tests

Signed-off-by: Flavio Crisciani <flavio.crisciani@docker.com>

Flavio Crisciani authored on 2018/03/08 04:14:13
Showing 2 changed files
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	"github.com/docker/libnetwork/ipamutils"
21 21
 	_ "github.com/docker/libnetwork/testutils"
22 22
 	"github.com/docker/libnetwork/types"
23
+	"github.com/stretchr/testify/assert"
23 24
 )
24 25
 
25 26
 const (
... ...
@@ -170,662 +171,669 @@ func TestPoolDataMarshal(t *testing.T) {
170 170
 }
171 171
 
172 172
 func TestSubnetsMarshal(t *testing.T) {
173
-	a, err := getAllocator(true)
174
-	if err != nil {
175
-		t.Fatal(err)
176
-	}
177
-	pid0, _, _, err := a.RequestPool(localAddressSpace, "192.168.0.0/16", "", nil, false)
178
-	if err != nil {
179
-		t.Fatal(err)
180
-	}
181
-	pid1, _, _, err := a.RequestPool(localAddressSpace, "192.169.0.0/16", "", nil, false)
182
-	if err != nil {
183
-		t.Fatal(err)
184
-	}
185
-	_, _, err = a.RequestAddress(pid0, nil, nil)
186
-	if err != nil {
187
-		t.Fatal(err)
188
-	}
173
+	for _, store := range []bool{false, true} {
174
+		a, err := getAllocator(store)
175
+		if err != nil {
176
+			t.Fatal(err)
177
+		}
178
+		pid0, _, _, err := a.RequestPool(localAddressSpace, "192.168.0.0/16", "", nil, false)
179
+		if err != nil {
180
+			t.Fatal(err)
181
+		}
182
+		pid1, _, _, err := a.RequestPool(localAddressSpace, "192.169.0.0/16", "", nil, false)
183
+		if err != nil {
184
+			t.Fatal(err)
185
+		}
186
+		_, _, err = a.RequestAddress(pid0, nil, nil)
187
+		if err != nil {
188
+			t.Fatal(err)
189
+		}
189 190
 
190
-	cfg, err := a.getAddrSpace(localAddressSpace)
191
-	if err != nil {
192
-		t.Fatal(err)
193
-	}
191
+		cfg, err := a.getAddrSpace(localAddressSpace)
192
+		if err != nil {
193
+			t.Fatal(err)
194
+		}
194 195
 
195
-	ba := cfg.Value()
196
-	if err := cfg.SetValue(ba); err != nil {
197
-		t.Fatal(err)
198
-	}
196
+		ba := cfg.Value()
197
+		if err := cfg.SetValue(ba); err != nil {
198
+			t.Fatal(err)
199
+		}
199 200
 
200
-	expIP := &net.IPNet{IP: net.IP{192, 168, 0, 2}, Mask: net.IPMask{255, 255, 0, 0}}
201
-	ip, _, err := a.RequestAddress(pid0, nil, nil)
202
-	if err != nil {
203
-		t.Fatal(err)
204
-	}
205
-	if !types.CompareIPNet(expIP, ip) {
206
-		t.Fatalf("Got unexpected ip after pool config restore: %s", ip)
207
-	}
201
+		expIP := &net.IPNet{IP: net.IP{192, 168, 0, 2}, Mask: net.IPMask{255, 255, 0, 0}}
202
+		ip, _, err := a.RequestAddress(pid0, nil, nil)
203
+		if err != nil {
204
+			t.Fatal(err)
205
+		}
206
+		if !types.CompareIPNet(expIP, ip) {
207
+			t.Fatalf("Got unexpected ip after pool config restore: %s", ip)
208
+		}
208 209
 
209
-	expIP = &net.IPNet{IP: net.IP{192, 169, 0, 1}, Mask: net.IPMask{255, 255, 0, 0}}
210
-	ip, _, err = a.RequestAddress(pid1, nil, nil)
211
-	if err != nil {
212
-		t.Fatal(err)
213
-	}
214
-	if !types.CompareIPNet(expIP, ip) {
215
-		t.Fatalf("Got unexpected ip after pool config restore: %s", ip)
210
+		expIP = &net.IPNet{IP: net.IP{192, 169, 0, 1}, Mask: net.IPMask{255, 255, 0, 0}}
211
+		ip, _, err = a.RequestAddress(pid1, nil, nil)
212
+		if err != nil {
213
+			t.Fatal(err)
214
+		}
215
+		if !types.CompareIPNet(expIP, ip) {
216
+			t.Fatalf("Got unexpected ip after pool config restore: %s", ip)
217
+		}
216 218
 	}
217 219
 }
218 220
 
219 221
 func TestAddSubnets(t *testing.T) {
220
-	a, err := getAllocator(true)
221
-	if err != nil {
222
-		t.Fatal(err)
223
-	}
224
-	a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace]
222
+	for _, store := range []bool{false, true} {
223
+		a, err := getAllocator(store)
224
+		if err != nil {
225
+			t.Fatal(err)
226
+		}
227
+		a.addrSpaces["abc"] = a.addrSpaces[localAddressSpace]
225 228
 
226
-	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
227
-	if err != nil {
228
-		t.Fatal("Unexpected failure in adding subnet")
229
-	}
229
+		pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
230
+		if err != nil {
231
+			t.Fatal("Unexpected failure in adding subnet")
232
+		}
230 233
 
231
-	pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false)
232
-	if err != nil {
233
-		t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err)
234
-	}
234
+		pid1, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false)
235
+		if err != nil {
236
+			t.Fatalf("Unexpected failure in adding overlapping subnets to different address spaces: %v", err)
237
+		}
235 238
 
236
-	if pid0 == pid1 {
237
-		t.Fatal("returned same pool id for same subnets in different namespaces")
238
-	}
239
+		if pid0 == pid1 {
240
+			t.Fatal("returned same pool id for same subnets in different namespaces")
241
+		}
239 242
 
240
-	pid, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false)
241
-	if err != nil {
242
-		t.Fatalf("Unexpected failure requesting existing subnet: %v", err)
243
-	}
244
-	if pid != pid1 {
245
-		t.Fatal("returned different pool id for same subnet requests")
246
-	}
243
+		pid, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "", nil, false)
244
+		if err != nil {
245
+			t.Fatalf("Unexpected failure requesting existing subnet: %v", err)
246
+		}
247
+		if pid != pid1 {
248
+			t.Fatal("returned different pool id for same subnet requests")
249
+		}
247 250
 
248
-	_, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false)
249
-	if err == nil {
250
-		t.Fatal("Expected failure on adding overlapping base subnet")
251
-	}
251
+		_, _, _, err = a.RequestPool("abc", "10.128.0.0/9", "", nil, false)
252
+		if err == nil {
253
+			t.Fatal("Expected failure on adding overlapping base subnet")
254
+		}
252 255
 
253
-	pid2, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false)
254
-	if err != nil {
255
-		t.Fatalf("Unexpected failure on adding sub pool: %v", err)
256
-	}
257
-	pid3, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false)
258
-	if err != nil {
259
-		t.Fatalf("Unexpected failure on adding overlapping sub pool: %v", err)
260
-	}
261
-	if pid2 != pid3 {
262
-		t.Fatal("returned different pool id for same sub pool requests")
263
-	}
256
+		pid2, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false)
257
+		if err != nil {
258
+			t.Fatalf("Unexpected failure on adding sub pool: %v", err)
259
+		}
260
+		pid3, _, _, err := a.RequestPool("abc", "10.0.0.0/8", "10.128.0.0/9", nil, false)
261
+		if err != nil {
262
+			t.Fatalf("Unexpected failure on adding overlapping sub pool: %v", err)
263
+		}
264
+		if pid2 != pid3 {
265
+			t.Fatal("returned different pool id for same sub pool requests")
266
+		}
264 267
 
265
-	_, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false)
266
-	if err == nil {
267
-		t.Fatal("Failed to detect overlapping subnets")
268
-	}
268
+		_, _, _, err = a.RequestPool(localAddressSpace, "10.20.2.0/24", "", nil, false)
269
+		if err == nil {
270
+			t.Fatal("Failed to detect overlapping subnets")
271
+		}
269 272
 
270
-	_, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false)
271
-	if err == nil {
272
-		t.Fatal("Failed to detect overlapping subnets")
273
-	}
273
+		_, _, _, err = a.RequestPool(localAddressSpace, "10.128.0.0/9", "", nil, false)
274
+		if err == nil {
275
+			t.Fatal("Failed to detect overlapping subnets")
276
+		}
274 277
 
275
-	_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false)
276
-	if err != nil {
277
-		t.Fatalf("Failed to add v6 subnet: %s", err.Error())
278
-	}
278
+		_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3:4:5:6::/112", "", nil, false)
279
+		if err != nil {
280
+			t.Fatalf("Failed to add v6 subnet: %s", err.Error())
281
+		}
279 282
 
280
-	_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false)
281
-	if err == nil {
282
-		t.Fatal("Failed to detect overlapping v6 subnet")
283
+		_, _, _, err = a.RequestPool(localAddressSpace, "1003:1:2:3::/64", "", nil, false)
284
+		if err == nil {
285
+			t.Fatal("Failed to detect overlapping v6 subnet")
286
+		}
283 287
 	}
284 288
 }
285 289
 
286 290
 func TestAddReleasePoolID(t *testing.T) {
287
-	var k0, k1, k2 SubnetKey
288
-
289
-	a, err := getAllocator(true)
290
-	if err != nil {
291
-		t.Fatal(err)
292
-	}
291
+	for _, store := range []bool{false, true} {
292
+		a, err := getAllocator(store)
293
+		assert.NoError(t, err)
293 294
 
294
-	aSpace, err := a.getAddrSpace(localAddressSpace)
295
-	if err != nil {
296
-		t.Fatal(err)
297
-	}
295
+		var k0, k1, k2 SubnetKey
296
+		aSpace, err := a.getAddrSpace(localAddressSpace)
297
+		if err != nil {
298
+			t.Fatal(err)
299
+		}
298 300
 
299
-	pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
300
-	if err != nil {
301
-		t.Fatal("Unexpected failure in adding pool")
302
-	}
303
-	if err := k0.FromString(pid0); err != nil {
304
-		t.Fatal(err)
305
-	}
301
+		pid0, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
302
+		if err != nil {
303
+			t.Fatal("Unexpected failure in adding pool")
304
+		}
305
+		if err := k0.FromString(pid0); err != nil {
306
+			t.Fatal(err)
307
+		}
306 308
 
307
-	aSpace, err = a.getAddrSpace(localAddressSpace)
308
-	if err != nil {
309
-		t.Fatal(err)
310
-	}
309
+		aSpace, err = a.getAddrSpace(localAddressSpace)
310
+		if err != nil {
311
+			t.Fatal(err)
312
+		}
311 313
 
312
-	subnets := aSpace.subnets
314
+		subnets := aSpace.subnets
313 315
 
314
-	if subnets[k0].RefCount != 1 {
315
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
316
-	}
316
+		if subnets[k0].RefCount != 1 {
317
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
318
+		}
317 319
 
318
-	pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
319
-	if err != nil {
320
-		t.Fatal("Unexpected failure in adding sub pool")
321
-	}
322
-	if err := k1.FromString(pid1); err != nil {
323
-		t.Fatal(err)
324
-	}
320
+		pid1, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
321
+		if err != nil {
322
+			t.Fatal("Unexpected failure in adding sub pool")
323
+		}
324
+		if err := k1.FromString(pid1); err != nil {
325
+			t.Fatal(err)
326
+		}
325 327
 
326
-	aSpace, err = a.getAddrSpace(localAddressSpace)
327
-	if err != nil {
328
-		t.Fatal(err)
329
-	}
328
+		aSpace, err = a.getAddrSpace(localAddressSpace)
329
+		if err != nil {
330
+			t.Fatal(err)
331
+		}
330 332
 
331
-	subnets = aSpace.subnets
332
-	if subnets[k1].RefCount != 1 {
333
-		t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount)
334
-	}
333
+		subnets = aSpace.subnets
334
+		if subnets[k1].RefCount != 1 {
335
+			t.Fatalf("Unexpected ref count for %s: %d", k1, subnets[k1].RefCount)
336
+		}
335 337
 
336
-	pid2, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
337
-	if err != nil {
338
-		t.Fatal("Unexpected failure in adding sub pool")
339
-	}
340
-	if pid0 == pid1 || pid0 == pid2 || pid1 != pid2 {
341
-		t.Fatalf("Incorrect poolIDs returned %s, %s, %s", pid0, pid1, pid2)
342
-	}
343
-	if err := k2.FromString(pid2); err != nil {
344
-		t.Fatal(err)
345
-	}
338
+		pid2, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "10.0.0.0/16", nil, false)
339
+		if err != nil {
340
+			t.Fatal("Unexpected failure in adding sub pool")
341
+		}
342
+		if pid0 == pid1 || pid0 == pid2 || pid1 != pid2 {
343
+			t.Fatalf("Incorrect poolIDs returned %s, %s, %s", pid0, pid1, pid2)
344
+		}
345
+		if err := k2.FromString(pid2); err != nil {
346
+			t.Fatal(err)
347
+		}
346 348
 
347
-	aSpace, err = a.getAddrSpace(localAddressSpace)
348
-	if err != nil {
349
-		t.Fatal(err)
350
-	}
349
+		aSpace, err = a.getAddrSpace(localAddressSpace)
350
+		if err != nil {
351
+			t.Fatal(err)
352
+		}
351 353
 
352
-	subnets = aSpace.subnets
353
-	if subnets[k2].RefCount != 2 {
354
-		t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount)
355
-	}
354
+		subnets = aSpace.subnets
355
+		if subnets[k2].RefCount != 2 {
356
+			t.Fatalf("Unexpected ref count for %s: %d", k2, subnets[k2].RefCount)
357
+		}
356 358
 
357
-	if subnets[k0].RefCount != 3 {
358
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
359
-	}
359
+		if subnets[k0].RefCount != 3 {
360
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
361
+		}
360 362
 
361
-	if err := a.ReleasePool(pid1); err != nil {
362
-		t.Fatal(err)
363
-	}
363
+		if err := a.ReleasePool(pid1); err != nil {
364
+			t.Fatal(err)
365
+		}
364 366
 
365
-	aSpace, err = a.getAddrSpace(localAddressSpace)
366
-	if err != nil {
367
-		t.Fatal(err)
368
-	}
367
+		aSpace, err = a.getAddrSpace(localAddressSpace)
368
+		if err != nil {
369
+			t.Fatal(err)
370
+		}
369 371
 
370
-	subnets = aSpace.subnets
371
-	if subnets[k0].RefCount != 2 {
372
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
373
-	}
374
-	if err := a.ReleasePool(pid0); err != nil {
375
-		t.Fatal(err)
376
-	}
372
+		subnets = aSpace.subnets
373
+		if subnets[k0].RefCount != 2 {
374
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
375
+		}
376
+		if err := a.ReleasePool(pid0); err != nil {
377
+			t.Fatal(err)
378
+		}
377 379
 
378
-	aSpace, err = a.getAddrSpace(localAddressSpace)
379
-	if err != nil {
380
-		t.Fatal(err)
381
-	}
380
+		aSpace, err = a.getAddrSpace(localAddressSpace)
381
+		if err != nil {
382
+			t.Fatal(err)
383
+		}
382 384
 
383
-	subnets = aSpace.subnets
384
-	if subnets[k0].RefCount != 1 {
385
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
386
-	}
385
+		subnets = aSpace.subnets
386
+		if subnets[k0].RefCount != 1 {
387
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
388
+		}
387 389
 
388
-	pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
389
-	if err != nil {
390
-		t.Fatal("Unexpected failure in adding pool")
391
-	}
392
-	if pid00 != pid0 {
393
-		t.Fatal("main pool should still exist")
394
-	}
390
+		pid00, _, _, err := a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
391
+		if err != nil {
392
+			t.Fatal("Unexpected failure in adding pool")
393
+		}
394
+		if pid00 != pid0 {
395
+			t.Fatal("main pool should still exist")
396
+		}
395 397
 
396
-	aSpace, err = a.getAddrSpace(localAddressSpace)
397
-	if err != nil {
398
-		t.Fatal(err)
399
-	}
398
+		aSpace, err = a.getAddrSpace(localAddressSpace)
399
+		if err != nil {
400
+			t.Fatal(err)
401
+		}
400 402
 
401
-	subnets = aSpace.subnets
402
-	if subnets[k0].RefCount != 2 {
403
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
404
-	}
403
+		subnets = aSpace.subnets
404
+		if subnets[k0].RefCount != 2 {
405
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
406
+		}
405 407
 
406
-	if err := a.ReleasePool(pid2); err != nil {
407
-		t.Fatal(err)
408
-	}
408
+		if err := a.ReleasePool(pid2); err != nil {
409
+			t.Fatal(err)
410
+		}
409 411
 
410
-	aSpace, err = a.getAddrSpace(localAddressSpace)
411
-	if err != nil {
412
-		t.Fatal(err)
413
-	}
412
+		aSpace, err = a.getAddrSpace(localAddressSpace)
413
+		if err != nil {
414
+			t.Fatal(err)
415
+		}
414 416
 
415
-	subnets = aSpace.subnets
416
-	if subnets[k0].RefCount != 1 {
417
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
418
-	}
417
+		subnets = aSpace.subnets
418
+		if subnets[k0].RefCount != 1 {
419
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
420
+		}
419 421
 
420
-	if err := a.ReleasePool(pid00); err != nil {
421
-		t.Fatal(err)
422
-	}
422
+		if err := a.ReleasePool(pid00); err != nil {
423
+			t.Fatal(err)
424
+		}
423 425
 
424
-	aSpace, err = a.getAddrSpace(localAddressSpace)
425
-	if err != nil {
426
-		t.Fatal(err)
427
-	}
426
+		aSpace, err = a.getAddrSpace(localAddressSpace)
427
+		if err != nil {
428
+			t.Fatal(err)
429
+		}
428 430
 
429
-	subnets = aSpace.subnets
430
-	if bp, ok := subnets[k0]; ok {
431
-		t.Fatalf("Base pool %s is still present: %v", k0, bp)
432
-	}
431
+		subnets = aSpace.subnets
432
+		if bp, ok := subnets[k0]; ok {
433
+			t.Fatalf("Base pool %s is still present: %v", k0, bp)
434
+		}
433 435
 
434
-	_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
435
-	if err != nil {
436
-		t.Fatal("Unexpected failure in adding pool")
437
-	}
436
+		_, _, _, err = a.RequestPool(localAddressSpace, "10.0.0.0/8", "", nil, false)
437
+		if err != nil {
438
+			t.Fatal("Unexpected failure in adding pool")
439
+		}
438 440
 
439
-	aSpace, err = a.getAddrSpace(localAddressSpace)
440
-	if err != nil {
441
-		t.Fatal(err)
442
-	}
441
+		aSpace, err = a.getAddrSpace(localAddressSpace)
442
+		if err != nil {
443
+			t.Fatal(err)
444
+		}
443 445
 
444
-	subnets = aSpace.subnets
445
-	if subnets[k0].RefCount != 1 {
446
-		t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
446
+		subnets = aSpace.subnets
447
+		if subnets[k0].RefCount != 1 {
448
+			t.Fatalf("Unexpected ref count for %s: %d", k0, subnets[k0].RefCount)
449
+		}
447 450
 	}
448 451
 }
449 452
 
450 453
 func TestPredefinedPool(t *testing.T) {
451
-	a, err := getAllocator(true)
452
-	if err != nil {
453
-		t.Fatal(err)
454
-	}
454
+	for _, store := range []bool{false, true} {
455
+		a, err := getAllocator(store)
456
+		assert.NoError(t, err)
455 457
 
456
-	if _, err := a.getPredefinedPool("blue", false); err == nil {
457
-		t.Fatal("Expected failure for non default addr space")
458
-	}
458
+		if _, err := a.getPredefinedPool("blue", false); err == nil {
459
+			t.Fatal("Expected failure for non default addr space")
460
+		}
459 461
 
460
-	pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
461
-	if err != nil {
462
-		t.Fatal(err)
463
-	}
462
+		pid, nw, _, err := a.RequestPool(localAddressSpace, "", "", nil, false)
463
+		if err != nil {
464
+			t.Fatal(err)
465
+		}
464 466
 
465
-	nw2, err := a.getPredefinedPool(localAddressSpace, false)
466
-	if err != nil {
467
-		t.Fatal(err)
468
-	}
469
-	if types.CompareIPNet(nw, nw2) {
470
-		t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw)
471
-	}
467
+		nw2, err := a.getPredefinedPool(localAddressSpace, false)
468
+		if err != nil {
469
+			t.Fatal(err)
470
+		}
471
+		if types.CompareIPNet(nw, nw2) {
472
+			t.Fatalf("Unexpected default network returned: %s = %s", nw2, nw)
473
+		}
472 474
 
473
-	if err := a.ReleasePool(pid); err != nil {
474
-		t.Fatal(err)
475
+		if err := a.ReleasePool(pid); err != nil {
476
+			t.Fatal(err)
477
+		}
475 478
 	}
476 479
 }
477 480
 
478 481
 func TestRemoveSubnet(t *testing.T) {
479
-	a, err := getAllocator(true)
480
-	if err != nil {
481
-		t.Fatal(err)
482
-	}
483
-	a.addrSpaces["splane"] = &addrSpace{
484
-		id:      dsConfigKey + "/" + "splane",
485
-		ds:      a.addrSpaces[localAddressSpace].ds,
486
-		alloc:   a.addrSpaces[localAddressSpace].alloc,
487
-		scope:   a.addrSpaces[localAddressSpace].scope,
488
-		subnets: map[SubnetKey]*PoolData{},
489
-	}
482
+	for _, store := range []bool{false, true} {
483
+		a, err := getAllocator(store)
484
+		assert.NoError(t, err)
485
+
486
+		a.addrSpaces["splane"] = &addrSpace{
487
+			id:      dsConfigKey + "/" + "splane",
488
+			ds:      a.addrSpaces[localAddressSpace].ds,
489
+			alloc:   a.addrSpaces[localAddressSpace].alloc,
490
+			scope:   a.addrSpaces[localAddressSpace].scope,
491
+			subnets: map[SubnetKey]*PoolData{},
492
+		}
490 493
 
491
-	input := []struct {
492
-		addrSpace string
493
-		subnet    string
494
-		v6        bool
495
-	}{
496
-		{localAddressSpace, "192.168.0.0/16", false},
497
-		{localAddressSpace, "172.17.0.0/16", false},
498
-		{localAddressSpace, "10.0.0.0/8", false},
499
-		{localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false},
500
-		{"splane", "172.17.0.0/16", false},
501
-		{"splane", "10.0.0.0/8", false},
502
-		{"splane", "2001:db8:1:2:3:4:5::/112", true},
503
-		{"splane", "2001:db8:1:2:3:4:ffff::/112", true},
504
-	}
494
+		input := []struct {
495
+			addrSpace string
496
+			subnet    string
497
+			v6        bool
498
+		}{
499
+			{localAddressSpace, "192.168.0.0/16", false},
500
+			{localAddressSpace, "172.17.0.0/16", false},
501
+			{localAddressSpace, "10.0.0.0/8", false},
502
+			{localAddressSpace, "2001:db8:1:2:3:4:ffff::/112", false},
503
+			{"splane", "172.17.0.0/16", false},
504
+			{"splane", "10.0.0.0/8", false},
505
+			{"splane", "2001:db8:1:2:3:4:5::/112", true},
506
+			{"splane", "2001:db8:1:2:3:4:ffff::/112", true},
507
+		}
505 508
 
506
-	poolIDs := make([]string, len(input))
509
+		poolIDs := make([]string, len(input))
507 510
 
508
-	for ind, i := range input {
509
-		if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil {
510
-			t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error())
511
+		for ind, i := range input {
512
+			if poolIDs[ind], _, _, err = a.RequestPool(i.addrSpace, i.subnet, "", nil, i.v6); err != nil {
513
+				t.Fatalf("Failed to apply input. Can't proceed: %s", err.Error())
514
+			}
511 515
 		}
512
-	}
513 516
 
514
-	for ind, id := range poolIDs {
515
-		if err := a.ReleasePool(id); err != nil {
516
-			t.Fatalf("Failed to release poolID %s (%d)", id, ind)
517
+		for ind, id := range poolIDs {
518
+			if err := a.ReleasePool(id); err != nil {
519
+				t.Fatalf("Failed to release poolID %s (%d)", id, ind)
520
+			}
517 521
 		}
518 522
 	}
519 523
 }
520 524
 
521 525
 func TestGetSameAddress(t *testing.T) {
522
-	a, err := getAllocator(true)
523
-	if err != nil {
524
-		t.Fatal(err)
525
-	}
526
-	a.addrSpaces["giallo"] = &addrSpace{
527
-		id:      dsConfigKey + "/" + "giallo",
528
-		ds:      a.addrSpaces[localAddressSpace].ds,
529
-		alloc:   a.addrSpaces[localAddressSpace].alloc,
530
-		scope:   a.addrSpaces[localAddressSpace].scope,
531
-		subnets: map[SubnetKey]*PoolData{},
532
-	}
526
+	for _, store := range []bool{false, true} {
527
+		a, err := getAllocator(store)
528
+		assert.NoError(t, err)
529
+
530
+		a.addrSpaces["giallo"] = &addrSpace{
531
+			id:      dsConfigKey + "/" + "giallo",
532
+			ds:      a.addrSpaces[localAddressSpace].ds,
533
+			alloc:   a.addrSpaces[localAddressSpace].alloc,
534
+			scope:   a.addrSpaces[localAddressSpace].scope,
535
+			subnets: map[SubnetKey]*PoolData{},
536
+		}
533 537
 
534
-	pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false)
535
-	if err != nil {
536
-		t.Fatal(err)
537
-	}
538
+		pid, _, _, err := a.RequestPool("giallo", "192.168.100.0/24", "", nil, false)
539
+		if err != nil {
540
+			t.Fatal(err)
541
+		}
538 542
 
539
-	ip := net.ParseIP("192.168.100.250")
540
-	_, _, err = a.RequestAddress(pid, ip, nil)
541
-	if err != nil {
542
-		t.Fatal(err)
543
-	}
543
+		ip := net.ParseIP("192.168.100.250")
544
+		_, _, err = a.RequestAddress(pid, ip, nil)
545
+		if err != nil {
546
+			t.Fatal(err)
547
+		}
544 548
 
545
-	_, _, err = a.RequestAddress(pid, ip, nil)
546
-	if err == nil {
547
-		t.Fatal(err)
549
+		_, _, err = a.RequestAddress(pid, ip, nil)
550
+		if err == nil {
551
+			t.Fatal(err)
552
+		}
548 553
 	}
549 554
 }
550 555
 
551 556
 func TestGetAddressSubPoolEqualPool(t *testing.T) {
552
-	a, err := getAllocator(true)
553
-	if err != nil {
554
-		t.Fatal(err)
555
-	}
556
-	// Requesting a subpool of same size of the master pool should not cause any problem on ip allocation
557
-	pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false)
558
-	if err != nil {
559
-		t.Fatal(err)
560
-	}
557
+	for _, store := range []bool{false, true} {
558
+		a, err := getAllocator(store)
559
+		assert.NoError(t, err)
561 560
 
562
-	_, _, err = a.RequestAddress(pid, nil, nil)
563
-	if err != nil {
564
-		t.Fatal(err)
561
+		// Requesting a subpool of same size of the master pool should not cause any problem on ip allocation
562
+		pid, _, _, err := a.RequestPool(localAddressSpace, "172.18.0.0/16", "172.18.0.0/16", nil, false)
563
+		if err != nil {
564
+			t.Fatal(err)
565
+		}
566
+
567
+		_, _, err = a.RequestAddress(pid, nil, nil)
568
+		if err != nil {
569
+			t.Fatal(err)
570
+		}
565 571
 	}
566 572
 }
567 573
 
568 574
 func TestRequestReleaseAddressFromSubPool(t *testing.T) {
569
-	a, err := getAllocator(true)
570
-	if err != nil {
571
-		t.Fatal(err)
572
-	}
573
-	a.addrSpaces["rosso"] = &addrSpace{
574
-		id:      dsConfigKey + "/" + "rosso",
575
-		ds:      a.addrSpaces[localAddressSpace].ds,
576
-		alloc:   a.addrSpaces[localAddressSpace].alloc,
577
-		scope:   a.addrSpaces[localAddressSpace].scope,
578
-		subnets: map[SubnetKey]*PoolData{},
579
-	}
575
+	for _, store := range []bool{false, true} {
576
+		a, err := getAllocator(store)
577
+		assert.NoError(t, err)
578
+
579
+		a.addrSpaces["rosso"] = &addrSpace{
580
+			id:      dsConfigKey + "/" + "rosso",
581
+			ds:      a.addrSpaces[localAddressSpace].ds,
582
+			alloc:   a.addrSpaces[localAddressSpace].alloc,
583
+			scope:   a.addrSpaces[localAddressSpace].scope,
584
+			subnets: map[SubnetKey]*PoolData{},
585
+		}
580 586
 
581
-	poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
582
-	if err != nil {
583
-		t.Fatal(err)
584
-	}
587
+		poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
588
+		if err != nil {
589
+			t.Fatal(err)
590
+		}
585 591
 
586
-	var ip *net.IPNet
587
-	expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
588
-	for err == nil {
589
-		var c *net.IPNet
590
-		if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
591
-			ip = c
592
+		var ip *net.IPNet
593
+		expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
594
+		for err == nil {
595
+			var c *net.IPNet
596
+			if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
597
+				ip = c
598
+			}
599
+		}
600
+		if err != ipamapi.ErrNoAvailableIPs {
601
+			t.Fatal(err)
602
+		}
603
+		if !types.CompareIPNet(expected, ip) {
604
+			t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
605
+		}
606
+		rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
607
+		if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
608
+			t.Fatal(err)
609
+		}
610
+		if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
611
+			t.Fatal(err)
612
+		}
613
+		if !types.CompareIPNet(rp, ip) {
614
+			t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
592 615
 		}
593
-	}
594
-	if err != ipamapi.ErrNoAvailableIPs {
595
-		t.Fatal(err)
596
-	}
597
-	if !types.CompareIPNet(expected, ip) {
598
-		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
599
-	}
600
-	rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
601
-	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
602
-		t.Fatal(err)
603
-	}
604
-	if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
605
-		t.Fatal(err)
606
-	}
607
-	if !types.CompareIPNet(rp, ip) {
608
-		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
609
-	}
610 616
 
611
-	_, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false)
612
-	if err != nil {
613
-		t.Fatal(err)
614
-	}
615
-	poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false)
616
-	if err != nil {
617
-		t.Fatal(err)
618
-	}
619
-	expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
620
-	for err == nil {
621
-		var c *net.IPNet
622
-		if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
623
-			ip = c
617
+		_, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false)
618
+		if err != nil {
619
+			t.Fatal(err)
620
+		}
621
+		poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false)
622
+		if err != nil {
623
+			t.Fatal(err)
624
+		}
625
+		expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
626
+		for err == nil {
627
+			var c *net.IPNet
628
+			if c, _, err = a.RequestAddress(poolID, nil, nil); err == nil {
629
+				ip = c
630
+			}
631
+		}
632
+		if err != ipamapi.ErrNoAvailableIPs {
633
+			t.Fatal(err)
634
+		}
635
+		if !types.CompareIPNet(expected, ip) {
636
+			t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
637
+		}
638
+		rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
639
+		if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
640
+			t.Fatal(err)
641
+		}
642
+		if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
643
+			t.Fatal(err)
644
+		}
645
+		if !types.CompareIPNet(rp, ip) {
646
+			t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
624 647
 		}
625
-	}
626
-	if err != ipamapi.ErrNoAvailableIPs {
627
-		t.Fatal(err)
628
-	}
629
-	if !types.CompareIPNet(expected, ip) {
630
-		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
631
-	}
632
-	rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
633
-	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
634
-		t.Fatal(err)
635
-	}
636
-	if ip, _, err = a.RequestAddress(poolID, nil, nil); err != nil {
637
-		t.Fatal(err)
638
-	}
639
-	if !types.CompareIPNet(rp, ip) {
640
-		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
641
-	}
642 648
 
643
-	// Request any addresses from subpool after explicit address request
644
-	unoExp, _ := types.ParseCIDR("10.2.2.0/16")
645
-	dueExp, _ := types.ParseCIDR("10.2.2.2/16")
646
-	treExp, _ := types.ParseCIDR("10.2.2.1/16")
649
+		// Request any addresses from subpool after explicit address request
650
+		unoExp, _ := types.ParseCIDR("10.2.2.0/16")
651
+		dueExp, _ := types.ParseCIDR("10.2.2.2/16")
652
+		treExp, _ := types.ParseCIDR("10.2.2.1/16")
647 653
 
648
-	if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
649
-		t.Fatal(err)
650
-	}
651
-	tre, _, err := a.RequestAddress(poolID, treExp.IP, nil)
652
-	if err != nil {
653
-		t.Fatal(err)
654
-	}
655
-	if !types.CompareIPNet(tre, treExp) {
656
-		t.Fatalf("Unexpected address: %v", tre)
657
-	}
654
+		if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
655
+			t.Fatal(err)
656
+		}
657
+		tre, _, err := a.RequestAddress(poolID, treExp.IP, nil)
658
+		if err != nil {
659
+			t.Fatal(err)
660
+		}
661
+		if !types.CompareIPNet(tre, treExp) {
662
+			t.Fatalf("Unexpected address: %v", tre)
663
+		}
658 664
 
659
-	uno, _, err := a.RequestAddress(poolID, nil, nil)
660
-	if err != nil {
661
-		t.Fatal(err)
662
-	}
663
-	if !types.CompareIPNet(uno, unoExp) {
664
-		t.Fatalf("Unexpected address: %v", uno)
665
-	}
665
+		uno, _, err := a.RequestAddress(poolID, nil, nil)
666
+		if err != nil {
667
+			t.Fatal(err)
668
+		}
669
+		if !types.CompareIPNet(uno, unoExp) {
670
+			t.Fatalf("Unexpected address: %v", uno)
671
+		}
666 672
 
667
-	due, _, err := a.RequestAddress(poolID, nil, nil)
668
-	if err != nil {
669
-		t.Fatal(err)
670
-	}
671
-	if !types.CompareIPNet(due, dueExp) {
672
-		t.Fatalf("Unexpected address: %v", due)
673
-	}
673
+		due, _, err := a.RequestAddress(poolID, nil, nil)
674
+		if err != nil {
675
+			t.Fatal(err)
676
+		}
677
+		if !types.CompareIPNet(due, dueExp) {
678
+			t.Fatalf("Unexpected address: %v", due)
679
+		}
674 680
 
675
-	if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
676
-		t.Fatal(err)
677
-	}
678
-	uno, _, err = a.RequestAddress(poolID, nil, nil)
679
-	if err != nil {
680
-		t.Fatal(err)
681
-	}
682
-	if !types.CompareIPNet(uno, unoExp) {
683
-		t.Fatalf("Unexpected address: %v", uno)
684
-	}
681
+		if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
682
+			t.Fatal(err)
683
+		}
684
+		uno, _, err = a.RequestAddress(poolID, nil, nil)
685
+		if err != nil {
686
+			t.Fatal(err)
687
+		}
688
+		if !types.CompareIPNet(uno, unoExp) {
689
+			t.Fatalf("Unexpected address: %v", uno)
690
+		}
685 691
 
686
-	if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
687
-		t.Fatal(err)
688
-	}
689
-	tre, _, err = a.RequestAddress(poolID, nil, nil)
690
-	if err != nil {
691
-		t.Fatal(err)
692
-	}
693
-	if !types.CompareIPNet(tre, treExp) {
694
-		t.Fatalf("Unexpected address: %v", tre)
692
+		if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
693
+			t.Fatal(err)
694
+		}
695
+		tre, _, err = a.RequestAddress(poolID, nil, nil)
696
+		if err != nil {
697
+			t.Fatal(err)
698
+		}
699
+		if !types.CompareIPNet(tre, treExp) {
700
+			t.Fatalf("Unexpected address: %v", tre)
701
+		}
695 702
 	}
696 703
 }
697 704
 
698 705
 func TestSerializeRequestReleaseAddressFromSubPool(t *testing.T) {
699 706
 	opts := map[string]string{
700
-		ipamapi.AllocSerialPrefix: "true",
701
-	}
702
-	a, err := getAllocator(false)
703
-	if err != nil {
704
-		t.Fatal(err)
705
-	}
706
-	a.addrSpaces["rosso"] = &addrSpace{
707
-		id:      dsConfigKey + "/" + "rosso",
708
-		ds:      a.addrSpaces[localAddressSpace].ds,
709
-		alloc:   a.addrSpaces[localAddressSpace].alloc,
710
-		scope:   a.addrSpaces[localAddressSpace].scope,
711
-		subnets: map[SubnetKey]*PoolData{},
712
-	}
707
+		ipamapi.AllocSerialPrefix: "true"}
708
+	for _, store := range []bool{false, true} {
709
+		a, err := getAllocator(store)
710
+		assert.NoError(t, err)
711
+
712
+		a.addrSpaces["rosso"] = &addrSpace{
713
+			id:      dsConfigKey + "/" + "rosso",
714
+			ds:      a.addrSpaces[localAddressSpace].ds,
715
+			alloc:   a.addrSpaces[localAddressSpace].alloc,
716
+			scope:   a.addrSpaces[localAddressSpace].scope,
717
+			subnets: map[SubnetKey]*PoolData{},
718
+		}
713 719
 
714
-	poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
715
-	if err != nil {
716
-		t.Fatal(err)
717
-	}
720
+		poolID, _, _, err := a.RequestPool("rosso", "172.28.0.0/16", "172.28.30.0/24", nil, false)
721
+		if err != nil {
722
+			t.Fatal(err)
723
+		}
718 724
 
719
-	var ip *net.IPNet
720
-	expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
721
-	for err == nil {
722
-		var c *net.IPNet
723
-		if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
724
-			ip = c
725
+		var ip *net.IPNet
726
+		expected := &net.IPNet{IP: net.IP{172, 28, 30, 255}, Mask: net.IPMask{255, 255, 0, 0}}
727
+		for err == nil {
728
+			var c *net.IPNet
729
+			if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
730
+				ip = c
731
+			}
732
+		}
733
+		if err != ipamapi.ErrNoAvailableIPs {
734
+			t.Fatal(err)
735
+		}
736
+		if !types.CompareIPNet(expected, ip) {
737
+			t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
738
+		}
739
+		rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
740
+		if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
741
+			t.Fatal(err)
742
+		}
743
+		if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
744
+			t.Fatal(err)
745
+		}
746
+		if !types.CompareIPNet(rp, ip) {
747
+			t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
725 748
 		}
726
-	}
727
-	if err != ipamapi.ErrNoAvailableIPs {
728
-		t.Fatal(err)
729
-	}
730
-	if !types.CompareIPNet(expected, ip) {
731
-		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
732
-	}
733
-	rp := &net.IPNet{IP: net.IP{172, 28, 30, 97}, Mask: net.IPMask{255, 255, 0, 0}}
734
-	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
735
-		t.Fatal(err)
736
-	}
737
-	if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
738
-		t.Fatal(err)
739
-	}
740
-	if !types.CompareIPNet(rp, ip) {
741
-		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
742
-	}
743 749
 
744
-	_, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false)
745
-	if err != nil {
746
-		t.Fatal(err)
747
-	}
748
-	poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false)
749
-	if err != nil {
750
-		t.Fatal(err)
751
-	}
752
-	expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
753
-	for err == nil {
754
-		var c *net.IPNet
755
-		if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
756
-			ip = c
750
+		_, _, _, err = a.RequestPool("rosso", "10.0.0.0/8", "10.0.0.0/16", nil, false)
751
+		if err != nil {
752
+			t.Fatal(err)
753
+		}
754
+		poolID, _, _, err = a.RequestPool("rosso", "10.0.0.0/16", "10.0.0.0/24", nil, false)
755
+		if err != nil {
756
+			t.Fatal(err)
757
+		}
758
+		expected = &net.IPNet{IP: net.IP{10, 0, 0, 255}, Mask: net.IPMask{255, 255, 0, 0}}
759
+		for err == nil {
760
+			var c *net.IPNet
761
+			if c, _, err = a.RequestAddress(poolID, nil, opts); err == nil {
762
+				ip = c
763
+			}
764
+		}
765
+		if err != ipamapi.ErrNoAvailableIPs {
766
+			t.Fatal(err)
767
+		}
768
+		if !types.CompareIPNet(expected, ip) {
769
+			t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
770
+		}
771
+		rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
772
+		if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
773
+			t.Fatal(err)
774
+		}
775
+		if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
776
+			t.Fatal(err)
777
+		}
778
+		if !types.CompareIPNet(rp, ip) {
779
+			t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
757 780
 		}
758
-	}
759
-	if err != ipamapi.ErrNoAvailableIPs {
760
-		t.Fatal(err)
761
-	}
762
-	if !types.CompareIPNet(expected, ip) {
763
-		t.Fatalf("Unexpected last IP from subpool. Expected: %s. Got: %v.", expected, ip)
764
-	}
765
-	rp = &net.IPNet{IP: net.IP{10, 0, 0, 79}, Mask: net.IPMask{255, 255, 0, 0}}
766
-	if err = a.ReleaseAddress(poolID, rp.IP); err != nil {
767
-		t.Fatal(err)
768
-	}
769
-	if ip, _, err = a.RequestAddress(poolID, nil, opts); err != nil {
770
-		t.Fatal(err)
771
-	}
772
-	if !types.CompareIPNet(rp, ip) {
773
-		t.Fatalf("Unexpected IP from subpool. Expected: %s. Got: %v.", rp, ip)
774
-	}
775 781
 
776
-	// Request any addresses from subpool after explicit address request
777
-	unoExp, _ := types.ParseCIDR("10.2.2.0/16")
778
-	dueExp, _ := types.ParseCIDR("10.2.2.2/16")
779
-	treExp, _ := types.ParseCIDR("10.2.2.1/16")
780
-	quaExp, _ := types.ParseCIDR("10.2.2.3/16")
781
-	fivExp, _ := types.ParseCIDR("10.2.2.4/16")
782
-	if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
783
-		t.Fatal(err)
784
-	}
785
-	tre, _, err := a.RequestAddress(poolID, treExp.IP, opts)
786
-	if err != nil {
787
-		t.Fatal(err)
788
-	}
789
-	if !types.CompareIPNet(tre, treExp) {
790
-		t.Fatalf("Unexpected address: %v", tre)
791
-	}
782
+		// Request any addresses from subpool after explicit address request
783
+		unoExp, _ := types.ParseCIDR("10.2.2.0/16")
784
+		dueExp, _ := types.ParseCIDR("10.2.2.2/16")
785
+		treExp, _ := types.ParseCIDR("10.2.2.1/16")
786
+		quaExp, _ := types.ParseCIDR("10.2.2.3/16")
787
+		fivExp, _ := types.ParseCIDR("10.2.2.4/16")
788
+		if poolID, _, _, err = a.RequestPool("rosso", "10.2.0.0/16", "10.2.2.0/24", nil, false); err != nil {
789
+			t.Fatal(err)
790
+		}
791
+		tre, _, err := a.RequestAddress(poolID, treExp.IP, opts)
792
+		if err != nil {
793
+			t.Fatal(err)
794
+		}
795
+		if !types.CompareIPNet(tre, treExp) {
796
+			t.Fatalf("Unexpected address: %v", tre)
797
+		}
792 798
 
793
-	uno, _, err := a.RequestAddress(poolID, nil, opts)
794
-	if err != nil {
795
-		t.Fatal(err)
796
-	}
797
-	if !types.CompareIPNet(uno, unoExp) {
798
-		t.Fatalf("Unexpected address: %v", uno)
799
-	}
799
+		uno, _, err := a.RequestAddress(poolID, nil, opts)
800
+		if err != nil {
801
+			t.Fatal(err)
802
+		}
803
+		if !types.CompareIPNet(uno, unoExp) {
804
+			t.Fatalf("Unexpected address: %v", uno)
805
+		}
800 806
 
801
-	due, _, err := a.RequestAddress(poolID, nil, opts)
802
-	if err != nil {
803
-		t.Fatal(err)
804
-	}
805
-	if !types.CompareIPNet(due, dueExp) {
806
-		t.Fatalf("Unexpected address: %v", due)
807
-	}
807
+		due, _, err := a.RequestAddress(poolID, nil, opts)
808
+		if err != nil {
809
+			t.Fatal(err)
810
+		}
811
+		if !types.CompareIPNet(due, dueExp) {
812
+			t.Fatalf("Unexpected address: %v", due)
813
+		}
808 814
 
809
-	if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
810
-		t.Fatal(err)
811
-	}
812
-	uno, _, err = a.RequestAddress(poolID, nil, opts)
813
-	if err != nil {
814
-		t.Fatal(err)
815
-	}
816
-	if !types.CompareIPNet(uno, quaExp) {
817
-		t.Fatalf("Unexpected address: %v", uno)
818
-	}
815
+		if err = a.ReleaseAddress(poolID, uno.IP); err != nil {
816
+			t.Fatal(err)
817
+		}
818
+		uno, _, err = a.RequestAddress(poolID, nil, opts)
819
+		if err != nil {
820
+			t.Fatal(err)
821
+		}
822
+		if !types.CompareIPNet(uno, quaExp) {
823
+			t.Fatalf("Unexpected address: %v", uno)
824
+		}
819 825
 
820
-	if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
821
-		t.Fatal(err)
822
-	}
823
-	tre, _, err = a.RequestAddress(poolID, nil, opts)
824
-	if err != nil {
825
-		t.Fatal(err)
826
-	}
827
-	if !types.CompareIPNet(tre, fivExp) {
828
-		t.Fatalf("Unexpected address: %v", tre)
826
+		if err = a.ReleaseAddress(poolID, tre.IP); err != nil {
827
+			t.Fatal(err)
828
+		}
829
+		tre, _, err = a.RequestAddress(poolID, nil, opts)
830
+		if err != nil {
831
+			t.Fatal(err)
832
+		}
833
+		if !types.CompareIPNet(tre, fivExp) {
834
+			t.Fatalf("Unexpected address: %v", tre)
835
+		}
829 836
 	}
830 837
 }
831 838
 
... ...
@@ -846,71 +854,71 @@ func TestRequestSyntaxCheck(t *testing.T) {
846 846
 		pool    = "192.168.0.0/16"
847 847
 		subPool = "192.168.0.0/24"
848 848
 		as      = "green"
849
-		err     error
850 849
 	)
851 850
 
852
-	a, err := getAllocator(true)
853
-	if err != nil {
854
-		t.Fatal(err)
855
-	}
856
-	a.addrSpaces[as] = &addrSpace{
857
-		id:      dsConfigKey + "/" + as,
858
-		ds:      a.addrSpaces[localAddressSpace].ds,
859
-		alloc:   a.addrSpaces[localAddressSpace].alloc,
860
-		scope:   a.addrSpaces[localAddressSpace].scope,
861
-		subnets: map[SubnetKey]*PoolData{},
862
-	}
851
+	for _, store := range []bool{false, true} {
852
+		a, err := getAllocator(store)
853
+		assert.NoError(t, err)
863 854
 
864
-	_, _, _, err = a.RequestPool("", pool, "", nil, false)
865
-	if err == nil {
866
-		t.Fatal("Failed to detect wrong request: empty address space")
867
-	}
855
+		a.addrSpaces[as] = &addrSpace{
856
+			id:      dsConfigKey + "/" + as,
857
+			ds:      a.addrSpaces[localAddressSpace].ds,
858
+			alloc:   a.addrSpaces[localAddressSpace].alloc,
859
+			scope:   a.addrSpaces[localAddressSpace].scope,
860
+			subnets: map[SubnetKey]*PoolData{},
861
+		}
868 862
 
869
-	_, _, _, err = a.RequestPool("", pool, subPool, nil, false)
870
-	if err == nil {
871
-		t.Fatal("Failed to detect wrong request: empty address space")
872
-	}
863
+		_, _, _, err = a.RequestPool("", pool, "", nil, false)
864
+		if err == nil {
865
+			t.Fatal("Failed to detect wrong request: empty address space")
866
+		}
873 867
 
874
-	_, _, _, err = a.RequestPool(as, "", subPool, nil, false)
875
-	if err == nil {
876
-		t.Fatal("Failed to detect wrong request: subPool specified and no pool")
877
-	}
868
+		_, _, _, err = a.RequestPool("", pool, subPool, nil, false)
869
+		if err == nil {
870
+			t.Fatal("Failed to detect wrong request: empty address space")
871
+		}
878 872
 
879
-	pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false)
880
-	if err != nil {
881
-		t.Fatalf("Unexpected failure: %v", err)
882
-	}
873
+		_, _, _, err = a.RequestPool(as, "", subPool, nil, false)
874
+		if err == nil {
875
+			t.Fatal("Failed to detect wrong request: subPool specified and no pool")
876
+		}
883 877
 
884
-	_, _, err = a.RequestAddress("", nil, nil)
885
-	if err == nil {
886
-		t.Fatal("Failed to detect wrong request: no pool id specified")
887
-	}
878
+		pid, _, _, err := a.RequestPool(as, pool, subPool, nil, false)
879
+		if err != nil {
880
+			t.Fatalf("Unexpected failure: %v", err)
881
+		}
888 882
 
889
-	ip := net.ParseIP("172.17.0.23")
890
-	_, _, err = a.RequestAddress(pid, ip, nil)
891
-	if err == nil {
892
-		t.Fatal("Failed to detect wrong request: requested IP from different subnet")
893
-	}
883
+		_, _, err = a.RequestAddress("", nil, nil)
884
+		if err == nil {
885
+			t.Fatal("Failed to detect wrong request: no pool id specified")
886
+		}
894 887
 
895
-	ip = net.ParseIP("192.168.0.50")
896
-	_, _, err = a.RequestAddress(pid, ip, nil)
897
-	if err != nil {
898
-		t.Fatalf("Unexpected failure: %v", err)
899
-	}
888
+		ip := net.ParseIP("172.17.0.23")
889
+		_, _, err = a.RequestAddress(pid, ip, nil)
890
+		if err == nil {
891
+			t.Fatal("Failed to detect wrong request: requested IP from different subnet")
892
+		}
900 893
 
901
-	err = a.ReleaseAddress("", ip)
902
-	if err == nil {
903
-		t.Fatal("Failed to detect wrong request: no pool id specified")
904
-	}
894
+		ip = net.ParseIP("192.168.0.50")
895
+		_, _, err = a.RequestAddress(pid, ip, nil)
896
+		if err != nil {
897
+			t.Fatalf("Unexpected failure: %v", err)
898
+		}
905 899
 
906
-	err = a.ReleaseAddress(pid, nil)
907
-	if err == nil {
908
-		t.Fatal("Failed to detect wrong request: no pool id specified")
909
-	}
900
+		err = a.ReleaseAddress("", ip)
901
+		if err == nil {
902
+			t.Fatal("Failed to detect wrong request: no pool id specified")
903
+		}
910 904
 
911
-	err = a.ReleaseAddress(pid, ip)
912
-	if err != nil {
913
-		t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip)
905
+		err = a.ReleaseAddress(pid, nil)
906
+		if err == nil {
907
+			t.Fatal("Failed to detect wrong request: no pool id specified")
908
+		}
909
+
910
+		err = a.ReleaseAddress(pid, ip)
911
+		if err != nil {
912
+			t.Fatalf("Unexpected failure: %v: %s, %s", err, pid, ip)
913
+		}
914 914
 	}
915 915
 }
916 916
 
... ...
@@ -951,65 +959,66 @@ func TestRelease(t *testing.T) {
951 951
 		subnet = "192.168.0.0/23"
952 952
 	)
953 953
 
954
-	a, err := getAllocator(true)
955
-	if err != nil {
956
-		t.Fatal(err)
957
-	}
958
-	pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
959
-	if err != nil {
960
-		t.Fatal(err)
961
-	}
954
+	for _, store := range []bool{false, true} {
955
+		a, err := getAllocator(store)
956
+		assert.NoError(t, err)
962 957
 
963
-	bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
958
+		pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
959
+		if err != nil {
960
+			t.Fatal(err)
961
+		}
964 962
 
965
-	// Allocate all addresses
966
-	for err != ipamapi.ErrNoAvailableIPs {
967
-		_, _, err = a.RequestAddress(pid, nil, nil)
968
-	}
963
+		bm := a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
969 964
 
970
-	toRelease := []struct {
971
-		address string
972
-	}{
973
-		{"192.168.0.1"},
974
-		{"192.168.0.2"},
975
-		{"192.168.0.3"},
976
-		{"192.168.0.4"},
977
-		{"192.168.0.5"},
978
-		{"192.168.0.6"},
979
-		{"192.168.0.7"},
980
-		{"192.168.0.8"},
981
-		{"192.168.0.9"},
982
-		{"192.168.0.10"},
983
-		{"192.168.0.30"},
984
-		{"192.168.0.31"},
985
-		{"192.168.1.32"},
986
-
987
-		{"192.168.0.254"},
988
-		{"192.168.1.1"},
989
-		{"192.168.1.2"},
990
-
991
-		{"192.168.1.3"},
992
-
993
-		{"192.168.1.253"},
994
-		{"192.168.1.254"},
995
-	}
996
-
997
-	// One by one, relase the address and request again. We should get the same IP
998
-	for i, inp := range toRelease {
999
-		ip0 := net.ParseIP(inp.address)
1000
-		a.ReleaseAddress(pid, ip0)
1001
-		bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
1002
-		if bm.Unselected() != 1 {
1003
-			t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected())
1004
-		}
1005
-
1006
-		nw, _, err := a.RequestAddress(pid, nil, nil)
1007
-		if err != nil {
1008
-			t.Fatalf("Failed to obtain the address: %s", err.Error())
965
+		// Allocate all addresses
966
+		for err != ipamapi.ErrNoAvailableIPs {
967
+			_, _, err = a.RequestAddress(pid, nil, nil)
968
+		}
969
+
970
+		toRelease := []struct {
971
+			address string
972
+		}{
973
+			{"192.168.0.1"},
974
+			{"192.168.0.2"},
975
+			{"192.168.0.3"},
976
+			{"192.168.0.4"},
977
+			{"192.168.0.5"},
978
+			{"192.168.0.6"},
979
+			{"192.168.0.7"},
980
+			{"192.168.0.8"},
981
+			{"192.168.0.9"},
982
+			{"192.168.0.10"},
983
+			{"192.168.0.30"},
984
+			{"192.168.0.31"},
985
+			{"192.168.1.32"},
986
+
987
+			{"192.168.0.254"},
988
+			{"192.168.1.1"},
989
+			{"192.168.1.2"},
990
+
991
+			{"192.168.1.3"},
992
+
993
+			{"192.168.1.253"},
994
+			{"192.168.1.254"},
1009 995
 		}
1010
-		ip := nw.IP
1011
-		if !ip0.Equal(ip) {
1012
-			t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip)
996
+
997
+		// One by one, relase the address and request again. We should get the same IP
998
+		for i, inp := range toRelease {
999
+			ip0 := net.ParseIP(inp.address)
1000
+			a.ReleaseAddress(pid, ip0)
1001
+			bm = a.addresses[SubnetKey{localAddressSpace, subnet, ""}]
1002
+			if bm.Unselected() != 1 {
1003
+				t.Fatalf("Failed to update free address count after release. Expected %d, Found: %d", i+1, bm.Unselected())
1004
+			}
1005
+
1006
+			nw, _, err := a.RequestAddress(pid, nil, nil)
1007
+			if err != nil {
1008
+				t.Fatalf("Failed to obtain the address: %s", err.Error())
1009
+			}
1010
+			ip := nw.IP
1011
+			if !ip0.Equal(ip) {
1012
+				t.Fatalf("Failed to obtain the same address. Expected: %s, Got: %s", ip0, ip)
1013
+			}
1013 1014
 		}
1014 1015
 	}
1015 1016
 }
... ...
@@ -1058,26 +1067,27 @@ func assertNRequests(t *testing.T, subnet string, numReq int, lastExpectedIP str
1058 1058
 	)
1059 1059
 
1060 1060
 	lastIP := net.ParseIP(lastExpectedIP)
1061
-	a, err := getAllocator(true)
1062
-	if err != nil {
1063
-		t.Fatal(err)
1064
-	}
1065
-	pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
1066
-	if err != nil {
1067
-		t.Fatal(err)
1068
-	}
1061
+	for _, store := range []bool{false, true} {
1062
+		a, err := getAllocator(store)
1063
+		assert.NoError(t, err)
1069 1064
 
1070
-	i := 0
1071
-	start := time.Now()
1072
-	for ; i < numReq; i++ {
1073
-		nw, _, err = a.RequestAddress(pid, nil, nil)
1074
-	}
1075
-	if printTime {
1076
-		fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet)
1077
-	}
1065
+		pid, _, _, err := a.RequestPool(localAddressSpace, subnet, "", nil, false)
1066
+		if err != nil {
1067
+			t.Fatal(err)
1068
+		}
1078 1069
 
1079
-	if !lastIP.Equal(nw.IP) {
1080
-		t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i)
1070
+		i := 0
1071
+		start := time.Now()
1072
+		for ; i < numReq; i++ {
1073
+			nw, _, err = a.RequestAddress(pid, nil, nil)
1074
+		}
1075
+		if printTime {
1076
+			fmt.Printf("\nTaken %v, to allocate %d addresses on %s\n", time.Since(start), numReq, subnet)
1077
+		}
1078
+
1079
+		if !lastIP.Equal(nw.IP) {
1080
+			t.Fatalf("Wrong last IP. Expected %s. Got: %s (err: %v, ind: %d)", lastExpectedIP, nw.IP.String(), err, i)
1081
+		}
1081 1082
 	}
1082 1083
 }
1083 1084
 
... ...
@@ -1111,15 +1121,15 @@ func BenchmarkRequest_8(b *testing.B) {
1111 1111
 }
1112 1112
 
1113 1113
 func TestAllocateRandomDeallocate(t *testing.T) {
1114
-	testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384)
1115
-	testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384)
1114
+	for _, store := range []bool{false, true} {
1115
+		testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384, store)
1116
+		testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384, store)
1117
+	}
1116 1118
 }
1117 1119
 
1118
-func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int) {
1119
-	ds, err := randomLocalStore(true)
1120
-	if err != nil {
1121
-		t.Fatal(err)
1122
-	}
1120
+func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int, store bool) {
1121
+	ds, err := randomLocalStore(store)
1122
+	assert.NoError(t, err)
1123 1123
 
1124 1124
 	a, err := NewAllocator(ds, nil)
1125 1125
 	if err != nil {
1126 1126
new file mode 100644
... ...
@@ -0,0 +1,239 @@
0
+package ipam
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"net"
6
+	"sync"
7
+	"testing"
8
+
9
+	"github.com/golang/sync/semaphore"
10
+
11
+	"github.com/docker/libnetwork/ipamapi"
12
+	"github.com/stretchr/testify/assert"
13
+)
14
+
15
+const (
16
+	all = iota
17
+	even
18
+	odd
19
+)
20
+
21
+type releaseMode uint
22
+
23
+type testContext struct {
24
+	a      *Allocator
25
+	opts   map[string]string
26
+	ipList []*net.IPNet
27
+	ipMap  map[string]bool
28
+	pid    string
29
+	maxIP  int
30
+}
31
+
32
+func newTestContext(t *testing.T, mask int, options map[string]string) *testContext {
33
+	a, err := getAllocator(true)
34
+	if err != nil {
35
+		t.Fatal(err)
36
+	}
37
+	a.addrSpaces["giallo"] = &addrSpace{
38
+		id:      dsConfigKey + "/" + "giallo",
39
+		ds:      a.addrSpaces[localAddressSpace].ds,
40
+		alloc:   a.addrSpaces[localAddressSpace].alloc,
41
+		scope:   a.addrSpaces[localAddressSpace].scope,
42
+		subnets: map[SubnetKey]*PoolData{},
43
+	}
44
+
45
+	network := fmt.Sprintf("192.168.100.0/%d", mask)
46
+	// total ips 2^(32-mask) - 2 (network and broadcast)
47
+	totalIps := 1<<uint(32-mask) - 2
48
+
49
+	pid, _, _, err := a.RequestPool("giallo", network, "", nil, false)
50
+	if err != nil {
51
+		t.Fatal(err)
52
+	}
53
+
54
+	return &testContext{
55
+		a:      a,
56
+		opts:   options,
57
+		ipList: make([]*net.IPNet, 0, totalIps),
58
+		ipMap:  make(map[string]bool),
59
+		pid:    pid,
60
+		maxIP:  totalIps,
61
+	}
62
+}
63
+
64
+func TestDebug(t *testing.T) {
65
+	tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
66
+	tctx.a.RequestAddress(tctx.pid, nil, map[string]string{ipamapi.AllocSerialPrefix: "true"})
67
+	tctx.a.RequestAddress(tctx.pid, nil, map[string]string{ipamapi.AllocSerialPrefix: "true"})
68
+}
69
+
70
+func TestFullAllocateRelease(t *testing.T) {
71
+	for _, parallelism := range []int64{2, 4, 8} {
72
+		for _, mask := range []int{29, 25, 24, 21} {
73
+			tctx := newTestContext(t, mask, map[string]string{ipamapi.AllocSerialPrefix: "true"})
74
+			allocate(t, tctx, parallelism)
75
+			release(t, tctx, all, parallelism)
76
+		}
77
+	}
78
+}
79
+
80
+func TestOddAllocateRelease(t *testing.T) {
81
+	for _, parallelism := range []int64{2, 4, 8} {
82
+		for _, mask := range []int{29, 25, 24, 21} {
83
+			tctx := newTestContext(t, mask, map[string]string{ipamapi.AllocSerialPrefix: "true"})
84
+			allocate(t, tctx, parallelism)
85
+			release(t, tctx, odd, parallelism)
86
+		}
87
+	}
88
+}
89
+
90
+func TestFullAllocateSerialReleaseParallel(t *testing.T) {
91
+	for _, parallelism := range []int64{1, 4, 8} {
92
+		tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
93
+		allocate(t, tctx, 1)
94
+		release(t, tctx, all, parallelism)
95
+	}
96
+}
97
+
98
+func TestOddAllocateSerialReleaseParallel(t *testing.T) {
99
+	for _, parallelism := range []int64{1, 4, 8} {
100
+		tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
101
+		allocate(t, tctx, 1)
102
+		release(t, tctx, odd, parallelism)
103
+	}
104
+}
105
+
106
+func TestEvenAllocateSerialReleaseParallel(t *testing.T) {
107
+	for _, parallelism := range []int64{1, 4, 8} {
108
+		tctx := newTestContext(t, 23, map[string]string{ipamapi.AllocSerialPrefix: "true"})
109
+		allocate(t, tctx, 1)
110
+		release(t, tctx, even, parallelism)
111
+	}
112
+}
113
+
114
+func allocate(t *testing.T, tctx *testContext, parallel int64) {
115
+	// Allocate the whole space
116
+	parallelExec := semaphore.NewWeighted(parallel)
117
+	routineNum := tctx.maxIP + 10
118
+	ch := make(chan *net.IPNet, routineNum)
119
+	var id int
120
+	var wg sync.WaitGroup
121
+	// routine loop
122
+	for {
123
+		wg.Add(1)
124
+		go func(id int) {
125
+			parallelExec.Acquire(context.Background(), 1)
126
+			ip, _, _ := tctx.a.RequestAddress(tctx.pid, nil, tctx.opts)
127
+			ch <- ip
128
+			parallelExec.Release(1)
129
+			wg.Done()
130
+		}(id)
131
+		id++
132
+		if id == routineNum {
133
+			break
134
+		}
135
+	}
136
+
137
+	// give time to all the go routines to finish
138
+	wg.Wait()
139
+
140
+	// process results
141
+	for i := 0; i < routineNum; i++ {
142
+		ip := <-ch
143
+		if ip == nil {
144
+			continue
145
+		}
146
+		if there, ok := tctx.ipMap[ip.String()]; ok && there {
147
+			t.Fatalf("Got duplicate IP %s", ip.String())
148
+			break
149
+		}
150
+		tctx.ipList = append(tctx.ipList, ip)
151
+		tctx.ipMap[ip.String()] = true
152
+	}
153
+
154
+	assert.Len(t, tctx.ipList, tctx.maxIP)
155
+	if len(tctx.ipList) != tctx.maxIP {
156
+		t.Fatal("missmatch number allocation")
157
+	}
158
+}
159
+
160
+func release(t *testing.T, tctx *testContext, mode releaseMode, parallel int64) {
161
+	var startIndex, increment, stopIndex, length int
162
+	switch mode {
163
+	case all:
164
+		startIndex = 0
165
+		increment = 1
166
+		stopIndex = tctx.maxIP - 1
167
+		length = tctx.maxIP
168
+	case odd, even:
169
+		if mode == odd {
170
+			startIndex = 1
171
+		}
172
+		increment = 2
173
+		stopIndex = tctx.maxIP - 1
174
+		length = tctx.maxIP / 2
175
+		if tctx.maxIP%2 > 0 {
176
+			length++
177
+		}
178
+	default:
179
+		t.Fatal("unsupported mode yet")
180
+	}
181
+
182
+	ipIndex := make([]int, 0, length)
183
+	// calculate the index to release from the ipList
184
+	for i := startIndex; ; i += increment {
185
+		ipIndex = append(ipIndex, i)
186
+		if i+increment > stopIndex {
187
+			break
188
+		}
189
+	}
190
+
191
+	var id int
192
+	parallelExec := semaphore.NewWeighted(parallel)
193
+	ch := make(chan *net.IPNet, len(ipIndex))
194
+	wg := sync.WaitGroup{}
195
+	for index := range ipIndex {
196
+		wg.Add(1)
197
+		go func(id, index int) {
198
+			parallelExec.Acquire(context.Background(), 1)
199
+			// logrus.Errorf("index %v", index)
200
+			// logrus.Errorf("list %v", tctx.ipList)
201
+			err := tctx.a.ReleaseAddress(tctx.pid, tctx.ipList[index].IP)
202
+			if err != nil {
203
+				t.Fatalf("routine %d got %v", id, err)
204
+			}
205
+			ch <- tctx.ipList[index]
206
+			parallelExec.Release(1)
207
+			wg.Done()
208
+		}(id, index)
209
+		id++
210
+	}
211
+	wg.Wait()
212
+
213
+	for i := 0; i < len(ipIndex); i++ {
214
+		ip := <-ch
215
+
216
+		// check if it is really free
217
+		_, _, err := tctx.a.RequestAddress(tctx.pid, ip.IP, nil)
218
+		assert.NoError(t, err, "ip %v not properly released", ip)
219
+		if err != nil {
220
+			t.Fatalf("ip %v not properly released, error:%v", ip, err)
221
+		}
222
+		err = tctx.a.ReleaseAddress(tctx.pid, ip.IP)
223
+		assert.NoError(t, err)
224
+
225
+		if there, ok := tctx.ipMap[ip.String()]; !ok || !there {
226
+			t.Fatalf("ip %v got double deallocated", ip)
227
+		}
228
+		tctx.ipMap[ip.String()] = false
229
+		for j, v := range tctx.ipList {
230
+			if v == ip {
231
+				tctx.ipList = append(tctx.ipList[:j], tctx.ipList[j+1:]...)
232
+				break
233
+			}
234
+		}
235
+	}
236
+
237
+	assert.Len(t, tctx.ipList, tctx.maxIP-length)
238
+}