1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Improve ipam test coverage

- Test random de-allocation of allocated addresses
  which is closer to real use case
- Test db reconstruction after read from datastore

Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
Alessandro Boch 2015-12-13 00:35:05 -08:00
parent 3881fa3063
commit 4cb0d27cf9
2 changed files with 188 additions and 14 deletions

View file

@ -486,21 +486,28 @@ func (a *Allocator) getAddress(nw *net.IPNet, bitmask *bitseq.Handle, prefAddres
// DumpDatabase dumps the internal info
func (a *Allocator) DumpDatabase() string {
a.Lock()
defer a.Unlock()
aspaces := make(map[string]*addrSpace, len(a.addrSpaces))
for as, aSpace := range a.addrSpaces {
aspaces[as] = aSpace
}
a.Unlock()
var s string
for as, aSpace := range a.addrSpaces {
for as, aSpace := range aspaces {
s = fmt.Sprintf("\n\n%s Config", as)
aSpace.Lock()
for k, config := range aSpace.subnets {
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%v: %v", k, config))
if config.Range == nil {
a.retrieveBitmask(k, config.Pool)
}
}
aSpace.Unlock()
}
s = fmt.Sprintf("%s\n\nBitmasks", s)
for k, bm := range a.addresses {
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n\t%s: %s\n\t%d", k, bm, bm.Unselected()))
s = fmt.Sprintf("%s%s", s, fmt.Sprintf("\n%s: %s", k, bm))
}
return s

View file

@ -4,8 +4,8 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net"
"os"
"testing"
"time"
@ -43,16 +43,6 @@ func randomLocalStore() (datastore.DataStore, error) {
})
}
// enable w/ upper case
func TestMain(m *testing.M) {
var err error
if err != nil {
fmt.Println(err)
}
os.Exit(m.Run())
}
func getAllocator() (*Allocator, error) {
ds, err := randomLocalStore()
if err != nil {
@ -1001,3 +991,180 @@ func BenchmarkRequest_8(b *testing.B) {
a, _ := getAllocator()
benchmarkRequest(b, a, "10.0.0.0/8")
}
func TestAllocateRandomDeallocate(t *testing.T) {
testAllocateRandomDeallocate(t, "172.25.0.0/16", "", 384)
testAllocateRandomDeallocate(t, "172.25.0.0/16", "172.25.252.0/22", 384)
}
func testAllocateRandomDeallocate(t *testing.T, pool, subPool string, num int) {
ds, err := randomLocalStore()
if err != nil {
t.Fatal(err)
}
a, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
pid, _, _, err := a.RequestPool(localAddressSpace, pool, subPool, nil, false)
if err != nil {
t.Fatal(err)
}
// Allocate num ip addresses
indices := make(map[int]*net.IPNet, num)
allocated := make(map[string]bool, num)
for i := 0; i < num; i++ {
ip, _, err := a.RequestAddress(pid, nil, nil)
if err != nil {
t.Fatal(err)
}
ips := ip.String()
if _, ok := allocated[ips]; ok {
t.Fatalf("Address %s is already allocated", ips)
}
allocated[ips] = true
indices[i] = ip
}
if len(indices) != len(allocated) || len(indices) != num {
t.Fatalf("Unexpected number of allocated addresses: (%d,%d).", len(indices), len(allocated))
}
seed := time.Now().Unix()
rand.Seed(seed)
// Deallocate half of the allocated addresses following a random pattern
pattern := rand.Perm(num)
for i := 0; i < num/2; i++ {
idx := pattern[i]
ip := indices[idx]
err := a.ReleaseAddress(pid, ip.IP)
if err != nil {
t.Fatalf("Unexpected failure on deallocation of %s: %v.\nSeed: %d.", ip, err, seed)
}
delete(indices, idx)
delete(allocated, ip.String())
}
// Request a quarter of addresses
for i := 0; i < num/2; i++ {
ip, _, err := a.RequestAddress(pid, nil, nil)
if err != nil {
t.Fatal(err)
}
ips := ip.String()
if _, ok := allocated[ips]; ok {
t.Fatalf("\nAddress %s is already allocated.\nSeed: %d.", ips, seed)
}
allocated[ips] = true
}
if len(allocated) != num {
t.Fatalf("Unexpected number of allocated addresses: %d.\nSeed: %d.", len(allocated), seed)
}
}
func TestRetrieveFromStore(t *testing.T) {
num := 200
ds, err := randomLocalStore()
if err != nil {
t.Fatal(err)
}
a, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
pid, _, _, err := a.RequestPool(localAddressSpace, "172.25.0.0/16", "", nil, false)
if err != nil {
t.Fatal(err)
}
for i := 0; i < num; i++ {
if _, _, err := a.RequestAddress(pid, nil, nil); err != nil {
t.Fatal(err)
}
}
// Restore
a1, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
a1.refresh(localAddressSpace)
db := a.DumpDatabase()
db1 := a1.DumpDatabase()
if db != db1 {
t.Fatalf("Unexpected db change.\nExpected:%s\nGot:%s", db, db1)
}
checkDBEquality(a, a1, t)
pid, _, _, err = a1.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.1.0/24", nil, false)
if err != nil {
t.Fatal(err)
}
for i := 0; i < num/2; i++ {
if _, _, err := a1.RequestAddress(pid, nil, nil); err != nil {
t.Fatal(err)
}
}
// Restore
a2, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
a2.refresh(localAddressSpace)
checkDBEquality(a1, a2, t)
pid, _, _, err = a2.RequestPool(localAddressSpace, "172.25.0.0/16", "172.25.2.0/24", nil, false)
if err != nil {
t.Fatal(err)
}
for i := 0; i < num/2; i++ {
if _, _, err := a2.RequestAddress(pid, nil, nil); err != nil {
t.Fatal(err)
}
}
// Restore
a3, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
a3.refresh(localAddressSpace)
checkDBEquality(a2, a3, t)
pid, _, _, err = a3.RequestPool(localAddressSpace, "172.26.0.0/16", "", nil, false)
if err != nil {
t.Fatal(err)
}
for i := 0; i < num/2; i++ {
if _, _, err := a3.RequestAddress(pid, nil, nil); err != nil {
t.Fatal(err)
}
}
// Restore
a4, err := NewAllocator(ds, nil)
if err != nil {
t.Fatal(err)
}
a4.refresh(localAddressSpace)
checkDBEquality(a3, a4, t)
}
func checkDBEquality(a1, a2 *Allocator, t *testing.T) {
for k, cnf1 := range a1.addrSpaces[localAddressSpace].subnets {
cnf2 := a2.addrSpaces[localAddressSpace].subnets[k]
if cnf1.String() != cnf2.String() {
t.Fatalf("%s\n%s", cnf1, cnf2)
}
if cnf1.Range == nil {
a2.retrieveBitmask(k, cnf1.Pool)
}
}
for k, bm1 := range a1.addresses {
bm2 := a2.addresses[k]
if bm1.String() != bm2.String() {
t.Fatalf("%s\n%s", bm1, bm2)
}
}
}