|
|
@@ -19,6 +19,7 @@ package dnsdisc
|
|
|
import (
|
|
|
"context"
|
|
|
"crypto/ecdsa"
|
|
|
+ "errors"
|
|
|
"math/rand"
|
|
|
"reflect"
|
|
|
"testing"
|
|
|
@@ -176,11 +177,62 @@ func TestIteratorNodeUpdates(t *testing.T) {
|
|
|
t.Fatal(err)
|
|
|
}
|
|
|
|
|
|
- // sync the original tree.
|
|
|
+ // Sync the original tree.
|
|
|
resolver.add(tree1.ToTXT("n"))
|
|
|
checkIterator(t, it, nodes[:25])
|
|
|
|
|
|
- // Update some nodes and ensure RandomNode returns the new nodes as well.
|
|
|
+ // Ensure RandomNode returns the new nodes after the tree is updated.
|
|
|
+ updateSomeNodes(nodesSeed1, nodes)
|
|
|
+ tree2, _ := makeTestTree("n", nodes, nil)
|
|
|
+ resolver.clear()
|
|
|
+ resolver.add(tree2.ToTXT("n"))
|
|
|
+ t.Log("tree updated")
|
|
|
+
|
|
|
+ clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
|
+ checkIterator(t, it, nodes)
|
|
|
+}
|
|
|
+
|
|
|
+// This test checks that the tree root is rechecked when a couple of leaf
|
|
|
+// requests have failed. The test is just like TestIteratorNodeUpdates, but
|
|
|
+// without advancing the clock by recheckInterval after the tree update.
|
|
|
+func TestIteratorRootRecheckOnFail(t *testing.T) {
|
|
|
+ var (
|
|
|
+ clock = new(mclock.Simulated)
|
|
|
+ nodes = testNodes(nodesSeed1, 30)
|
|
|
+ resolver = newMapResolver()
|
|
|
+ c = NewClient(Config{
|
|
|
+ Resolver: resolver,
|
|
|
+ Logger: testlog.Logger(t, log.LvlTrace),
|
|
|
+ RecheckInterval: 20 * time.Minute,
|
|
|
+ RateLimit: 500,
|
|
|
+ // Disabling the cache is required for this test because the client doesn't
|
|
|
+ // notice leaf failures if all records are cached.
|
|
|
+ CacheLimit: 1,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ c.clock = clock
|
|
|
+ tree1, url := makeTestTree("n", nodes[:25], nil)
|
|
|
+ it, err := c.NewIterator(url)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Sync the original tree.
|
|
|
+ resolver.add(tree1.ToTXT("n"))
|
|
|
+ checkIterator(t, it, nodes[:25])
|
|
|
+
|
|
|
+ // Ensure RandomNode returns the new nodes after the tree is updated.
|
|
|
+ updateSomeNodes(nodesSeed1, nodes)
|
|
|
+ tree2, _ := makeTestTree("n", nodes, nil)
|
|
|
+ resolver.clear()
|
|
|
+ resolver.add(tree2.ToTXT("n"))
|
|
|
+ t.Log("tree updated")
|
|
|
+
|
|
|
+ checkIterator(t, it, nodes)
|
|
|
+}
|
|
|
+
|
|
|
+// updateSomeNodes applies ENR updates to some of the given nodes.
|
|
|
+func updateSomeNodes(keySeed int64, nodes []*enode.Node) {
|
|
|
keys := testKeys(nodesSeed1, len(nodes))
|
|
|
for i, n := range nodes[:len(nodes)/2] {
|
|
|
r := n.Record()
|
|
|
@@ -190,11 +242,6 @@ func TestIteratorNodeUpdates(t *testing.T) {
|
|
|
n2, _ := enode.New(enode.ValidSchemes, r)
|
|
|
nodes[i] = n2
|
|
|
}
|
|
|
- tree2, _ := makeTestTree("n", nodes, nil)
|
|
|
- clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
|
- resolver.clear()
|
|
|
- resolver.add(tree2.ToTXT("n"))
|
|
|
- checkIterator(t, it, nodes)
|
|
|
}
|
|
|
|
|
|
// This test verifies that randomIterator re-checks the root of the tree to catch
|
|
|
@@ -230,9 +277,10 @@ func TestIteratorLinkUpdates(t *testing.T) {
|
|
|
// Add link to tree3, remove link to tree2.
|
|
|
tree1, _ = makeTestTree("t1", nodes[:10], []string{url3})
|
|
|
resolver.add(tree1.ToTXT("t1"))
|
|
|
- clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
|
t.Log("tree1 updated")
|
|
|
|
|
|
+ clock.Run(c.cfg.RecheckInterval + 1*time.Second)
|
|
|
+
|
|
|
var wantNodes []*enode.Node
|
|
|
wantNodes = append(wantNodes, tree1.Nodes()...)
|
|
|
wantNodes = append(wantNodes, tree3.Nodes()...)
|
|
|
@@ -345,5 +393,5 @@ func (mr mapResolver) LookupTXT(ctx context.Context, name string) ([]string, err
|
|
|
if record, ok := mr[name]; ok {
|
|
|
return []string{record}, nil
|
|
|
}
|
|
|
- return nil, nil
|
|
|
+ return nil, errors.New("not found")
|
|
|
}
|