@ -19,6 +19,7 @@ package dnsdisc
import (
import (
"context"
"context"
"crypto/ecdsa"
"crypto/ecdsa"
"errors"
"math/rand"
"math/rand"
"reflect"
"reflect"
"testing"
"testing"
@ -176,11 +177,62 @@ func TestIteratorNodeUpdates(t *testing.T) {
t . Fatal ( err )
t . Fatal ( err )
}
}
// s ync the original tree.
// S ync the original tree.
resolver . add ( tree1 . ToTXT ( "n" ) )
resolver . add ( tree1 . ToTXT ( "n" ) )
checkIterator ( t , it , nodes [ : 25 ] )
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 ) )
keys := testKeys ( nodesSeed1 , len ( nodes ) )
for i , n := range nodes [ : len ( nodes ) / 2 ] {
for i , n := range nodes [ : len ( nodes ) / 2 ] {
r := n . Record ( )
r := n . Record ( )
@ -190,11 +242,6 @@ func TestIteratorNodeUpdates(t *testing.T) {
n2 , _ := enode . New ( enode . ValidSchemes , r )
n2 , _ := enode . New ( enode . ValidSchemes , r )
nodes [ i ] = n2
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
// 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.
// Add link to tree3, remove link to tree2.
tree1 , _ = makeTestTree ( "t1" , nodes [ : 10 ] , [ ] string { url3 } )
tree1 , _ = makeTestTree ( "t1" , nodes [ : 10 ] , [ ] string { url3 } )
resolver . add ( tree1 . ToTXT ( "t1" ) )
resolver . add ( tree1 . ToTXT ( "t1" ) )
clock . Run ( c . cfg . RecheckInterval + 1 * time . Second )
t . Log ( "tree1 updated" )
t . Log ( "tree1 updated" )
clock . Run ( c . cfg . RecheckInterval + 1 * time . Second )
var wantNodes [ ] * enode . Node
var wantNodes [ ] * enode . Node
wantNodes = append ( wantNodes , tree1 . Nodes ( ) ... )
wantNodes = append ( wantNodes , tree1 . Nodes ( ) ... )
wantNodes = append ( wantNodes , tree3 . 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 {
if record , ok := mr [ name ] ; ok {
return [ ] string { record } , nil
return [ ] string { record } , nil
}
}
return nil , nil
return nil , errors . New ( "not found" )
}
}