|
|
@@ -66,6 +66,48 @@ func TestTable_pingReplace(t *testing.T) {
|
|
|
doit(false, false)
|
|
|
}
|
|
|
|
|
|
+func TestBucket_bumpNoDuplicates(t *testing.T) {
|
|
|
+ t.Parallel()
|
|
|
+ cfg := &quick.Config{
|
|
|
+ MaxCount: 1000,
|
|
|
+ Rand: quickrand,
|
|
|
+ Values: func(args []reflect.Value, rand *rand.Rand) {
|
|
|
+ // generate a random list of nodes. this will be the content of the bucket.
|
|
|
+ n := rand.Intn(bucketSize-1) + 1
|
|
|
+ nodes := make([]*Node, n)
|
|
|
+ for i := range nodes {
|
|
|
+ nodes[i] = &Node{ID: randomID(NodeID{}, 200)}
|
|
|
+ }
|
|
|
+ args[0] = reflect.ValueOf(nodes)
|
|
|
+ // generate random bump positions.
|
|
|
+ bumps := make([]int, rand.Intn(100))
|
|
|
+ for i := range bumps {
|
|
|
+ bumps[i] = rand.Intn(len(nodes))
|
|
|
+ }
|
|
|
+ args[1] = reflect.ValueOf(bumps)
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ prop := func(nodes []*Node, bumps []int) (ok bool) {
|
|
|
+ b := &bucket{entries: make([]*Node, len(nodes))}
|
|
|
+ copy(b.entries, nodes)
|
|
|
+ for i, pos := range bumps {
|
|
|
+ b.bump(b.entries[pos])
|
|
|
+ if hasDuplicates(b.entries) {
|
|
|
+ t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps))
|
|
|
+ for _, n := range b.entries {
|
|
|
+ t.Logf(" %p", n)
|
|
|
+ }
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ if err := quick.Check(prop, cfg); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
func fillBucket(tab *Table, ld int) (last *Node) {
|
|
|
b := tab.buckets[ld]
|
|
|
for len(b.entries) < bucketSize {
|