github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/p2p/discover/udp_test.go (about)

     1  package discover
     2  
     3  import (
     4  	"fmt"
     5  	logpkg "log"
     6  	"net"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/jonasnick/go-ethereum/logger"
    12  )
    13  
    14  func init() {
    15  	logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, logpkg.LstdFlags, logger.ErrorLevel))
    16  }
    17  
    18  func TestUDP_ping(t *testing.T) {
    19  	t.Parallel()
    20  
    21  	n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
    22  	n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
    23  	defer n1.Close()
    24  	defer n2.Close()
    25  
    26  	if err := n1.net.ping(n2.self); err != nil {
    27  		t.Fatalf("ping error: %v", err)
    28  	}
    29  	if find(n2, n1.self.ID) == nil {
    30  		t.Errorf("node 2 does not contain id of node 1")
    31  	}
    32  	if e := find(n1, n2.self.ID); e != nil {
    33  		t.Errorf("node 1 does contains id of node 2: %v", e)
    34  	}
    35  }
    36  
    37  func find(tab *Table, id NodeID) *Node {
    38  	for _, b := range tab.buckets {
    39  		for _, e := range b.entries {
    40  			if e.ID == id {
    41  				return e
    42  			}
    43  		}
    44  	}
    45  	return nil
    46  }
    47  
    48  func TestUDP_findnode(t *testing.T) {
    49  	t.Parallel()
    50  
    51  	n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
    52  	n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
    53  	defer n1.Close()
    54  	defer n2.Close()
    55  
    56  	// put a few nodes into n2. the exact distribution shouldn't
    57  	// matter much, altough we need to take care not to overflow
    58  	// any bucket.
    59  	target := randomID(n1.self.ID, 100)
    60  	nodes := &nodesByDistance{target: target}
    61  	for i := 0; i < bucketSize; i++ {
    62  		n2.add([]*Node{&Node{
    63  			IP:       net.IP{1, 2, 3, byte(i)},
    64  			DiscPort: i + 2,
    65  			TCPPort:  i + 2,
    66  			ID:       randomID(n2.self.ID, i+2),
    67  		}})
    68  	}
    69  	n2.add(nodes.entries)
    70  	n2.bumpOrAdd(n1.self.ID, &net.UDPAddr{IP: n1.self.IP, Port: n1.self.DiscPort})
    71  	expected := n2.closest(target, bucketSize)
    72  
    73  	err := runUDP(10, func() error {
    74  		result, _ := n1.net.findnode(n2.self, target)
    75  		if len(result) != bucketSize {
    76  			return fmt.Errorf("wrong number of results: got %d, want %d", len(result), bucketSize)
    77  		}
    78  		for i := range result {
    79  			if result[i].ID != expected.entries[i].ID {
    80  				return fmt.Errorf("result mismatch at %d:\n  got:  %v\n  want: %v", i, result[i], expected.entries[i])
    81  			}
    82  		}
    83  		return nil
    84  	})
    85  	if err != nil {
    86  		t.Error(err)
    87  	}
    88  }
    89  
    90  func TestUDP_replytimeout(t *testing.T) {
    91  	t.Parallel()
    92  
    93  	// reserve a port so we don't talk to an existing service by accident
    94  	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0")
    95  	fd, err := net.ListenUDP("udp", addr)
    96  	if err != nil {
    97  		t.Fatal(err)
    98  	}
    99  	defer fd.Close()
   100  
   101  	n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
   102  	defer n1.Close()
   103  	n2 := n1.bumpOrAdd(randomID(n1.self.ID, 10), fd.LocalAddr().(*net.UDPAddr))
   104  
   105  	if err := n1.net.ping(n2); err != errTimeout {
   106  		t.Error("expected timeout error, got", err)
   107  	}
   108  
   109  	if result, err := n1.net.findnode(n2, n1.self.ID); err != errTimeout {
   110  		t.Error("expected timeout error, got", err)
   111  	} else if len(result) > 0 {
   112  		t.Error("expected empty result, got", result)
   113  	}
   114  }
   115  
   116  func TestUDP_findnodeMultiReply(t *testing.T) {
   117  	t.Parallel()
   118  
   119  	n1, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
   120  	n2, _ := ListenUDP(newkey(), "127.0.0.1:0", nil)
   121  	udp2 := n2.net.(*udp)
   122  	defer n1.Close()
   123  	defer n2.Close()
   124  
   125  	err := runUDP(10, func() error {
   126  		nodes := make([]*Node, bucketSize)
   127  		for i := range nodes {
   128  			nodes[i] = &Node{
   129  				IP:       net.IP{1, 2, 3, 4},
   130  				DiscPort: i + 1,
   131  				TCPPort:  i + 1,
   132  				ID:       randomID(n2.self.ID, i+1),
   133  			}
   134  		}
   135  
   136  		// ask N2 for neighbors. it will send an empty reply back.
   137  		// the request will wait for up to bucketSize replies.
   138  		resultc := make(chan []*Node)
   139  		errc := make(chan error)
   140  		go func() {
   141  			ns, err := n1.net.findnode(n2.self, n1.self.ID)
   142  			if err != nil {
   143  				errc <- err
   144  			} else {
   145  				resultc <- ns
   146  			}
   147  		}()
   148  
   149  		// send a few more neighbors packets to N1.
   150  		// it should collect those.
   151  		for end := 0; end < len(nodes); {
   152  			off := end
   153  			if end = end + 5; end > len(nodes) {
   154  				end = len(nodes)
   155  			}
   156  			udp2.send(n1.self, neighborsPacket, neighbors{
   157  				Nodes:      nodes[off:end],
   158  				Expiration: uint64(time.Now().Add(10 * time.Second).Unix()),
   159  			})
   160  		}
   161  
   162  		// check that they are all returned. we cannot just check for
   163  		// equality because they might not be returned in the order they
   164  		// were sent.
   165  		var result []*Node
   166  		select {
   167  		case result = <-resultc:
   168  		case err := <-errc:
   169  			return err
   170  		}
   171  		if hasDuplicates(result) {
   172  			return fmt.Errorf("result slice contains duplicates")
   173  		}
   174  		if len(result) != len(nodes) {
   175  			return fmt.Errorf("wrong number of nodes returned: got %d, want %d", len(result), len(nodes))
   176  		}
   177  		matched := make(map[NodeID]bool)
   178  		for _, n := range result {
   179  			for _, expn := range nodes {
   180  				if n.ID == expn.ID { // && bytes.Equal(n.Addr.IP, expn.Addr.IP) && n.Addr.Port == expn.Addr.Port {
   181  					matched[n.ID] = true
   182  				}
   183  			}
   184  		}
   185  		if len(matched) != len(nodes) {
   186  			return fmt.Errorf("wrong number of matching nodes: got %d, want %d", len(matched), len(nodes))
   187  		}
   188  		return nil
   189  	})
   190  	if err != nil {
   191  		t.Error(err)
   192  	}
   193  }
   194  
   195  // runUDP runs a test n times and returns an error if the test failed
   196  // in all n runs. This is necessary because UDP is unreliable even for
   197  // connections on the local machine, causing test failures.
   198  func runUDP(n int, test func() error) error {
   199  	errcount := 0
   200  	errors := ""
   201  	for i := 0; i < n; i++ {
   202  		if err := test(); err != nil {
   203  			errors += fmt.Sprintf("\n#%d: %v", i, err)
   204  			errcount++
   205  		}
   206  	}
   207  	if errcount == n {
   208  		return fmt.Errorf("failed on all %d iterations:%s", n, errors)
   209  	}
   210  	return nil
   211  }