github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/dial_test.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package p2p
    13  
    14  import (
    15  	"encoding/binary"
    16  	"net"
    17  	"reflect"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/davecgh/go-spew/spew"
    22  	"github.com/Sberex/go-sberex/p2p/discover"
    23  	"github.com/Sberex/go-sberex/p2p/netutil"
    24  )
    25  
    26  func init() {
    27  	spew.Config.Indent = "\t"
    28  }
    29  
    30  type dialtest struct {
    31  	init   *dialstate // state before and after the test.
    32  	rounds []round
    33  }
    34  
    35  type round struct {
    36  	peers []*Peer // current peer set
    37  	done  []task  // tasks that got done this round
    38  	new   []task  // the result must match this one
    39  }
    40  
    41  func runDialTest(t *testing.T, test dialtest) {
    42  	var (
    43  		vtime   time.Time
    44  		running int
    45  	)
    46  	pm := func(ps []*Peer) map[discover.NodeID]*Peer {
    47  		m := make(map[discover.NodeID]*Peer)
    48  		for _, p := range ps {
    49  			m[p.rw.id] = p
    50  		}
    51  		return m
    52  	}
    53  	for i, round := range test.rounds {
    54  		for _, task := range round.done {
    55  			running--
    56  			if running < 0 {
    57  				panic("running task counter underflow")
    58  			}
    59  			test.init.taskDone(task, vtime)
    60  		}
    61  
    62  		new := test.init.newTasks(running, pm(round.peers), vtime)
    63  		if !sametasks(new, round.new) {
    64  			t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
    65  				i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
    66  		}
    67  
    68  		// Time advances by 16 seconds on every round.
    69  		vtime = vtime.Add(16 * time.Second)
    70  		running += len(new)
    71  	}
    72  }
    73  
    74  type fakeTable []*discover.Node
    75  
    76  func (t fakeTable) Self() *discover.Node                     { return new(discover.Node) }
    77  func (t fakeTable) Close()                                   {}
    78  func (t fakeTable) Lookup(discover.NodeID) []*discover.Node  { return nil }
    79  func (t fakeTable) Resolve(discover.NodeID) *discover.Node   { return nil }
    80  func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
    81  
    82  // This test checks that dynamic dials are launched from discovery results.
    83  func TestDialStateDynDial(t *testing.T) {
    84  	runDialTest(t, dialtest{
    85  		init: newDialState(nil, nil, fakeTable{}, 5, nil),
    86  		rounds: []round{
    87  			// A discovery query is launched.
    88  			{
    89  				peers: []*Peer{
    90  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
    91  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
    92  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
    93  				},
    94  				new: []task{&discoverTask{}},
    95  			},
    96  			// Dynamic dials are launched when it completes.
    97  			{
    98  				peers: []*Peer{
    99  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   100  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   101  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   102  				},
   103  				done: []task{
   104  					&discoverTask{results: []*discover.Node{
   105  						{ID: uintID(2)}, // this one is already connected and not dialed.
   106  						{ID: uintID(3)},
   107  						{ID: uintID(4)},
   108  						{ID: uintID(5)},
   109  						{ID: uintID(6)}, // these are not tried because max dyn dials is 5
   110  						{ID: uintID(7)}, // ...
   111  					}},
   112  				},
   113  				new: []task{
   114  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   115  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   116  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   117  				},
   118  			},
   119  			// Some of the dials complete but no new ones are launched yet because
   120  			// the sum of active dial count and dynamic peer count is == maxDynDials.
   121  			{
   122  				peers: []*Peer{
   123  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   124  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   125  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   126  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   127  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   128  				},
   129  				done: []task{
   130  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   131  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   132  				},
   133  			},
   134  			// No new dial tasks are launched in the this round because
   135  			// maxDynDials has been reached.
   136  			{
   137  				peers: []*Peer{
   138  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   139  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   140  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   141  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   142  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   143  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   144  				},
   145  				done: []task{
   146  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   147  				},
   148  				new: []task{
   149  					&waitExpireTask{Duration: 14 * time.Second},
   150  				},
   151  			},
   152  			// In this round, the peer with id 2 drops off. The query
   153  			// results from last discovery lookup are reused.
   154  			{
   155  				peers: []*Peer{
   156  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   157  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   158  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   159  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   160  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   161  				},
   162  				new: []task{
   163  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   164  				},
   165  			},
   166  			// More peers (3,4) drop off and dial for ID 6 completes.
   167  			// The last query result from the discovery lookup is reused
   168  			// and a new one is spawned because more candidates are needed.
   169  			{
   170  				peers: []*Peer{
   171  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   172  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   173  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   174  				},
   175  				done: []task{
   176  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   177  				},
   178  				new: []task{
   179  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   180  					&discoverTask{},
   181  				},
   182  			},
   183  			// Peer 7 is connected, but there still aren't enough dynamic peers
   184  			// (4 out of 5). However, a discovery is already running, so ensure
   185  			// no new is started.
   186  			{
   187  				peers: []*Peer{
   188  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   189  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   190  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   191  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   192  				},
   193  				done: []task{
   194  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   195  				},
   196  			},
   197  			// Finish the running node discovery with an empty set. A new lookup
   198  			// should be immediately requested.
   199  			{
   200  				peers: []*Peer{
   201  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   202  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   203  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   204  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   205  				},
   206  				done: []task{
   207  					&discoverTask{},
   208  				},
   209  				new: []task{
   210  					&discoverTask{},
   211  				},
   212  			},
   213  		},
   214  	})
   215  }
   216  
   217  // Tests that bootnodes are dialed if no peers are connectd, but not otherwise.
   218  func TestDialStateDynDialBootnode(t *testing.T) {
   219  	bootnodes := []*discover.Node{
   220  		{ID: uintID(1)},
   221  		{ID: uintID(2)},
   222  		{ID: uintID(3)},
   223  	}
   224  	table := fakeTable{
   225  		{ID: uintID(4)},
   226  		{ID: uintID(5)},
   227  		{ID: uintID(6)},
   228  		{ID: uintID(7)},
   229  		{ID: uintID(8)},
   230  	}
   231  	runDialTest(t, dialtest{
   232  		init: newDialState(nil, bootnodes, table, 5, nil),
   233  		rounds: []round{
   234  			// 2 dynamic dials attempted, bootnodes pending fallback interval
   235  			{
   236  				new: []task{
   237  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   238  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   239  					&discoverTask{},
   240  				},
   241  			},
   242  			// No dials succeed, bootnodes still pending fallback interval
   243  			{
   244  				done: []task{
   245  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   246  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   247  				},
   248  			},
   249  			// No dials succeed, bootnodes still pending fallback interval
   250  			{},
   251  			// No dials succeed, 2 dynamic dials attempted and 1 bootnode too as fallback interval was reached
   252  			{
   253  				new: []task{
   254  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   255  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   256  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   257  				},
   258  			},
   259  			// No dials succeed, 2nd bootnode is attempted
   260  			{
   261  				done: []task{
   262  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   263  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   264  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   265  				},
   266  				new: []task{
   267  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   268  				},
   269  			},
   270  			// No dials succeed, 3rd bootnode is attempted
   271  			{
   272  				done: []task{
   273  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   274  				},
   275  				new: []task{
   276  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   277  				},
   278  			},
   279  			// No dials succeed, 1st bootnode is attempted again, expired random nodes retried
   280  			{
   281  				done: []task{
   282  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   283  				},
   284  				new: []task{
   285  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   286  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   287  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   288  				},
   289  			},
   290  			// Random dial succeeds, no more bootnodes are attempted
   291  			{
   292  				peers: []*Peer{
   293  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   294  				},
   295  				done: []task{
   296  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   297  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   298  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   299  				},
   300  			},
   301  		},
   302  	})
   303  }
   304  
   305  func TestDialStateDynDialFromTable(t *testing.T) {
   306  	// This table always returns the same random nodes
   307  	// in the order given below.
   308  	table := fakeTable{
   309  		{ID: uintID(1)},
   310  		{ID: uintID(2)},
   311  		{ID: uintID(3)},
   312  		{ID: uintID(4)},
   313  		{ID: uintID(5)},
   314  		{ID: uintID(6)},
   315  		{ID: uintID(7)},
   316  		{ID: uintID(8)},
   317  	}
   318  
   319  	runDialTest(t, dialtest{
   320  		init: newDialState(nil, nil, table, 10, nil),
   321  		rounds: []round{
   322  			// 5 out of 8 of the nodes returned by ReadRandomNodes are dialed.
   323  			{
   324  				new: []task{
   325  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   326  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   327  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   328  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   329  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   330  					&discoverTask{},
   331  				},
   332  			},
   333  			// Dialing nodes 1,2 succeeds. Dials from the lookup are launched.
   334  			{
   335  				peers: []*Peer{
   336  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   337  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   338  				},
   339  				done: []task{
   340  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   341  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   342  					&discoverTask{results: []*discover.Node{
   343  						{ID: uintID(10)},
   344  						{ID: uintID(11)},
   345  						{ID: uintID(12)},
   346  					}},
   347  				},
   348  				new: []task{
   349  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   350  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   351  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   352  					&discoverTask{},
   353  				},
   354  			},
   355  			// Dialing nodes 3,4,5 fails. The dials from the lookup succeed.
   356  			{
   357  				peers: []*Peer{
   358  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   359  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   360  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   361  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   362  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   363  				},
   364  				done: []task{
   365  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   366  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   367  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   368  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   369  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   370  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   371  				},
   372  			},
   373  			// Waiting for expiry. No waitExpireTask is launched because the
   374  			// discovery query is still running.
   375  			{
   376  				peers: []*Peer{
   377  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   378  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   379  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   380  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   381  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   382  				},
   383  			},
   384  			// Nodes 3,4 are not tried again because only the first two
   385  			// returned random nodes (nodes 1,2) are tried and they're
   386  			// already connected.
   387  			{
   388  				peers: []*Peer{
   389  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   390  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   391  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   392  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   393  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   394  				},
   395  			},
   396  		},
   397  	})
   398  }
   399  
   400  // This test checks that candidates that do not match the netrestrict list are not dialed.
   401  func TestDialStateNetRestrict(t *testing.T) {
   402  	// This table always returns the same random nodes
   403  	// in the order given below.
   404  	table := fakeTable{
   405  		{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
   406  		{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
   407  		{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
   408  		{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
   409  		{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
   410  		{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
   411  		{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
   412  		{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
   413  	}
   414  	restrict := new(netutil.Netlist)
   415  	restrict.Add("127.0.2.0/24")
   416  
   417  	runDialTest(t, dialtest{
   418  		init: newDialState(nil, nil, table, 10, restrict),
   419  		rounds: []round{
   420  			{
   421  				new: []task{
   422  					&dialTask{flags: dynDialedConn, dest: table[4]},
   423  					&discoverTask{},
   424  				},
   425  			},
   426  		},
   427  	})
   428  }
   429  
   430  // This test checks that static dials are launched.
   431  func TestDialStateStaticDial(t *testing.T) {
   432  	wantStatic := []*discover.Node{
   433  		{ID: uintID(1)},
   434  		{ID: uintID(2)},
   435  		{ID: uintID(3)},
   436  		{ID: uintID(4)},
   437  		{ID: uintID(5)},
   438  	}
   439  
   440  	runDialTest(t, dialtest{
   441  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   442  		rounds: []round{
   443  			// Static dials are launched for the nodes that
   444  			// aren't yet connected.
   445  			{
   446  				peers: []*Peer{
   447  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   448  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   449  				},
   450  				new: []task{
   451  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   452  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   453  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   454  				},
   455  			},
   456  			// No new tasks are launched in this round because all static
   457  			// nodes are either connected or still being dialed.
   458  			{
   459  				peers: []*Peer{
   460  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   461  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   462  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   463  				},
   464  				done: []task{
   465  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   466  				},
   467  			},
   468  			// No new dial tasks are launched because all static
   469  			// nodes are now connected.
   470  			{
   471  				peers: []*Peer{
   472  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   473  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   474  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   475  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   476  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   477  				},
   478  				done: []task{
   479  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   480  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   481  				},
   482  				new: []task{
   483  					&waitExpireTask{Duration: 14 * time.Second},
   484  				},
   485  			},
   486  			// Wait a round for dial history to expire, no new tasks should spawn.
   487  			{
   488  				peers: []*Peer{
   489  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   490  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   491  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   492  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   493  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   494  				},
   495  			},
   496  			// If a static node is dropped, it should be immediately redialed,
   497  			// irrespective whether it was originally static or dynamic.
   498  			{
   499  				peers: []*Peer{
   500  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   501  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   502  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   503  				},
   504  				new: []task{
   505  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   506  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   507  				},
   508  			},
   509  		},
   510  	})
   511  }
   512  
   513  // This test checks that static peers will be redialed immediately if they were re-added to a static list.
   514  func TestDialStaticAfterReset(t *testing.T) {
   515  	wantStatic := []*discover.Node{
   516  		{ID: uintID(1)},
   517  		{ID: uintID(2)},
   518  	}
   519  
   520  	rounds := []round{
   521  		// Static dials are launched for the nodes that aren't yet connected.
   522  		{
   523  			peers: nil,
   524  			new: []task{
   525  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   526  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   527  			},
   528  		},
   529  		// No new dial tasks, all peers are connected.
   530  		{
   531  			peers: []*Peer{
   532  				{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   533  				{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   534  			},
   535  			done: []task{
   536  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   537  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   538  			},
   539  			new: []task{
   540  				&waitExpireTask{Duration: 30 * time.Second},
   541  			},
   542  		},
   543  	}
   544  	dTest := dialtest{
   545  		init:   newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   546  		rounds: rounds,
   547  	}
   548  	runDialTest(t, dTest)
   549  	for _, n := range wantStatic {
   550  		dTest.init.removeStatic(n)
   551  		dTest.init.addStatic(n)
   552  	}
   553  	// without removing peers they will be considered recently dialed
   554  	runDialTest(t, dTest)
   555  }
   556  
   557  // This test checks that past dials are not retried for some time.
   558  func TestDialStateCache(t *testing.T) {
   559  	wantStatic := []*discover.Node{
   560  		{ID: uintID(1)},
   561  		{ID: uintID(2)},
   562  		{ID: uintID(3)},
   563  	}
   564  
   565  	runDialTest(t, dialtest{
   566  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   567  		rounds: []round{
   568  			// Static dials are launched for the nodes that
   569  			// aren't yet connected.
   570  			{
   571  				peers: nil,
   572  				new: []task{
   573  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   574  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   575  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   576  				},
   577  			},
   578  			// No new tasks are launched in this round because all static
   579  			// nodes are either connected or still being dialed.
   580  			{
   581  				peers: []*Peer{
   582  					{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   583  					{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   584  				},
   585  				done: []task{
   586  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   587  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   588  				},
   589  			},
   590  			// A salvage task is launched to wait for node 3's history
   591  			// entry to expire.
   592  			{
   593  				peers: []*Peer{
   594  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   595  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   596  				},
   597  				done: []task{
   598  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   599  				},
   600  				new: []task{
   601  					&waitExpireTask{Duration: 14 * time.Second},
   602  				},
   603  			},
   604  			// Still waiting for node 3's entry to expire in the cache.
   605  			{
   606  				peers: []*Peer{
   607  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   608  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   609  				},
   610  			},
   611  			// The cache entry for node 3 has expired and is retried.
   612  			{
   613  				peers: []*Peer{
   614  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   615  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   616  				},
   617  				new: []task{
   618  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   619  				},
   620  			},
   621  		},
   622  	})
   623  }
   624  
   625  func TestDialResolve(t *testing.T) {
   626  	resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444)
   627  	table := &resolveMock{answer: resolved}
   628  	state := newDialState(nil, nil, table, 0, nil)
   629  
   630  	// Check that the task is generated with an incomplete ID.
   631  	dest := discover.NewNode(uintID(1), nil, 0, 0)
   632  	state.addStatic(dest)
   633  	tasks := state.newTasks(0, nil, time.Time{})
   634  	if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
   635  		t.Fatalf("expected dial task, got %#v", tasks)
   636  	}
   637  
   638  	// Now run the task, it should resolve the ID once.
   639  	config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
   640  	srv := &Server{ntab: table, Config: config}
   641  	tasks[0].Do(srv)
   642  	if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
   643  		t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
   644  	}
   645  
   646  	// Report it as done to the dialer, which should update the static node record.
   647  	state.taskDone(tasks[0], time.Now())
   648  	if state.static[uintID(1)].dest != resolved {
   649  		t.Fatalf("state.dest not updated")
   650  	}
   651  }
   652  
   653  // compares task lists but doesn't care about the order.
   654  func sametasks(a, b []task) bool {
   655  	if len(a) != len(b) {
   656  		return false
   657  	}
   658  next:
   659  	for _, ta := range a {
   660  		for _, tb := range b {
   661  			if reflect.DeepEqual(ta, tb) {
   662  				continue next
   663  			}
   664  		}
   665  		return false
   666  	}
   667  	return true
   668  }
   669  
   670  func uintID(i uint32) discover.NodeID {
   671  	var id discover.NodeID
   672  	binary.BigEndian.PutUint32(id[:], i)
   673  	return id
   674  }
   675  
   676  // implements discoverTable for TestDialResolve
   677  type resolveMock struct {
   678  	resolveCalls []discover.NodeID
   679  	answer       *discover.Node
   680  }
   681  
   682  func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
   683  	t.resolveCalls = append(t.resolveCalls, id)
   684  	return t.answer
   685  }
   686  
   687  func (t *resolveMock) Self() *discover.Node                     { return new(discover.Node) }
   688  func (t *resolveMock) Close()                                   {}
   689  func (t *resolveMock) Bootstrap([]*discover.Node)               {}
   690  func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node  { return nil }
   691  func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }