github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/testing/protocoltester.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2017 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  /*
    26  p2p/测试包提供了一个单元测试方案来检查
    27  协议消息与一个透视节点和多个虚拟对等点交换
    28  透视测试节点运行一个节点。服务,虚拟对等运行一个模拟节点
    29  可用于发送和接收消息的
    30  **/
    31  
    32  
    33  package testing
    34  
    35  import (
    36  	"bytes"
    37  	"fmt"
    38  	"io"
    39  	"io/ioutil"
    40  	"strings"
    41  	"sync"
    42  	"testing"
    43  
    44  	"github.com/ethereum/go-ethereum/log"
    45  	"github.com/ethereum/go-ethereum/node"
    46  	"github.com/ethereum/go-ethereum/p2p"
    47  	"github.com/ethereum/go-ethereum/p2p/discover"
    48  	"github.com/ethereum/go-ethereum/p2p/simulations"
    49  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    50  	"github.com/ethereum/go-ethereum/rlp"
    51  	"github.com/ethereum/go-ethereum/rpc"
    52  )
    53  
    54  //ProtocolTester是用于单元测试协议的测试环境
    55  //消息交换。它使用P2P/仿真框架
    56  type ProtocolTester struct {
    57  	*ProtocolSession
    58  	network *simulations.Network
    59  }
    60  
    61  //NewProtocolTester构造了一个新的ProtocolTester
    62  //它将透视节点ID、虚拟对等数和
    63  //P2P服务器在对等连接上调用的协议运行函数
    64  func NewProtocolTester(t *testing.T, id discover.NodeID, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
    65  	services := adapters.Services{
    66  		"test": func(ctx *adapters.ServiceContext) (node.Service, error) {
    67  			return &testNode{run}, nil
    68  		},
    69  		"mock": func(ctx *adapters.ServiceContext) (node.Service, error) {
    70  			return newMockNode(), nil
    71  		},
    72  	}
    73  	adapter := adapters.NewSimAdapter(services)
    74  	net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{})
    75  	if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{
    76  		ID:              id,
    77  		EnableMsgEvents: true,
    78  		Services:        []string{"test"},
    79  	}); err != nil {
    80  		panic(err.Error())
    81  	}
    82  	if err := net.Start(id); err != nil {
    83  		panic(err.Error())
    84  	}
    85  
    86  	node := net.GetNode(id).Node.(*adapters.SimNode)
    87  	peers := make([]*adapters.NodeConfig, n)
    88  	peerIDs := make([]discover.NodeID, n)
    89  	for i := 0; i < n; i++ {
    90  		peers[i] = adapters.RandomNodeConfig()
    91  		peers[i].Services = []string{"mock"}
    92  		peerIDs[i] = peers[i].ID
    93  	}
    94  	events := make(chan *p2p.PeerEvent, 1000)
    95  	node.SubscribeEvents(events)
    96  	ps := &ProtocolSession{
    97  		Server:  node.Server(),
    98  		IDs:     peerIDs,
    99  		adapter: adapter,
   100  		events:  events,
   101  	}
   102  	self := &ProtocolTester{
   103  		ProtocolSession: ps,
   104  		network:         net,
   105  	}
   106  
   107  	self.Connect(id, peers...)
   108  
   109  	return self
   110  }
   111  
   112  //停止停止P2P服务器
   113  func (t *ProtocolTester) Stop() error {
   114  	t.Server.Stop()
   115  	return nil
   116  }
   117  
   118  //Connect打开远程对等节点并使用
   119  //P2P/模拟与内存网络适配器的网络连接
   120  func (t *ProtocolTester) Connect(selfID discover.NodeID, peers ...*adapters.NodeConfig) {
   121  	for _, peer := range peers {
   122  		log.Trace(fmt.Sprintf("start node %v", peer.ID))
   123  		if _, err := t.network.NewNodeWithConfig(peer); err != nil {
   124  			panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err))
   125  		}
   126  		if err := t.network.Start(peer.ID); err != nil {
   127  			panic(fmt.Sprintf("error starting peer %v: %v", peer.ID, err))
   128  		}
   129  		log.Trace(fmt.Sprintf("connect to %v", peer.ID))
   130  		if err := t.network.Connect(selfID, peer.ID); err != nil {
   131  			panic(fmt.Sprintf("error connecting to peer %v: %v", peer.ID, err))
   132  		}
   133  	}
   134  
   135  }
   136  
   137  //testnode包装协议运行函数并实现node.service
   138  //界面
   139  type testNode struct {
   140  	run func(*p2p.Peer, p2p.MsgReadWriter) error
   141  }
   142  
   143  func (t *testNode) Protocols() []p2p.Protocol {
   144  	return []p2p.Protocol{{
   145  		Length: 100,
   146  		Run:    t.run,
   147  	}}
   148  }
   149  
   150  func (t *testNode) APIs() []rpc.API {
   151  	return nil
   152  }
   153  
   154  func (t *testNode) Start(server *p2p.Server) error {
   155  	return nil
   156  }
   157  
   158  func (t *testNode) Stop() error {
   159  	return nil
   160  }
   161  
   162  //mocknode是一个没有实际运行协议的testnode
   163  //公开通道,以便测试可以手动触发并预期
   164  //信息
   165  type mockNode struct {
   166  	testNode
   167  
   168  	trigger  chan *Trigger
   169  	expect   chan []Expect
   170  	err      chan error
   171  	stop     chan struct{}
   172  	stopOnce sync.Once
   173  }
   174  
   175  func newMockNode() *mockNode {
   176  	mock := &mockNode{
   177  		trigger: make(chan *Trigger),
   178  		expect:  make(chan []Expect),
   179  		err:     make(chan error),
   180  		stop:    make(chan struct{}),
   181  	}
   182  	mock.testNode.run = mock.Run
   183  	return mock
   184  }
   185  
   186  //运行是一个协议运行函数,它只循环等待测试
   187  //指示它触发或期望来自对等端的消息
   188  func (m *mockNode) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
   189  	for {
   190  		select {
   191  		case trig := <-m.trigger:
   192  			wmsg := Wrap(trig.Msg)
   193  			m.err <- p2p.Send(rw, trig.Code, wmsg)
   194  		case exps := <-m.expect:
   195  			m.err <- expectMsgs(rw, exps)
   196  		case <-m.stop:
   197  			return nil
   198  		}
   199  	}
   200  }
   201  
   202  func (m *mockNode) Trigger(trig *Trigger) error {
   203  	m.trigger <- trig
   204  	return <-m.err
   205  }
   206  
   207  func (m *mockNode) Expect(exp ...Expect) error {
   208  	m.expect <- exp
   209  	return <-m.err
   210  }
   211  
   212  func (m *mockNode) Stop() error {
   213  	m.stopOnce.Do(func() { close(m.stop) })
   214  	return nil
   215  }
   216  
   217  func expectMsgs(rw p2p.MsgReadWriter, exps []Expect) error {
   218  	matched := make([]bool, len(exps))
   219  	for {
   220  		msg, err := rw.ReadMsg()
   221  		if err != nil {
   222  			if err == io.EOF {
   223  				break
   224  			}
   225  			return err
   226  		}
   227  		actualContent, err := ioutil.ReadAll(msg.Payload)
   228  		if err != nil {
   229  			return err
   230  		}
   231  		var found bool
   232  		for i, exp := range exps {
   233  			if exp.Code == msg.Code && bytes.Equal(actualContent, mustEncodeMsg(Wrap(exp.Msg))) {
   234  				if matched[i] {
   235  					return fmt.Errorf("message #%d received two times", i)
   236  				}
   237  				matched[i] = true
   238  				found = true
   239  				break
   240  			}
   241  		}
   242  		if !found {
   243  			expected := make([]string, 0)
   244  			for i, exp := range exps {
   245  				if matched[i] {
   246  					continue
   247  				}
   248  				expected = append(expected, fmt.Sprintf("code %d payload %x", exp.Code, mustEncodeMsg(Wrap(exp.Msg))))
   249  			}
   250  			return fmt.Errorf("unexpected message code %d payload %x, expected %s", msg.Code, actualContent, strings.Join(expected, " or "))
   251  		}
   252  		done := true
   253  		for _, m := range matched {
   254  			if !m {
   255  				done = false
   256  				break
   257  			}
   258  		}
   259  		if done {
   260  			return nil
   261  		}
   262  	}
   263  	for i, m := range matched {
   264  		if !m {
   265  			return fmt.Errorf("expected message #%d not received", i)
   266  		}
   267  	}
   268  	return nil
   269  }
   270  
   271  //mustencodemsg使用rlp对消息进行编码。
   272  //一旦出错,它就会惊慌失措。
   273  func mustEncodeMsg(msg interface{}) []byte {
   274  	contentEnc, err := rlp.EncodeToBytes(msg)
   275  	if err != nil {
   276  		panic("content encode error: " + err.Error())
   277  	}
   278  	return contentEnc
   279  }
   280  
   281  type WrappedMsg struct {
   282  	Context []byte
   283  	Size    uint32
   284  	Payload []byte
   285  }
   286  
   287  func Wrap(msg interface{}) interface{} {
   288  	data, _ := rlp.EncodeToBytes(msg)
   289  	return &WrappedMsg{
   290  		Size:    uint32(len(data)),
   291  		Payload: data,
   292  	}
   293  }