github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/p2p/dial_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"encoding/binary"
     5  	"net"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/davecgh/go-spew/spew"
    11  	"github.com/neatlab/neatio/network/p2p/discover"
    12  	"github.com/neatlab/neatio/network/p2p/netutil"
    13  )
    14  
    15  func init() {
    16  	spew.Config.Indent = "\t"
    17  }
    18  
    19  type dialtest struct {
    20  	init   *dialstate
    21  	rounds []round
    22  }
    23  
    24  type round struct {
    25  	peers []*Peer
    26  	done  []task
    27  	new   []task
    28  }
    29  
    30  func runDialTest(t *testing.T, test dialtest) {
    31  	var (
    32  		vtime   time.Time
    33  		running int
    34  	)
    35  	pm := func(ps []*Peer) map[discover.NodeID]*Peer {
    36  		m := make(map[discover.NodeID]*Peer)
    37  		for _, p := range ps {
    38  			m[p.rw.id] = p
    39  		}
    40  		return m
    41  	}
    42  	for i, round := range test.rounds {
    43  		for _, task := range round.done {
    44  			running--
    45  			if running < 0 {
    46  				panic("running task counter underflow")
    47  			}
    48  			test.init.taskDone(task, vtime)
    49  		}
    50  
    51  		new := test.init.newTasks(running, pm(round.peers), vtime)
    52  		if !sametasks(new, round.new) {
    53  			t.Errorf("round %d: new tasks mismatch:\ngot %v\nwant %v\nstate: %v\nrunning: %v\n",
    54  				i, spew.Sdump(new), spew.Sdump(round.new), spew.Sdump(test.init), spew.Sdump(running))
    55  		}
    56  
    57  		vtime = vtime.Add(16 * time.Second)
    58  		running += len(new)
    59  	}
    60  }
    61  
    62  type fakeTable []*discover.Node
    63  
    64  func (t fakeTable) Self() *discover.Node                     { return new(discover.Node) }
    65  func (t fakeTable) Close()                                   {}
    66  func (t fakeTable) Lookup(discover.NodeID) []*discover.Node  { return nil }
    67  func (t fakeTable) Resolve(discover.NodeID) *discover.Node   { return nil }
    68  func (t fakeTable) ReadRandomNodes(buf []*discover.Node) int { return copy(buf, t) }
    69  
    70  func TestDialStateDynDial(t *testing.T) {
    71  	runDialTest(t, dialtest{
    72  		init: newDialState(nil, nil, fakeTable{}, 5, nil),
    73  		rounds: []round{
    74  
    75  			{
    76  				peers: []*Peer{
    77  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
    78  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
    79  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
    80  				},
    81  				new: []task{&discoverTask{}},
    82  			},
    83  
    84  			{
    85  				peers: []*Peer{
    86  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
    87  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
    88  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
    89  				},
    90  				done: []task{
    91  					&discoverTask{results: []*discover.Node{
    92  						{ID: uintID(2)},
    93  						{ID: uintID(3)},
    94  						{ID: uintID(4)},
    95  						{ID: uintID(5)},
    96  						{ID: uintID(6)},
    97  						{ID: uintID(7)},
    98  					}},
    99  				},
   100  				new: []task{
   101  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   102  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   103  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   104  				},
   105  			},
   106  
   107  			{
   108  				peers: []*Peer{
   109  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   110  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   111  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   112  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   113  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   114  				},
   115  				done: []task{
   116  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   117  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   118  				},
   119  			},
   120  
   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  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   129  				},
   130  				done: []task{
   131  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   132  				},
   133  				new: []task{
   134  					&waitExpireTask{Duration: 14 * time.Second},
   135  				},
   136  			},
   137  
   138  			{
   139  				peers: []*Peer{
   140  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   141  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   142  					{rw: &conn{flags: dynDialedConn, id: uintID(3)}},
   143  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   144  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   145  				},
   146  				new: []task{
   147  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   148  				},
   149  			},
   150  
   151  			{
   152  				peers: []*Peer{
   153  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   154  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   155  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   156  				},
   157  				done: []task{
   158  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(6)}},
   159  				},
   160  				new: []task{
   161  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   162  					&discoverTask{},
   163  				},
   164  			},
   165  
   166  			{
   167  				peers: []*Peer{
   168  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   169  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   170  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   171  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   172  				},
   173  				done: []task{
   174  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(7)}},
   175  				},
   176  			},
   177  
   178  			{
   179  				peers: []*Peer{
   180  					{rw: &conn{flags: staticDialedConn, id: uintID(0)}},
   181  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   182  					{rw: &conn{flags: dynDialedConn, id: uintID(5)}},
   183  					{rw: &conn{flags: dynDialedConn, id: uintID(7)}},
   184  				},
   185  				done: []task{
   186  					&discoverTask{},
   187  				},
   188  				new: []task{
   189  					&discoverTask{},
   190  				},
   191  			},
   192  		},
   193  	})
   194  }
   195  
   196  func TestDialStateDynDialBootnode(t *testing.T) {
   197  	bootnodes := []*discover.Node{
   198  		{ID: uintID(1)},
   199  		{ID: uintID(2)},
   200  		{ID: uintID(3)},
   201  	}
   202  	table := fakeTable{
   203  		{ID: uintID(4)},
   204  		{ID: uintID(5)},
   205  		{ID: uintID(6)},
   206  		{ID: uintID(7)},
   207  		{ID: uintID(8)},
   208  	}
   209  	runDialTest(t, dialtest{
   210  		init: newDialState(nil, bootnodes, table, 5, nil),
   211  		rounds: []round{
   212  
   213  			{
   214  				new: []task{
   215  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   216  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   217  					&discoverTask{},
   218  				},
   219  			},
   220  
   221  			{
   222  				done: []task{
   223  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   224  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   225  				},
   226  			},
   227  
   228  			{},
   229  
   230  			{
   231  				new: []task{
   232  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   233  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   234  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   235  				},
   236  			},
   237  
   238  			{
   239  				done: []task{
   240  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   241  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   242  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   243  				},
   244  				new: []task{
   245  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   246  				},
   247  			},
   248  
   249  			{
   250  				done: []task{
   251  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   252  				},
   253  				new: []task{
   254  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   255  				},
   256  			},
   257  
   258  			{
   259  				done: []task{
   260  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   261  				},
   262  				new: []task{
   263  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   264  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   265  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   266  				},
   267  			},
   268  
   269  			{
   270  				peers: []*Peer{
   271  					{rw: &conn{flags: dynDialedConn, id: uintID(4)}},
   272  				},
   273  				done: []task{
   274  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   275  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   276  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   277  				},
   278  			},
   279  		},
   280  	})
   281  }
   282  
   283  func TestDialStateDynDialFromTable(t *testing.T) {
   284  
   285  	table := fakeTable{
   286  		{ID: uintID(1)},
   287  		{ID: uintID(2)},
   288  		{ID: uintID(3)},
   289  		{ID: uintID(4)},
   290  		{ID: uintID(5)},
   291  		{ID: uintID(6)},
   292  		{ID: uintID(7)},
   293  		{ID: uintID(8)},
   294  	}
   295  
   296  	runDialTest(t, dialtest{
   297  		init: newDialState(nil, nil, table, 10, nil),
   298  		rounds: []round{
   299  
   300  			{
   301  				new: []task{
   302  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   303  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   304  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   305  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   306  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   307  					&discoverTask{},
   308  				},
   309  			},
   310  
   311  			{
   312  				peers: []*Peer{
   313  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   314  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   315  				},
   316  				done: []task{
   317  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(1)}},
   318  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(2)}},
   319  					&discoverTask{results: []*discover.Node{
   320  						{ID: uintID(10)},
   321  						{ID: uintID(11)},
   322  						{ID: uintID(12)},
   323  					}},
   324  				},
   325  				new: []task{
   326  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   327  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   328  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   329  					&discoverTask{},
   330  				},
   331  			},
   332  
   333  			{
   334  				peers: []*Peer{
   335  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   336  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   337  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   338  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   339  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   340  				},
   341  				done: []task{
   342  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(3)}},
   343  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(4)}},
   344  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(5)}},
   345  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(10)}},
   346  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(11)}},
   347  					&dialTask{flags: dynDialedConn, dest: &discover.Node{ID: uintID(12)}},
   348  				},
   349  			},
   350  
   351  			{
   352  				peers: []*Peer{
   353  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   354  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   355  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   356  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   357  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   358  				},
   359  			},
   360  
   361  			{
   362  				peers: []*Peer{
   363  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   364  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   365  					{rw: &conn{flags: dynDialedConn, id: uintID(10)}},
   366  					{rw: &conn{flags: dynDialedConn, id: uintID(11)}},
   367  					{rw: &conn{flags: dynDialedConn, id: uintID(12)}},
   368  				},
   369  			},
   370  		},
   371  	})
   372  }
   373  
   374  func TestDialStateNetRestrict(t *testing.T) {
   375  
   376  	table := fakeTable{
   377  		{ID: uintID(1), IP: net.ParseIP("127.0.0.1")},
   378  		{ID: uintID(2), IP: net.ParseIP("127.0.0.2")},
   379  		{ID: uintID(3), IP: net.ParseIP("127.0.0.3")},
   380  		{ID: uintID(4), IP: net.ParseIP("127.0.0.4")},
   381  		{ID: uintID(5), IP: net.ParseIP("127.0.2.5")},
   382  		{ID: uintID(6), IP: net.ParseIP("127.0.2.6")},
   383  		{ID: uintID(7), IP: net.ParseIP("127.0.2.7")},
   384  		{ID: uintID(8), IP: net.ParseIP("127.0.2.8")},
   385  	}
   386  	restrict := new(netutil.Netlist)
   387  	restrict.Add("127.0.2.0/24")
   388  
   389  	runDialTest(t, dialtest{
   390  		init: newDialState(nil, nil, table, 10, restrict),
   391  		rounds: []round{
   392  			{
   393  				new: []task{
   394  					&dialTask{flags: dynDialedConn, dest: table[4]},
   395  					&discoverTask{},
   396  				},
   397  			},
   398  		},
   399  	})
   400  }
   401  
   402  func TestDialStateStaticDial(t *testing.T) {
   403  	wantStatic := []*discover.Node{
   404  		{ID: uintID(1)},
   405  		{ID: uintID(2)},
   406  		{ID: uintID(3)},
   407  		{ID: uintID(4)},
   408  		{ID: uintID(5)},
   409  	}
   410  
   411  	runDialTest(t, dialtest{
   412  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   413  		rounds: []round{
   414  
   415  			{
   416  				peers: []*Peer{
   417  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   418  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   419  				},
   420  				new: []task{
   421  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   422  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   423  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   424  				},
   425  			},
   426  
   427  			{
   428  				peers: []*Peer{
   429  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   430  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   431  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   432  				},
   433  				done: []task{
   434  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   435  				},
   436  			},
   437  
   438  			{
   439  				peers: []*Peer{
   440  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   441  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   442  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   443  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   444  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   445  				},
   446  				done: []task{
   447  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   448  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(5)}},
   449  				},
   450  				new: []task{
   451  					&waitExpireTask{Duration: 14 * time.Second},
   452  				},
   453  			},
   454  
   455  			{
   456  				peers: []*Peer{
   457  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   458  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   459  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   460  					{rw: &conn{flags: staticDialedConn, id: uintID(4)}},
   461  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   462  				},
   463  			},
   464  
   465  			{
   466  				peers: []*Peer{
   467  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   468  					{rw: &conn{flags: staticDialedConn, id: uintID(3)}},
   469  					{rw: &conn{flags: staticDialedConn, id: uintID(5)}},
   470  				},
   471  				new: []task{
   472  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   473  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(4)}},
   474  				},
   475  			},
   476  		},
   477  	})
   478  }
   479  
   480  func TestDialStaticAfterReset(t *testing.T) {
   481  	wantStatic := []*discover.Node{
   482  		{ID: uintID(1)},
   483  		{ID: uintID(2)},
   484  	}
   485  
   486  	rounds := []round{
   487  
   488  		{
   489  			peers: nil,
   490  			new: []task{
   491  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   492  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   493  			},
   494  		},
   495  
   496  		{
   497  			peers: []*Peer{
   498  				{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   499  				{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   500  			},
   501  			done: []task{
   502  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   503  				&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   504  			},
   505  			new: []task{
   506  				&waitExpireTask{Duration: 30 * time.Second},
   507  			},
   508  		},
   509  	}
   510  	dTest := dialtest{
   511  		init:   newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   512  		rounds: rounds,
   513  	}
   514  	runDialTest(t, dTest)
   515  	for _, n := range wantStatic {
   516  		dTest.init.removeStatic(n)
   517  		dTest.init.addStatic(n)
   518  	}
   519  
   520  	runDialTest(t, dTest)
   521  }
   522  
   523  func TestDialStateCache(t *testing.T) {
   524  	wantStatic := []*discover.Node{
   525  		{ID: uintID(1)},
   526  		{ID: uintID(2)},
   527  		{ID: uintID(3)},
   528  	}
   529  
   530  	runDialTest(t, dialtest{
   531  		init: newDialState(wantStatic, nil, fakeTable{}, 0, nil),
   532  		rounds: []round{
   533  
   534  			{
   535  				peers: nil,
   536  				new: []task{
   537  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   538  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   539  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   540  				},
   541  			},
   542  
   543  			{
   544  				peers: []*Peer{
   545  					{rw: &conn{flags: staticDialedConn, id: uintID(1)}},
   546  					{rw: &conn{flags: staticDialedConn, id: uintID(2)}},
   547  				},
   548  				done: []task{
   549  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(1)}},
   550  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(2)}},
   551  				},
   552  			},
   553  
   554  			{
   555  				peers: []*Peer{
   556  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   557  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   558  				},
   559  				done: []task{
   560  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   561  				},
   562  				new: []task{
   563  					&waitExpireTask{Duration: 14 * time.Second},
   564  				},
   565  			},
   566  
   567  			{
   568  				peers: []*Peer{
   569  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   570  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   571  				},
   572  			},
   573  
   574  			{
   575  				peers: []*Peer{
   576  					{rw: &conn{flags: dynDialedConn, id: uintID(1)}},
   577  					{rw: &conn{flags: dynDialedConn, id: uintID(2)}},
   578  				},
   579  				new: []task{
   580  					&dialTask{flags: staticDialedConn, dest: &discover.Node{ID: uintID(3)}},
   581  				},
   582  			},
   583  		},
   584  	})
   585  }
   586  
   587  func TestDialResolve(t *testing.T) {
   588  	resolved := discover.NewNode(uintID(1), net.IP{127, 0, 55, 234}, 3333, 4444)
   589  	table := &resolveMock{answer: resolved}
   590  	state := newDialState(nil, nil, table, 0, nil)
   591  
   592  	dest := discover.NewNode(uintID(1), nil, 0, 0)
   593  	state.addStatic(dest)
   594  	tasks := state.newTasks(0, nil, time.Time{})
   595  	if !reflect.DeepEqual(tasks, []task{&dialTask{flags: staticDialedConn, dest: dest}}) {
   596  		t.Fatalf("expected dial task, got %#v", tasks)
   597  	}
   598  
   599  	config := Config{Dialer: TCPDialer{&net.Dialer{Deadline: time.Now().Add(-5 * time.Minute)}}}
   600  	srv := &Server{ntab: table, Config: config}
   601  	tasks[0].Do(srv)
   602  	if !reflect.DeepEqual(table.resolveCalls, []discover.NodeID{dest.ID}) {
   603  		t.Fatalf("wrong resolve calls, got %v", table.resolveCalls)
   604  	}
   605  
   606  	state.taskDone(tasks[0], time.Now())
   607  	if state.static[uintID(1)].dest != resolved {
   608  		t.Fatalf("state.dest not updated")
   609  	}
   610  }
   611  
   612  func sametasks(a, b []task) bool {
   613  	if len(a) != len(b) {
   614  		return false
   615  	}
   616  next:
   617  	for _, ta := range a {
   618  		for _, tb := range b {
   619  			if reflect.DeepEqual(ta, tb) {
   620  				continue next
   621  			}
   622  		}
   623  		return false
   624  	}
   625  	return true
   626  }
   627  
   628  func uintID(i uint32) discover.NodeID {
   629  	var id discover.NodeID
   630  	binary.BigEndian.PutUint32(id[:], i)
   631  	return id
   632  }
   633  
   634  type resolveMock struct {
   635  	resolveCalls []discover.NodeID
   636  	answer       *discover.Node
   637  }
   638  
   639  func (t *resolveMock) Resolve(id discover.NodeID) *discover.Node {
   640  	t.resolveCalls = append(t.resolveCalls, id)
   641  	return t.answer
   642  }
   643  
   644  func (t *resolveMock) Self() *discover.Node                     { return new(discover.Node) }
   645  func (t *resolveMock) Close()                                   {}
   646  func (t *resolveMock) Bootstrap([]*discover.Node)               {}
   647  func (t *resolveMock) Lookup(discover.NodeID) []*discover.Node  { return nil }
   648  func (t *resolveMock) ReadRandomNodes(buf []*discover.Node) int { return 0 }