github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/peer_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:41</date>
    10  //</624450105675616256>
    11  
    12  
    13  package p2p
    14  
    15  import (
    16  	"errors"
    17  	"fmt"
    18  	"math/rand"
    19  	"net"
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  )
    24  
    25  var discard = Protocol{
    26  	Name:   "discard",
    27  	Length: 1,
    28  	Run: func(p *Peer, rw MsgReadWriter) error {
    29  		for {
    30  			msg, err := rw.ReadMsg()
    31  			if err != nil {
    32  				return err
    33  			}
    34  			fmt.Printf("discarding %d\n", msg.Code)
    35  			if err = msg.Discard(); err != nil {
    36  				return err
    37  			}
    38  		}
    39  	},
    40  }
    41  
    42  func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) {
    43  	fd1, fd2 := net.Pipe()
    44  	c1 := &conn{fd: fd1, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd1)}
    45  	c2 := &conn{fd: fd2, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd2)}
    46  	for _, p := range protos {
    47  		c1.caps = append(c1.caps, p.cap())
    48  		c2.caps = append(c2.caps, p.cap())
    49  	}
    50  
    51  	peer := newPeer(c1, protos)
    52  	errc := make(chan error, 1)
    53  	go func() {
    54  		_, err := peer.run()
    55  		errc <- err
    56  	}()
    57  
    58  	closer := func() { c2.close(errors.New("close func called")) }
    59  	return closer, c2, peer, errc
    60  }
    61  
    62  func TestPeerProtoReadMsg(t *testing.T) {
    63  	proto := Protocol{
    64  		Name:   "a",
    65  		Length: 5,
    66  		Run: func(peer *Peer, rw MsgReadWriter) error {
    67  			if err := ExpectMsg(rw, 2, []uint{1}); err != nil {
    68  				t.Error(err)
    69  			}
    70  			if err := ExpectMsg(rw, 3, []uint{2}); err != nil {
    71  				t.Error(err)
    72  			}
    73  			if err := ExpectMsg(rw, 4, []uint{3}); err != nil {
    74  				t.Error(err)
    75  			}
    76  			return nil
    77  		},
    78  	}
    79  
    80  	closer, rw, _, errc := testPeer([]Protocol{proto})
    81  	defer closer()
    82  
    83  	Send(rw, baseProtocolLength+2, []uint{1})
    84  	Send(rw, baseProtocolLength+3, []uint{2})
    85  	Send(rw, baseProtocolLength+4, []uint{3})
    86  
    87  	select {
    88  	case err := <-errc:
    89  		if err != errProtocolReturned {
    90  			t.Errorf("peer returned error: %v", err)
    91  		}
    92  	case <-time.After(2 * time.Second):
    93  		t.Errorf("receive timeout")
    94  	}
    95  }
    96  
    97  func TestPeerProtoEncodeMsg(t *testing.T) {
    98  	proto := Protocol{
    99  		Name:   "a",
   100  		Length: 2,
   101  		Run: func(peer *Peer, rw MsgReadWriter) error {
   102  			if err := SendItems(rw, 2); err == nil {
   103  				t.Error("expected error for out-of-range msg code, got nil")
   104  			}
   105  			if err := SendItems(rw, 1, "foo", "bar"); err != nil {
   106  				t.Errorf("write error: %v", err)
   107  			}
   108  			return nil
   109  		},
   110  	}
   111  	closer, rw, _, _ := testPeer([]Protocol{proto})
   112  	defer closer()
   113  
   114  	if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil {
   115  		t.Error(err)
   116  	}
   117  }
   118  
   119  func TestPeerPing(t *testing.T) {
   120  	closer, rw, _, _ := testPeer(nil)
   121  	defer closer()
   122  	if err := SendItems(rw, pingMsg); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	if err := ExpectMsg(rw, pongMsg, nil); err != nil {
   126  		t.Error(err)
   127  	}
   128  }
   129  
   130  func TestPeerDisconnect(t *testing.T) {
   131  	closer, rw, _, disc := testPeer(nil)
   132  	defer closer()
   133  	if err := SendItems(rw, discMsg, DiscQuitting); err != nil {
   134  		t.Fatal(err)
   135  	}
   136  	select {
   137  	case reason := <-disc:
   138  		if reason != DiscQuitting {
   139  			t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting)
   140  		}
   141  	case <-time.After(500 * time.Millisecond):
   142  		t.Error("peer did not return")
   143  	}
   144  }
   145  
   146  //此测试旨在验证对等端是否能够可靠地处理
   147  //同时发生多个断开原因。
   148  func TestPeerDisconnectRace(t *testing.T) {
   149  	maybe := func() bool { return rand.Intn(1) == 1 }
   150  
   151  	for i := 0; i < 1000; i++ {
   152  		protoclose := make(chan error)
   153  		protodisc := make(chan DiscReason)
   154  		closer, rw, p, disc := testPeer([]Protocol{
   155  			{
   156  				Name:   "closereq",
   157  				Run:    func(p *Peer, rw MsgReadWriter) error { return <-protoclose },
   158  				Length: 1,
   159  			},
   160  			{
   161  				Name:   "disconnect",
   162  				Run:    func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil },
   163  				Length: 1,
   164  			},
   165  		})
   166  
   167  //模拟传入消息。
   168  		go SendItems(rw, baseProtocolLength+1)
   169  		go SendItems(rw, baseProtocolLength+2)
   170  //关闭网络连接。
   171  		go closer()
   172  //使协议“closereq”返回。
   173  		protoclose <- errors.New("protocol closed")
   174  //使协议“断开”呼叫对等方。断开连接
   175  		protodisc <- DiscAlreadyConnected
   176  //在某些情况下,模拟调用peer.disconnect的其他内容。
   177  		if maybe() {
   178  			go p.Disconnect(DiscInvalidIdentity)
   179  		}
   180  //在某些情况下,模拟远程请求断开连接。
   181  		if maybe() {
   182  			go SendItems(rw, discMsg, DiscQuitting)
   183  		}
   184  
   185  		select {
   186  		case <-disc:
   187  		case <-time.After(2 * time.Second):
   188  //peer.run应该很快返回。如果不是同伴
   189  //Goroutines可能陷入了僵局。呼叫恐慌以便
   190  //显示堆栈。
   191  			panic("Peer.run took to long to return.")
   192  		}
   193  	}
   194  }
   195  
   196  func TestNewPeer(t *testing.T) {
   197  	name := "nodename"
   198  	caps := []Cap{{"foo", 2}, {"bar", 3}}
   199  	id := randomID()
   200  	p := NewPeer(id, name, caps)
   201  	if p.ID() != id {
   202  		t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id)
   203  	}
   204  	if p.Name() != name {
   205  		t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name)
   206  	}
   207  	if !reflect.DeepEqual(p.Caps(), caps) {
   208  		t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps)
   209  	}
   210  
   211  p.Disconnect(DiscAlreadyConnected) //不应该挂
   212  }
   213  
   214  func TestMatchProtocols(t *testing.T) {
   215  	tests := []struct {
   216  		Remote []Cap
   217  		Local  []Protocol
   218  		Match  map[string]protoRW
   219  	}{
   220  		{
   221  //无远程功能
   222  			Local: []Protocol{{Name: "a"}},
   223  		},
   224  		{
   225  //没有本地协议
   226  			Remote: []Cap{{Name: "a"}},
   227  		},
   228  		{
   229  //没有相互协议
   230  			Remote: []Cap{{Name: "a"}},
   231  			Local:  []Protocol{{Name: "b"}},
   232  		},
   233  		{
   234  //一些匹配,一些差异
   235  			Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}},
   236  			Local:  []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}},
   237  			Match:  map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}},
   238  		},
   239  		{
   240  //各种字母顺序
   241  			Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}},
   242  			Local:  []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}},
   243  			Match:  map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}},
   244  		},
   245  		{
   246  //没有相互的版本
   247  			Remote: []Cap{{Version: 1}},
   248  			Local:  []Protocol{{Version: 2}},
   249  		},
   250  		{
   251  //多版本,单通用
   252  			Remote: []Cap{{Version: 1}, {Version: 2}},
   253  			Local:  []Protocol{{Version: 2}, {Version: 3}},
   254  			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 2}}},
   255  		},
   256  		{
   257  //多版本,多公共
   258  			Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}},
   259  			Local:  []Protocol{{Version: 2}, {Version: 3}},
   260  			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}},
   261  		},
   262  		{
   263  //各种版本订单
   264  			Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}},
   265  			Local:  []Protocol{{Version: 2}, {Version: 3}, {Version: 1}},
   266  			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}},
   267  		},
   268  		{
   269  //覆盖子协议长度的版本
   270  			Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}},
   271  			Local:  []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}},
   272  			Match:  map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}},
   273  		},
   274  	}
   275  
   276  	for i, tt := range tests {
   277  		result := matchProtocols(tt.Local, tt.Remote, nil)
   278  		if len(result) != len(tt.Match) {
   279  			t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match))
   280  			continue
   281  		}
   282  //确保所有协商的协议都是必要的和正确的
   283  		for name, proto := range result {
   284  			match, ok := tt.Match[name]
   285  			if !ok {
   286  				t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name)
   287  				continue
   288  			}
   289  			if proto.Name != match.Name {
   290  				t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name)
   291  			}
   292  			if proto.Version != match.Version {
   293  				t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version)
   294  			}
   295  			if proto.offset-baseProtocolLength != match.offset {
   296  				t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset)
   297  			}
   298  		}
   299  //确保没有协议错过协商
   300  		for name := range tt.Match {
   301  			if _, ok := result[name]; !ok {
   302  				t.Errorf("test %d, proto '%s': not negotiated, should have", i, name)
   303  				continue
   304  			}
   305  		}
   306  	}
   307  }
   308