github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/testing/protocolsession.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 12:09:45</date>
    10  //</624342661968433152>
    11  
    12  
    13  package testing
    14  
    15  import (
    16  	"errors"
    17  	"fmt"
    18  	"sync"
    19  	"time"
    20  
    21  	"github.com/ethereum/go-ethereum/log"
    22  	"github.com/ethereum/go-ethereum/p2p"
    23  	"github.com/ethereum/go-ethereum/p2p/discover"
    24  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    25  )
    26  
    27  var errTimedOut = errors.New("timed out")
    28  
    29  //ProtocolSession是对运行的枢轴节点的准模拟。
    30  //可以发送(触发器)或
    31  //接收(预期)消息
    32  type ProtocolSession struct {
    33  	Server  *p2p.Server
    34  	IDs     []discover.NodeID
    35  	adapter *adapters.SimAdapter
    36  	events  chan *p2p.PeerEvent
    37  }
    38  
    39  //交换是协议测试的基本单元
    40  //数组中的触发器和预期将立即异步运行
    41  //因此,对于具有不同消息类型的同一对等端,不能有多个预期值
    42  //因为它是不可预测的,哪个期望会收到哪个消息
    43  //(对于Expect 1和2,可能会发送消息2和1,两个Expect都会抱怨错误的消息代码)
    44  //在会话上定义交换
    45  type Exchange struct {
    46  	Label    string
    47  	Triggers []Trigger
    48  	Expects  []Expect
    49  	Timeout  time.Duration
    50  }
    51  
    52  //触发器是交换的一部分,透视节点的传入消息
    53  //同行发送
    54  type Trigger struct {
    55  Msg     interface{}     //要发送的消息类型
    56  Code    uint64          //给出报文代码
    57  Peer    discover.NodeID //向其发送消息的对等方
    58  Timeout time.Duration   //发送超时时间
    59  }
    60  
    61  //Expect是来自透视节点的交换传出消息的一部分
    62  //由对等方接收
    63  type Expect struct {
    64  Msg     interface{}     //预期的消息类型
    65  Code    uint64          //现在给出了消息代码
    66  Peer    discover.NodeID //期望消息的对等机
    67  Timeout time.Duration   //接收超时时间
    68  }
    69  
    70  //disconnect表示一个disconnect事件,由testdisconnected使用并检查
    71  type Disconnect struct {
    72  Peer  discover.NodeID //DiscConnected对等
    73  Error error           //断开连接原因
    74  }
    75  
    76  //触发器从对等方发送消息
    77  func (s *ProtocolSession) trigger(trig Trigger) error {
    78  	simNode, ok := s.adapter.GetNode(trig.Peer)
    79  	if !ok {
    80  		return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.IDs))
    81  	}
    82  	mockNode, ok := simNode.Services()[0].(*mockNode)
    83  	if !ok {
    84  		return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer)
    85  	}
    86  
    87  	errc := make(chan error)
    88  
    89  	go func() {
    90  		log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code))
    91  		errc <- mockNode.Trigger(&trig)
    92  		log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code))
    93  	}()
    94  
    95  	t := trig.Timeout
    96  	if t == time.Duration(0) {
    97  		t = 1000 * time.Millisecond
    98  	}
    99  	select {
   100  	case err := <-errc:
   101  		return err
   102  	case <-time.After(t):
   103  		return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer)
   104  	}
   105  }
   106  
   107  //Expect检查透视节点发送的消息的期望值
   108  func (s *ProtocolSession) expect(exps []Expect) error {
   109  //构建每个节点的期望图
   110  	peerExpects := make(map[discover.NodeID][]Expect)
   111  	for _, exp := range exps {
   112  		if exp.Msg == nil {
   113  			return errors.New("no message to expect")
   114  		}
   115  		peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp)
   116  	}
   117  
   118  //为每个节点构造一个mocknode映射
   119  	mockNodes := make(map[discover.NodeID]*mockNode)
   120  	for nodeID := range peerExpects {
   121  		simNode, ok := s.adapter.GetNode(nodeID)
   122  		if !ok {
   123  			return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.IDs))
   124  		}
   125  		mockNode, ok := simNode.Services()[0].(*mockNode)
   126  		if !ok {
   127  			return fmt.Errorf("trigger: peer %v is not a mock", nodeID)
   128  		}
   129  		mockNodes[nodeID] = mockNode
   130  	}
   131  
   132  //done chanell在函数返回时取消所有创建的goroutine
   133  	done := make(chan struct{})
   134  	defer close(done)
   135  //errc从中捕获第一个错误
   136  	errc := make(chan error)
   137  
   138  	wg := &sync.WaitGroup{}
   139  	wg.Add(len(mockNodes))
   140  	for nodeID, mockNode := range mockNodes {
   141  		nodeID := nodeID
   142  		mockNode := mockNode
   143  		go func() {
   144  			defer wg.Done()
   145  
   146  //求和所有期望超时值以给出最大值
   147  //完成所有期望的时间。
   148  //mocknode.expect检查所有接收到的消息
   149  //每个消息的预期消息和超时列表
   150  //其中不能单独检查。
   151  			var t time.Duration
   152  			for _, exp := range peerExpects[nodeID] {
   153  				if exp.Timeout == time.Duration(0) {
   154  					t += 2000 * time.Millisecond
   155  				} else {
   156  					t += exp.Timeout
   157  				}
   158  			}
   159  			alarm := time.NewTimer(t)
   160  			defer alarm.Stop()
   161  
   162  //expecterrc用于检查是否返回错误
   163  //从mocknode.expect不是nil并将其发送到
   164  //只有在这种情况下才是errc。
   165  //完成通道将在功能关闭时关闭
   166  			expectErrc := make(chan error)
   167  			go func() {
   168  				select {
   169  				case expectErrc <- mockNode.Expect(peerExpects[nodeID]...):
   170  				case <-done:
   171  				case <-alarm.C:
   172  				}
   173  			}()
   174  
   175  			select {
   176  			case err := <-expectErrc:
   177  				if err != nil {
   178  					select {
   179  					case errc <- err:
   180  					case <-done:
   181  					case <-alarm.C:
   182  						errc <- errTimedOut
   183  					}
   184  				}
   185  			case <-done:
   186  			case <-alarm.C:
   187  				errc <- errTimedOut
   188  			}
   189  
   190  		}()
   191  	}
   192  
   193  	go func() {
   194  		wg.Wait()
   195  //当所有Goroutine完成时关闭errc,从errc返回nill err
   196  		close(errc)
   197  	}()
   198  
   199  	return <-errc
   200  }
   201  
   202  //测试交换测试一系列针对会话的交换
   203  func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error {
   204  	for i, e := range exchanges {
   205  		if err := s.testExchange(e); err != nil {
   206  			return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err)
   207  		}
   208  		log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label))
   209  	}
   210  	return nil
   211  }
   212  
   213  //测试交换测试单个交换。
   214  //默认超时值为2秒。
   215  func (s *ProtocolSession) testExchange(e Exchange) error {
   216  	errc := make(chan error)
   217  	done := make(chan struct{})
   218  	defer close(done)
   219  
   220  	go func() {
   221  		for _, trig := range e.Triggers {
   222  			err := s.trigger(trig)
   223  			if err != nil {
   224  				errc <- err
   225  				return
   226  			}
   227  		}
   228  
   229  		select {
   230  		case errc <- s.expect(e.Expects):
   231  		case <-done:
   232  		}
   233  	}()
   234  
   235  //全球超时或在所有期望都满足时结束
   236  	t := e.Timeout
   237  	if t == 0 {
   238  		t = 2000 * time.Millisecond
   239  	}
   240  	alarm := time.NewTimer(t)
   241  	select {
   242  	case err := <-errc:
   243  		return err
   244  	case <-alarm.C:
   245  		return errTimedOut
   246  	}
   247  }
   248  
   249  //testDisconnected测试作为参数提供的断开
   250  //disconnect结构描述了在哪个对等机上预期出现的断开连接错误
   251  func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error {
   252  	expects := make(map[discover.NodeID]error)
   253  	for _, disconnect := range disconnects {
   254  		expects[disconnect.Peer] = disconnect.Error
   255  	}
   256  
   257  	timeout := time.After(time.Second)
   258  	for len(expects) > 0 {
   259  		select {
   260  		case event := <-s.events:
   261  			if event.Type != p2p.PeerEventTypeDrop {
   262  				continue
   263  			}
   264  			expectErr, ok := expects[event.Peer]
   265  			if !ok {
   266  				continue
   267  			}
   268  
   269  			if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) {
   270  				return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error)
   271  			}
   272  			delete(expects, event.Peer)
   273  		case <-timeout:
   274  			return fmt.Errorf("timed out waiting for peers to disconnect")
   275  		}
   276  	}
   277  	return nil
   278  }
   279