package ipam import ( "context" "fmt" "math/rand" "net" "sort" "sync" "sync/atomic" "testing" "time" "github.com/docker/libnetwork/ipamapi" "github.com/stretchr/testify/assert" "golang.org/x/sync/semaphore" ) const ( all = iota even odd ) type releaseMode uint type testContext struct { a *Allocator opts map[string]string ipList []*net.IPNet ipMap map[string]bool pid string maxIP int } func newTestContext(t *testing.T, mask int, options map[string]string) *testContext { a, err := getAllocator(false) if err != nil { t.Fatal(err) } a.addrSpaces["giallo"] = &addrSpace{ id: dsConfigKey + "/" + "giallo", ds: a.addrSpaces[localAddressSpace].ds, alloc: a.addrSpaces[localAddressSpace].alloc, scope: a.addrSpaces[localAddressSpace].scope, subnets: map[SubnetKey]*PoolData{}, } network := fmt.Sprintf("192.168.100.0/%d", mask) // total ips 2^(32-mask) - 2 (network and broadcast) totalIps := 1< 0 { length++ } default: t.Fatal("unsupported mode yet") } ipIndex := make([]int, 0, length) // calculate the index to release from the ipList for i := startIndex; ; i += increment { ipIndex = append(ipIndex, i) if i+increment > stopIndex { break } } var id int parallelExec := semaphore.NewWeighted(parallel) ch := make(chan *net.IPNet, len(ipIndex)) wg := sync.WaitGroup{} for index := range ipIndex { wg.Add(1) go func(id, index int) { parallelExec.Acquire(context.Background(), 1) // logrus.Errorf("index %v", index) // logrus.Errorf("list %v", tctx.ipList) err := tctx.a.ReleaseAddress(tctx.pid, tctx.ipList[index].IP) if err != nil { t.Fatalf("routine %d got %v", id, err) } ch <- tctx.ipList[index] parallelExec.Release(1) wg.Done() }(id, index) id++ } wg.Wait() for i := 0; i < len(ipIndex); i++ { ip := <-ch // check if it is really free _, _, err := tctx.a.RequestAddress(tctx.pid, ip.IP, nil) assert.NoError(t, err, "ip %v not properly released", ip) if err != nil { t.Fatalf("ip %v not properly released, error:%v", ip, err) } err = tctx.a.ReleaseAddress(tctx.pid, ip.IP) assert.NoError(t, err) if there, ok := tctx.ipMap[ip.String()]; !ok || !there { t.Fatalf("ip %v got double deallocated", ip) } tctx.ipMap[ip.String()] = false for j, v := range tctx.ipList { if v == ip { tctx.ipList = append(tctx.ipList[:j], tctx.ipList[j+1:]...) break } } } assert.Len(t, tctx.ipList, tctx.maxIP-length) }