tidy Address helper functions, make ordering of members consistent in allocate and claim, make linter happier, remove some unused items, and update some comments
735 lines
25 KiB
Go
735 lines
25 KiB
Go
package ring
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"math/rand"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/weaveworks/weave/common"
|
|
"github.com/weaveworks/weave/ipam/address"
|
|
"github.com/weaveworks/weave/router"
|
|
wt "github.com/weaveworks/weave/testing"
|
|
)
|
|
|
|
var (
|
|
peer1name, _ = router.PeerNameFromString("01:00:00:00:02:00")
|
|
peer2name, _ = router.PeerNameFromString("02:00:00:00:02:00")
|
|
peer3name, _ = router.PeerNameFromString("03:00:00:00:02:00")
|
|
|
|
start, end = ParseIP("10.0.0.0"), ParseIP("10.0.0.255")
|
|
dot10, dot245 = ParseIP("10.0.0.10"), ParseIP("10.0.0.245")
|
|
dot250 = ParseIP("10.0.0.250")
|
|
middle = ParseIP("10.0.0.128")
|
|
)
|
|
|
|
func ParseIP(s string) address.Address {
|
|
addr, _ := address.ParseIP(s)
|
|
return addr
|
|
}
|
|
|
|
func TestInvariants(t *testing.T) {
|
|
ring := New(start, end, peer1name)
|
|
|
|
// Check ring is sorted
|
|
ring.Entries = []*entry{{Token: dot245, Peer: peer1name}, {Token: dot10, Peer: peer2name}}
|
|
wt.AssertTrue(t, ring.checkInvariants() == ErrNotSorted, "Expected error")
|
|
|
|
// Check tokens don't appear twice
|
|
ring.Entries = []*entry{{Token: dot245, Peer: peer1name}, {Token: dot245, Peer: peer2name}}
|
|
wt.AssertTrue(t, ring.checkInvariants() == ErrTokenRepeated, "Expected error")
|
|
|
|
// Check tokens are in bounds
|
|
ring = New(dot10, dot245, peer1name)
|
|
ring.Entries = []*entry{{Token: start, Peer: peer1name}}
|
|
wt.AssertTrue(t, ring.checkInvariants() == ErrTokenOutOfRange, "Expected error")
|
|
|
|
ring.Entries = []*entry{{Token: end, Peer: peer1name}}
|
|
wt.AssertTrue(t, ring.checkInvariants() == ErrTokenOutOfRange, "Expected error")
|
|
}
|
|
|
|
func TestInsert(t *testing.T) {
|
|
ring := New(start, end, peer1name)
|
|
ring.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
|
|
|
|
wt.AssertPanic(t, func() {
|
|
ring.Entries.insert(entry{Token: start, Peer: peer1name})
|
|
})
|
|
|
|
ring.Entries.entry(0).Free = 0
|
|
ring.Entries.insert(entry{Token: dot245, Peer: peer1name})
|
|
ring2 := New(start, end, peer1name)
|
|
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Free: 0}, {Token: dot245, Peer: peer1name}}
|
|
wt.AssertEquals(t, ring, ring2)
|
|
|
|
ring.Entries.insert(entry{Token: dot10, Peer: peer1name})
|
|
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Free: 0}, {Token: dot10, Peer: peer1name}, {Token: dot245, Peer: peer1name}}
|
|
wt.AssertEquals(t, ring, ring2)
|
|
}
|
|
|
|
func TestBetween(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
|
|
|
|
// First off, in a ring where everything is owned by the peer
|
|
// between should return true for everything
|
|
for i := 1; i <= 255; i++ {
|
|
ip := ParseIP(fmt.Sprintf("10.0.0.%d", i))
|
|
wt.AssertTrue(t, ring1.Entries.between(ip, 0, 1), "between should be true!")
|
|
}
|
|
|
|
// Now, construct a ring with entries at +10 and -10
|
|
// And check the correct behaviour
|
|
|
|
ring1.Entries = []*entry{{Token: dot10, Peer: peer1name}, {Token: dot245, Peer: peer2name}}
|
|
ring1.assertInvariants()
|
|
for i := 10; i <= 244; i++ {
|
|
ipStr := fmt.Sprintf("10.0.0.%d", i)
|
|
ip := ParseIP(ipStr)
|
|
wt.AssertTrue(t, ring1.Entries.between(ip, 0, 1),
|
|
fmt.Sprintf("Between should be true for %s!", ipStr))
|
|
wt.AssertFalse(t, ring1.Entries.between(ip, 1, 2),
|
|
fmt.Sprintf("Between should be false for %s!", ipStr))
|
|
}
|
|
for i := 0; i <= 9; i++ {
|
|
ipStr := fmt.Sprintf("10.0.0.%d", i)
|
|
ip := ParseIP(ipStr)
|
|
wt.AssertFalse(t, ring1.Entries.between(ip, 0, 1),
|
|
fmt.Sprintf("Between should be false for %s!", ipStr))
|
|
wt.AssertTrue(t, ring1.Entries.between(ip, 1, 2),
|
|
fmt.Sprintf("Between should be true for %s!", ipStr))
|
|
}
|
|
for i := 245; i <= 255; i++ {
|
|
ipStr := fmt.Sprintf("10.0.0.%d", i)
|
|
ip := ParseIP(ipStr)
|
|
wt.AssertFalse(t, ring1.Entries.between(ip, 0, 1),
|
|
fmt.Sprintf("Between should be false for %s!", ipStr))
|
|
wt.AssertTrue(t, ring1.Entries.between(ip, 1, 2),
|
|
fmt.Sprintf("Between should be true for %s!", ipStr))
|
|
}
|
|
}
|
|
|
|
func TestGrantSimple(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
// Claim everything for peer1
|
|
ring1.ClaimItAll()
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer1name, Free: 255}})
|
|
|
|
// Now grant everything to peer2
|
|
ring1.GrantRangeToHost(start, end, peer2name)
|
|
ring2.Entries = []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}}
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// Now spint back to peer 1
|
|
ring2.GrantRangeToHost(dot10, end, peer1name)
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer1name, Free: 245}}
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// And spint back to peer 2 again
|
|
ring1.GrantRangeToHost(dot245, end, peer2name)
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer2name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer1name, Free: 235, Version: 1},
|
|
{Token: dot245, Peer: peer2name, Free: 10}})
|
|
|
|
// Grant range spanning a live token
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer1name, Free: 235}, {Token: dot245, Peer: peer1name, Free: 10}}
|
|
ring1.GrantRangeToHost(dot10, end, peer2name)
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer1name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer2name, Free: 235, Version: 1},
|
|
{Token: dot245, Peer: peer2name, Free: 10, Version: 1}})
|
|
}
|
|
|
|
func TestGrantSplit(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
// Claim everything for peer1
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 255}}
|
|
ring2.Merge(*ring1)
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// Now grant a split range to peer2
|
|
ring1.GrantRangeToHost(dot10, dot245, peer2name)
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer1name, Free: 10, Version: 1},
|
|
{Token: dot10, Peer: peer2name, Free: 235},
|
|
{Token: dot245, Peer: peer1name, Free: 10}})
|
|
ring1.assertInvariants()
|
|
|
|
// Grant range spanning a live token, and inserting a new token
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer1name, Free: 118}, {Token: middle, Peer: peer1name, Free: 127}}
|
|
ring1.GrantRangeToHost(dot10, dot245, peer2name)
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer1name, Free: 10, Version: 2},
|
|
{Token: dot10, Peer: peer2name, Free: 118, Version: 1},
|
|
{Token: middle, Peer: peer2name, Free: 117, Version: 1},
|
|
{Token: dot245, Peer: peer1name, Free: 10, Version: 0}})
|
|
ring1.assertInvariants()
|
|
}
|
|
|
|
func TestMergeSimple(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
// Claim everything for peer1
|
|
ring1.ClaimItAll()
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer1name, Free: 128, Version: 1},
|
|
{Token: middle, Peer: peer2name, Free: 127}})
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// Now to two different operations on either side,
|
|
// check we can Merge again
|
|
ring1.GrantRangeToHost(start, middle, peer2name)
|
|
ring2.GrantRangeToHost(middle, end, peer1name)
|
|
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127, Version: 1}})
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
}
|
|
|
|
func TestMergeErrors(t *testing.T) {
|
|
// Cannot Merge in an invalid ring
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}, {Token: start, Peer: peer2name}}
|
|
wt.AssertTrue(t, ring1.Merge(*ring2) == ErrNotSorted, "Expected ErrNotSorted")
|
|
|
|
// Should Merge two rings for different ranges
|
|
ring2 = New(start, middle, peer2name)
|
|
ring2.Entries = []*entry{}
|
|
wt.AssertTrue(t, ring1.Merge(*ring2) == ErrDifferentSubnets, "Expected ErrDifferentSubnets")
|
|
|
|
// Cannot Merge newer version of entry I own
|
|
ring2 = New(start, end, peer2name)
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
|
|
ring2.Entries = []*entry{{Token: start, Peer: peer1name, Version: 1}}
|
|
wt.AssertTrue(t, ring1.Merge(*ring2) == ErrNewerVersion, "Expected ErrNewerVersion")
|
|
|
|
// Cannot Merge two entries with same version but different hosts
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
|
|
ring2.Entries = []*entry{{Token: start, Peer: peer2name}}
|
|
wt.AssertTrue(t, ring1.Merge(*ring2) == ErrInvalidEntry, "Expected ErrInvalidEntry")
|
|
|
|
// Cannot Merge an entry into a range I own
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
|
|
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}}
|
|
wt.AssertTrue(t, ring1.Merge(*ring2) == ErrEntryInMyRange, "Expected ErrEntryInMyRange")
|
|
}
|
|
|
|
func TestMergeMore(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
assertRing := func(ring *Ring, entries entries) {
|
|
wt.AssertEquals(t, ring.Entries, entries)
|
|
}
|
|
|
|
assertRing(ring1, []*entry{})
|
|
assertRing(ring2, []*entry{})
|
|
|
|
// Claim everything for peer1
|
|
ring1.ClaimItAll()
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
assertRing(ring2, []*entry{})
|
|
|
|
// Check the Merge sends it to the other ring
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
|
|
// Give everything to peer2
|
|
ring1.GrantRangeToHost(start, end, peer2name)
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
|
|
|
|
// And carve off some space
|
|
ring2.GrantRangeToHost(middle, end, peer1name)
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127}})
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 255, Version: 1}})
|
|
|
|
// And Merge back
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127}})
|
|
|
|
// This should be a no-op
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer2name, Free: 128, Version: 2},
|
|
{Token: middle, Peer: peer1name, Free: 127}})
|
|
}
|
|
|
|
func TestMergeSplit(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
// Claim everything for peer2
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 255}}
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// Now grant a split range to peer1
|
|
ring2.GrantRangeToHost(dot10, dot245, peer1name)
|
|
wt.AssertEquals(t, ring2.Entries, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
|
|
{Token: dot10, Peer: peer1name, Free: 235},
|
|
{Token: dot245, Peer: peer2name, Free: 10}})
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
|
|
{Token: dot10, Peer: peer1name, Free: 235},
|
|
{Token: dot245, Peer: peer2name, Free: 10}})
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
}
|
|
|
|
func TestMergeSplit2(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
// Claim everything for peer2
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 250}, {Token: dot250, Peer: peer2name, Free: 5}}
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
|
|
// Now grant a split range to peer1
|
|
ring2.GrantRangeToHost(dot10, dot245, peer1name)
|
|
wt.AssertEquals(t, ring2.Entries, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
|
|
{Token: dot10, Peer: peer1name, Free: 235},
|
|
{Token: dot245, Peer: peer2name, Free: 5}, {Token: dot250, Peer: peer2name, Free: 5}})
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
wt.AssertEquals(t, ring1.Entries, entries{{Token: start, Peer: peer2name, Free: 10, Version: 1},
|
|
{Token: dot10, Peer: peer1name, Free: 235},
|
|
{Token: dot245, Peer: peer2name, Free: 5}, {Token: dot250, Peer: peer2name, Free: 5}})
|
|
wt.AssertEquals(t, ring1.Entries, ring2.Entries)
|
|
}
|
|
|
|
// A simple test, very similar to above, but using the marshalling to byte[]s
|
|
func TestGossip(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
assertRing := func(ring *Ring, entries entries) {
|
|
wt.AssertEquals(t, ring.Entries, entries)
|
|
}
|
|
|
|
assertRing(ring1, []*entry{})
|
|
assertRing(ring2, []*entry{})
|
|
|
|
// Claim everything for peer1
|
|
ring1.ClaimItAll()
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
assertRing(ring2, []*entry{})
|
|
|
|
// Check the Merge sends it to the other ring
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
assertRing(ring1, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
assertRing(ring2, []*entry{{Token: start, Peer: peer1name, Free: 255}})
|
|
}
|
|
|
|
func TestFindFree(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
|
|
_, err := ring1.ChoosePeerToAskForSpace(start, end)
|
|
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
|
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
|
|
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
|
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
|
|
|
// We shouldn't return outselves
|
|
ring1.ReportFree(map[address.Address]address.Offset{start: 10})
|
|
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
|
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
|
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 1},
|
|
{Token: middle, Peer: peer1name, Free: 1}}
|
|
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
|
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
|
ring1.assertInvariants()
|
|
|
|
// We should return others
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 1}}
|
|
peer, err := ring1.ChoosePeerToAskForSpace(start, end)
|
|
wt.AssertSuccess(t, err)
|
|
wt.AssertEquals(t, peer, peer2name)
|
|
|
|
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 1},
|
|
{Token: middle, Peer: peer3name, Free: 1}}
|
|
peer, err = ring1.ChoosePeerToAskForSpace(start, middle)
|
|
wt.AssertSuccess(t, err)
|
|
wt.AssertEquals(t, peer, peer2name)
|
|
|
|
peer, err = ring1.ChoosePeerToAskForSpace(middle, end)
|
|
wt.AssertSuccess(t, err)
|
|
wt.AssertEquals(t, peer, peer3name)
|
|
ring1.assertInvariants()
|
|
}
|
|
|
|
func TestReportFree(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
ring1.ClaimItAll()
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
|
|
freespace := make(map[address.Address]address.Offset)
|
|
for _, r := range ring2.OwnedRanges() {
|
|
freespace[r.Start] = 0
|
|
}
|
|
ring2.ReportFree(freespace)
|
|
}
|
|
|
|
func TestMisc(t *testing.T) {
|
|
ring := New(start, end, peer1name)
|
|
|
|
wt.AssertTrue(t, ring.Empty(), "empty")
|
|
|
|
ring.ClaimItAll()
|
|
println(ring.String())
|
|
}
|
|
|
|
func TestEmptyGossip(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
ring1.ClaimItAll()
|
|
// This used to panic, and it shouldn't
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
}
|
|
|
|
func TestMergeOldMessage(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
ring1.ClaimItAll()
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
|
|
ring1.GrantRangeToHost(middle, end, peer1name)
|
|
wt.AssertSuccess(t, ring1.Merge(*ring2))
|
|
}
|
|
|
|
func TestSplitRangeAtBeginning(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring2 := New(start, end, peer2name)
|
|
|
|
ring1.ClaimItAll()
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
|
|
ring1.GrantRangeToHost(start, middle, peer2name)
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
}
|
|
|
|
func TestOwnedRange(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
ring1.ClaimItAll()
|
|
|
|
wt.AssertEquals(t, ring1.OwnedRanges(), []address.Range{{Start: start, End: end}})
|
|
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
wt.AssertEquals(t, ring1.OwnedRanges(), []address.Range{{Start: start, End: middle}})
|
|
|
|
ring2 := New(start, end, peer2name)
|
|
ring2.Merge(*ring1)
|
|
wt.AssertEquals(t, ring2.OwnedRanges(), []address.Range{{Start: middle, End: end}})
|
|
|
|
ring2.Entries = []*entry{{Token: middle, Peer: peer2name}}
|
|
wt.AssertEquals(t, ring2.OwnedRanges(),
|
|
[]address.Range{{Start: start, End: middle}, {Start: middle, End: end}})
|
|
|
|
ring2.Entries = []*entry{{Token: dot10, Peer: peer2name}, {Token: middle, Peer: peer2name}}
|
|
wt.AssertEquals(t, ring2.OwnedRanges(),
|
|
[]address.Range{{Start: start, End: dot10}, {Start: dot10, End: middle},
|
|
{Start: middle, End: end}})
|
|
}
|
|
|
|
func TestTransfer(t *testing.T) {
|
|
// First test just checks if we can grant some range to a host, when we transfer it, we get it back
|
|
ring1 := New(start, end, peer1name)
|
|
ring1.ClaimItAll()
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
ring1.Transfer(peer2name, peer1name)
|
|
wt.AssertEquals(t, ring1.OwnedRanges(), []address.Range{{start, middle}, {middle, end}})
|
|
|
|
// Second test is what happens when a token exists at the end of a range but is transferred
|
|
// - does it get resurrected correctly?
|
|
ring1 = New(start, end, peer1name)
|
|
ring1.ClaimItAll()
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
ring1.Transfer(peer2name, peer1name)
|
|
ring1.GrantRangeToHost(dot10, middle, peer2name)
|
|
wt.AssertEquals(t, ring1.OwnedRanges(), []address.Range{{start, dot10}, {middle, end}})
|
|
}
|
|
|
|
func TestOwner(t *testing.T) {
|
|
ring1 := New(start, end, peer1name)
|
|
wt.AssertTrue(t, ring1.Contains(start), "start should be in ring")
|
|
wt.AssertFalse(t, ring1.Contains(end), "end should not be in ring")
|
|
|
|
wt.AssertEquals(t, ring1.Owner(start), router.UnknownPeerName)
|
|
|
|
ring1.ClaimItAll()
|
|
ring1.GrantRangeToHost(middle, end, peer2name)
|
|
wt.AssertEquals(t, ring1.Owner(start), peer1name)
|
|
wt.AssertEquals(t, ring1.Owner(middle), peer2name)
|
|
wt.AssertPanic(t, func() {
|
|
ring1.Owner(end)
|
|
})
|
|
}
|
|
|
|
type addressSlice []address.Address
|
|
|
|
func (s addressSlice) Len() int { return len(s) }
|
|
func (s addressSlice) Less(i, j int) bool { return s[i] < s[j] }
|
|
func (s addressSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
func TestFuzzRing(t *testing.T) {
|
|
var (
|
|
numPeers = 25
|
|
iterations = 1000
|
|
)
|
|
|
|
peers := make([]router.PeerName, numPeers)
|
|
for i := 0; i < numPeers; i++ {
|
|
peer, _ := router.PeerNameFromString(fmt.Sprintf("%02d:00:00:00:02:00", i))
|
|
peers[i] = peer
|
|
}
|
|
|
|
// Make a valid, random ring
|
|
makeGoodRandomRing := func() *Ring {
|
|
addressSpace := end - start
|
|
numTokens := rand.Intn(int(addressSpace))
|
|
|
|
tokenMap := make(map[address.Address]bool)
|
|
for i := 0; i < numTokens; i++ {
|
|
tokenMap[address.Address(rand.Intn(int(addressSpace)))] = true
|
|
}
|
|
var tokens []address.Address
|
|
for token := range tokenMap {
|
|
tokens = append(tokens, token)
|
|
}
|
|
sort.Sort(addressSlice(tokens))
|
|
|
|
peer := peers[rand.Intn(len(peers))]
|
|
ring := New(start, end, peer)
|
|
for _, token := range tokens {
|
|
peer = peers[rand.Intn(len(peers))]
|
|
ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer})
|
|
}
|
|
|
|
ring.assertInvariants()
|
|
return ring
|
|
}
|
|
|
|
for i := 0; i < iterations; i++ {
|
|
// make 2 random rings
|
|
ring1 := makeGoodRandomRing()
|
|
ring2 := makeGoodRandomRing()
|
|
|
|
// Merge them - this might fail, we don't care
|
|
// We just want to make sure it doesn't panic
|
|
ring1.Merge(*ring2)
|
|
|
|
// Check whats left still passes assertions
|
|
ring1.assertInvariants()
|
|
ring2.assertInvariants()
|
|
}
|
|
|
|
// Make an invalid, random ring
|
|
makeBadRandomRing := func() *Ring {
|
|
addressSpace := end - start
|
|
numTokens := rand.Intn(int(addressSpace))
|
|
tokens := make([]address.Address, numTokens)
|
|
for i := 0; i < numTokens; i++ {
|
|
tokens[i] = address.Address(rand.Intn(int(addressSpace)))
|
|
}
|
|
|
|
peer := peers[rand.Intn(len(peers))]
|
|
ring := New(start, end, peer)
|
|
for _, token := range tokens {
|
|
peer = peers[rand.Intn(len(peers))]
|
|
ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer})
|
|
}
|
|
|
|
return ring
|
|
}
|
|
|
|
for i := 0; i < iterations; i++ {
|
|
// make 2 random rings
|
|
ring1 := makeGoodRandomRing()
|
|
ring2 := makeBadRandomRing()
|
|
|
|
// Merge them - this might fail, we don't care
|
|
// We just want to make sure it doesn't panic
|
|
ring1.Merge(*ring2)
|
|
|
|
// Check whats left still passes assertions
|
|
ring1.assertInvariants()
|
|
}
|
|
}
|
|
|
|
func TestFuzzRingHard(t *testing.T) {
|
|
//common.InitDefaultLogging(true)
|
|
var (
|
|
numPeers = 100
|
|
iterations = 3000
|
|
peers []router.PeerName
|
|
rings []*Ring
|
|
nextPeerID = 0
|
|
)
|
|
|
|
addPeer := func() {
|
|
peer, _ := router.PeerNameFromString(fmt.Sprintf("%02d:%02d:00:00:00:00", nextPeerID/10, nextPeerID%10))
|
|
common.Debug.Printf("%s: Adding peer", peer)
|
|
nextPeerID++
|
|
peers = append(peers, peer)
|
|
rings = append(rings, New(start, end, peer))
|
|
}
|
|
|
|
for i := 0; i < numPeers; i++ {
|
|
addPeer()
|
|
}
|
|
|
|
rings[0].ClaimItAll()
|
|
|
|
randomPeer := func(exclude int) (int, router.PeerName, *Ring) {
|
|
var peerIndex int
|
|
if exclude >= 0 {
|
|
peerIndex = rand.Intn(len(peers) - 1)
|
|
if peerIndex == exclude {
|
|
peerIndex++
|
|
}
|
|
} else {
|
|
peerIndex = rand.Intn(len(peers))
|
|
}
|
|
return peerIndex, peers[peerIndex], rings[peerIndex]
|
|
}
|
|
|
|
// Keep a map of index -> ranges, as these are a little expensive to
|
|
// calculate for every ring on every iteration.
|
|
var theRanges = make(map[int][]address.Range)
|
|
theRanges[0] = rings[0].OwnedRanges()
|
|
|
|
addOrRmPeer := func() {
|
|
if len(peers) < numPeers {
|
|
addPeer()
|
|
return
|
|
}
|
|
|
|
peerIndex, peername, _ := randomPeer(-1)
|
|
// Remove peer from our state
|
|
peers = append(peers[:peerIndex], peers[peerIndex+1:]...)
|
|
rings = append(rings[:peerIndex], rings[peerIndex+1:]...)
|
|
theRanges = make(map[int][]address.Range)
|
|
|
|
// Transfer the space for this peer on another peer, but not this one
|
|
_, otherPeername, otherRing := randomPeer(peerIndex)
|
|
|
|
// We need to be in a ~converged ring to rmpeer
|
|
for _, ring := range rings {
|
|
wt.AssertSuccess(t, otherRing.Merge(*ring))
|
|
}
|
|
|
|
common.Debug.Printf("%s: transferring from peer %s", otherPeername, peername)
|
|
otherRing.Transfer(peername, peername)
|
|
|
|
// And now tell everyone about the transfer - rmpeer is
|
|
// not partition safe
|
|
for i, ring := range rings {
|
|
wt.AssertSuccess(t, ring.Merge(*otherRing))
|
|
theRanges[i] = ring.OwnedRanges()
|
|
}
|
|
}
|
|
|
|
doGrantOrGossip := func() {
|
|
var ringsWithRanges = make([]int, 0, len(rings))
|
|
for index, ranges := range theRanges {
|
|
if len(ranges) > 0 {
|
|
ringsWithRanges = append(ringsWithRanges, index)
|
|
}
|
|
}
|
|
|
|
if len(ringsWithRanges) > 0 {
|
|
// Produce a random split in a random owned range, given to a random peer
|
|
indexWithRanges := ringsWithRanges[rand.Intn(len(ringsWithRanges))]
|
|
ownedRanges := theRanges[indexWithRanges]
|
|
ring := rings[indexWithRanges]
|
|
|
|
rangeToSplit := ownedRanges[rand.Intn(len(ownedRanges))]
|
|
size := address.Subtract(rangeToSplit.End, rangeToSplit.Start)
|
|
ipInRange := address.Add(rangeToSplit.Start, address.Offset(rand.Intn(int(size))))
|
|
_, peerToGiveTo, _ := randomPeer(-1)
|
|
common.Debug.Printf("%s: Granting [%v, %v) to %s", ring.Peer, ipInRange, rangeToSplit.End, peerToGiveTo)
|
|
ring.GrantRangeToHost(ipInRange, rangeToSplit.End, peerToGiveTo)
|
|
|
|
// Now 'gossip' this to a random host (note, note could be same host as above)
|
|
otherIndex, _, otherRing := randomPeer(-1)
|
|
common.Debug.Printf("%s: 'Gossiping' to %s", ring.Peer, otherRing.Peer)
|
|
wt.AssertSuccess(t, otherRing.Merge(*ring))
|
|
|
|
theRanges[indexWithRanges] = ring.OwnedRanges()
|
|
theRanges[otherIndex] = otherRing.OwnedRanges()
|
|
return
|
|
}
|
|
|
|
// No rings think they own anything (as gossip might be behind)
|
|
// We're going to pick a random host (which has entries) and gossip
|
|
// it to a random host (which may or may not have entries).
|
|
var ringsWithEntries = make([]*Ring, 0, len(rings))
|
|
for _, ring := range rings {
|
|
if len(ring.Entries) > 0 {
|
|
ringsWithEntries = append(ringsWithEntries, ring)
|
|
}
|
|
}
|
|
ring1 := ringsWithEntries[rand.Intn(len(ringsWithEntries))]
|
|
ring2index, _, ring2 := randomPeer(-1)
|
|
common.Debug.Printf("%s: 'Gossiping' to %s", ring1.Peer, ring2.Peer)
|
|
wt.AssertSuccess(t, ring2.Merge(*ring1))
|
|
theRanges[ring2index] = ring2.OwnedRanges()
|
|
}
|
|
|
|
for i := 0; i < iterations; i++ {
|
|
// about 1 in 10 times, rmpeer or add host
|
|
n := rand.Intn(10)
|
|
switch {
|
|
case n < 1:
|
|
addOrRmPeer()
|
|
default:
|
|
doGrantOrGossip()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (r *Ring) ClaimItAll() {
|
|
r.ClaimForPeers([]router.PeerName{r.Peer})
|
|
}
|
|
|
|
func (es entries) String() string {
|
|
var buffer bytes.Buffer
|
|
fmt.Fprintf(&buffer, "[")
|
|
for i, entry := range es {
|
|
fmt.Fprintf(&buffer, "%+v", *entry)
|
|
if i+1 < len(es) {
|
|
fmt.Fprintf(&buffer, " ")
|
|
}
|
|
}
|
|
fmt.Fprintf(&buffer, "]")
|
|
return buffer.String()
|
|
}
|