diff --git a/p2p/testing/peerpool.go b/p2p/testing/peerpool.go
deleted file mode 100644
index 91b9704c79..0000000000
--- a/p2p/testing/peerpool.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package testing
-
-import (
- "fmt"
- "sync"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p/enode"
-)
-
-type TestPeer interface {
- ID() enode.ID
- Drop()
-}
-
-// TestPeerPool is an example peerPool to demonstrate registration of peer connections
-type TestPeerPool struct {
- lock sync.Mutex
- peers map[enode.ID]TestPeer
-}
-
-func NewTestPeerPool() *TestPeerPool {
- return &TestPeerPool{peers: make(map[enode.ID]TestPeer)}
-}
-
-func (p *TestPeerPool) Add(peer TestPeer) {
- p.lock.Lock()
- defer p.lock.Unlock()
- log.Trace(fmt.Sprintf("pp add peer %v", peer.ID()))
- p.peers[peer.ID()] = peer
-
-}
-
-func (p *TestPeerPool) Remove(peer TestPeer) {
- p.lock.Lock()
- defer p.lock.Unlock()
- delete(p.peers, peer.ID())
-}
-
-func (p *TestPeerPool) Has(id enode.ID) bool {
- p.lock.Lock()
- defer p.lock.Unlock()
- _, ok := p.peers[id]
- return ok
-}
-
-func (p *TestPeerPool) Get(id enode.ID) TestPeer {
- p.lock.Lock()
- defer p.lock.Unlock()
- return p.peers[id]
-}
diff --git a/p2p/testing/protocolsession.go b/p2p/testing/protocolsession.go
deleted file mode 100644
index e3a3915a81..0000000000
--- a/p2p/testing/protocolsession.go
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package testing
-
-import (
- "errors"
- "fmt"
- "sync"
- "time"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
-)
-
-var errTimedOut = errors.New("timed out")
-
-// ProtocolSession is a quasi simulation of a pivot node running
-// a service and a number of dummy peers that can send (trigger) or
-// receive (expect) messages
-type ProtocolSession struct {
- Server *p2p.Server
- Nodes []*enode.Node
- adapter *adapters.SimAdapter
- events chan *p2p.PeerEvent
-}
-
-// Exchange is the basic units of protocol tests
-// the triggers and expects in the arrays are run immediately and asynchronously
-// thus one cannot have multiple expects for the SAME peer with DIFFERENT message types
-// because it's unpredictable which expect will receive which message
-// (with expect #1 and #2, messages might be sent #2 and #1, and both expects will complain about wrong message code)
-// an exchange is defined on a session
-type Exchange struct {
- Label string
- Triggers []Trigger
- Expects []Expect
- Timeout time.Duration
-}
-
-// Trigger is part of the exchange, incoming message for the pivot node
-// sent by a peer
-type Trigger struct {
- Msg interface{} // type of message to be sent
- Code uint64 // code of message is given
- Peer enode.ID // the peer to send the message to
- Timeout time.Duration // timeout duration for the sending
-}
-
-// Expect is part of an exchange, outgoing message from the pivot node
-// received by a peer
-type Expect struct {
- Msg interface{} // type of message to expect
- Code uint64 // code of message is now given
- Peer enode.ID // the peer that expects the message
- Timeout time.Duration // timeout duration for receiving
-}
-
-// Disconnect represents a disconnect event, used and checked by TestDisconnected
-type Disconnect struct {
- Peer enode.ID // discconnected peer
- Error error // disconnect reason
-}
-
-// trigger sends messages from peers
-func (s *ProtocolSession) trigger(trig Trigger) error {
- simNode, ok := s.adapter.GetNode(trig.Peer)
- if !ok {
- return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.Nodes))
- }
- mockNode, ok := simNode.Services()[0].(*mockNode)
- if !ok {
- return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer)
- }
-
- errc := make(chan error)
-
- go func() {
- log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code))
- errc <- mockNode.Trigger(&trig)
- log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code))
- }()
-
- t := trig.Timeout
- if t == time.Duration(0) {
- t = 1000 * time.Millisecond
- }
- select {
- case err := <-errc:
- return err
- case <-time.After(t):
- return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer)
- }
-}
-
-// expect checks an expectation of a message sent out by the pivot node
-func (s *ProtocolSession) expect(exps []Expect) error {
- // construct a map of expectations for each node
- peerExpects := make(map[enode.ID][]Expect)
- for _, exp := range exps {
- if exp.Msg == nil {
- return errors.New("no message to expect")
- }
- peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp)
- }
-
- // construct a map of mockNodes for each node
- mockNodes := make(map[enode.ID]*mockNode)
- for nodeID := range peerExpects {
- simNode, ok := s.adapter.GetNode(nodeID)
- if !ok {
- return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.Nodes))
- }
- mockNode, ok := simNode.Services()[0].(*mockNode)
- if !ok {
- return fmt.Errorf("trigger: peer %v is not a mock", nodeID)
- }
- mockNodes[nodeID] = mockNode
- }
-
- // done chanell cancels all created goroutines when function returns
- done := make(chan struct{})
- defer close(done)
- // errc catches the first error from
- errc := make(chan error)
-
- wg := &sync.WaitGroup{}
- wg.Add(len(mockNodes))
- for nodeID, mockNode := range mockNodes {
- nodeID := nodeID
- mockNode := mockNode
- go func() {
- defer wg.Done()
-
- // Sum all Expect timeouts to give the maximum
- // time for all expectations to finish.
- // mockNode.Expect checks all received messages against
- // a list of expected messages and timeout for each
- // of them can not be checked separately.
- var t time.Duration
- for _, exp := range peerExpects[nodeID] {
- if exp.Timeout == time.Duration(0) {
- t += 2000 * time.Millisecond
- } else {
- t += exp.Timeout
- }
- }
- alarm := time.NewTimer(t)
- defer alarm.Stop()
-
- // expectErrc is used to check if error returned
- // from mockNode.Expect is not nil and to send it to
- // errc only in that case.
- // done channel will be closed when function
- expectErrc := make(chan error)
- go func() {
- select {
- case expectErrc <- mockNode.Expect(peerExpects[nodeID]...):
- case <-done:
- case <-alarm.C:
- }
- }()
-
- select {
- case err := <-expectErrc:
- if err != nil {
- select {
- case errc <- err:
- case <-done:
- case <-alarm.C:
- errc <- errTimedOut
- }
- }
- case <-done:
- case <-alarm.C:
- errc <- errTimedOut
- }
-
- }()
- }
-
- go func() {
- wg.Wait()
- // close errc when all goroutines finish to return nill err from errc
- close(errc)
- }()
-
- return <-errc
-}
-
-// TestExchanges tests a series of exchanges against the session
-func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error {
- for i, e := range exchanges {
- if err := s.testExchange(e); err != nil {
- return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err)
- }
- log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label))
- }
- return nil
-}
-
-// testExchange tests a single Exchange.
-// Default timeout value is 2 seconds.
-func (s *ProtocolSession) testExchange(e Exchange) error {
- errc := make(chan error)
- done := make(chan struct{})
- defer close(done)
-
- go func() {
- for _, trig := range e.Triggers {
- err := s.trigger(trig)
- if err != nil {
- errc <- err
- return
- }
- }
-
- select {
- case errc <- s.expect(e.Expects):
- case <-done:
- }
- }()
-
- // time out globally or finish when all expectations satisfied
- t := e.Timeout
- if t == 0 {
- t = 2000 * time.Millisecond
- }
- alarm := time.NewTimer(t)
- select {
- case err := <-errc:
- return err
- case <-alarm.C:
- return errTimedOut
- }
-}
-
-// TestDisconnected tests the disconnections given as arguments
-// the disconnect structs describe what disconnect error is expected on which peer
-func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error {
- expects := make(map[enode.ID]error)
- for _, disconnect := range disconnects {
- expects[disconnect.Peer] = disconnect.Error
- }
-
- timeout := time.After(time.Second)
- for len(expects) > 0 {
- select {
- case event := <-s.events:
- if event.Type != p2p.PeerEventTypeDrop {
- continue
- }
- expectErr, ok := expects[event.Peer]
- if !ok {
- continue
- }
-
- if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) {
- return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error)
- }
- delete(expects, event.Peer)
- case <-timeout:
- return fmt.Errorf("timed out waiting for peers to disconnect")
- }
- }
- return nil
-}
diff --git a/p2p/testing/protocoltester.go b/p2p/testing/protocoltester.go
deleted file mode 100644
index b80abcc264..0000000000
--- a/p2p/testing/protocoltester.go
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2018 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-/*
-the p2p/testing package provides a unit test scheme to check simple
-protocol message exchanges with one pivot node and a number of dummy peers
-The pivot test node runs a node.Service, the dummy peers run a mock node
-that can be used to send and receive messages
-*/
-
-package testing
-
-import (
- "bytes"
- "crypto/ecdsa"
- "fmt"
- "io"
- "io/ioutil"
- "strings"
- "sync"
-
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/p2p/enode"
- "github.com/ethereum/go-ethereum/p2p/simulations"
- "github.com/ethereum/go-ethereum/p2p/simulations/adapters"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/rpc"
-)
-
-// ProtocolTester is the tester environment used for unit testing protocol
-// message exchanges. It uses p2p/simulations framework
-type ProtocolTester struct {
- *ProtocolSession
- network *simulations.Network
-}
-
-// NewProtocolTester constructs a new ProtocolTester
-// it takes as argument the pivot node id, the number of dummy peers and the
-// protocol run function called on a peer connection by the p2p server
-func NewProtocolTester(prvkey *ecdsa.PrivateKey, nodeCount int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
- services := adapters.Services{
- "test": func(ctx *adapters.ServiceContext) (node.Service, error) {
- return &testNode{run}, nil
- },
- "mock": func(ctx *adapters.ServiceContext) (node.Service, error) {
- return newMockNode(), nil
- },
- }
- adapter := adapters.NewSimAdapter(services)
- net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{})
- nodeConfig := &adapters.NodeConfig{
- PrivateKey: prvkey,
- EnableMsgEvents: true,
- Services: []string{"test"},
- }
- if _, err := net.NewNodeWithConfig(nodeConfig); err != nil {
- panic(err.Error())
- }
- if err := net.Start(nodeConfig.ID); err != nil {
- panic(err.Error())
- }
-
- node := net.GetNode(nodeConfig.ID).Node.(*adapters.SimNode)
- peers := make([]*adapters.NodeConfig, nodeCount)
- nodes := make([]*enode.Node, nodeCount)
- for i := 0; i < nodeCount; i++ {
- peers[i] = adapters.RandomNodeConfig()
- peers[i].Services = []string{"mock"}
- if _, err := net.NewNodeWithConfig(peers[i]); err != nil {
- panic(fmt.Sprintf("error initializing peer %v: %v", peers[i].ID, err))
- }
- if err := net.Start(peers[i].ID); err != nil {
- panic(fmt.Sprintf("error starting peer %v: %v", peers[i].ID, err))
- }
- nodes[i] = peers[i].Node()
- }
- events := make(chan *p2p.PeerEvent, 1000)
- node.SubscribeEvents(events)
- ps := &ProtocolSession{
- Server: node.Server(),
- Nodes: nodes,
- adapter: adapter,
- events: events,
- }
- self := &ProtocolTester{
- ProtocolSession: ps,
- network: net,
- }
-
- self.Connect(nodeConfig.ID, peers...)
-
- return self
-}
-
-// Stop stops the p2p server
-func (t *ProtocolTester) Stop() {
- t.Server.Stop()
- t.network.Shutdown()
-}
-
-// Connect brings up the remote peer node and connects it using the
-// p2p/simulations network connection with the in memory network adapter
-func (t *ProtocolTester) Connect(selfID enode.ID, peers ...*adapters.NodeConfig) {
- for _, peer := range peers {
- log.Trace(fmt.Sprintf("connect to %v", peer.ID))
- if err := t.network.Connect(selfID, peer.ID); err != nil {
- panic(fmt.Sprintf("error connecting to peer %v: %v", peer.ID, err))
- }
- }
-
-}
-
-// testNode wraps a protocol run function and implements the node.Service
-// interface
-type testNode struct {
- run func(*p2p.Peer, p2p.MsgReadWriter) error
-}
-
-func (t *testNode) Protocols() []p2p.Protocol {
- return []p2p.Protocol{{
- Length: 100,
- Run: t.run,
- }}
-}
-
-func (t *testNode) APIs() []rpc.API {
- return nil
-}
-
-func (t *testNode) Start(server *p2p.Server) error {
- return nil
-}
-
-func (t *testNode) Stop() error {
- return nil
-}
-
-// mockNode is a testNode which doesn't actually run a protocol, instead
-// exposing channels so that tests can manually trigger and expect certain
-// messages
-type mockNode struct {
- testNode
-
- trigger chan *Trigger
- expect chan []Expect
- err chan error
- stop chan struct{}
- stopOnce sync.Once
-}
-
-func newMockNode() *mockNode {
- mock := &mockNode{
- trigger: make(chan *Trigger),
- expect: make(chan []Expect),
- err: make(chan error),
- stop: make(chan struct{}),
- }
- mock.testNode.run = mock.Run
- return mock
-}
-
-// Run is a protocol run function which just loops waiting for tests to
-// instruct it to either trigger or expect a message from the peer
-func (m *mockNode) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error {
- for {
- select {
- case trig := <-m.trigger:
- wmsg := Wrap(trig.Msg)
- m.err <- p2p.Send(rw, trig.Code, wmsg)
- case exps := <-m.expect:
- m.err <- expectMsgs(rw, exps)
- case <-m.stop:
- return nil
- }
- }
-}
-
-func (m *mockNode) Trigger(trig *Trigger) error {
- m.trigger <- trig
- return <-m.err
-}
-
-func (m *mockNode) Expect(exp ...Expect) error {
- m.expect <- exp
- return <-m.err
-}
-
-func (m *mockNode) Stop() error {
- m.stopOnce.Do(func() { close(m.stop) })
- return nil
-}
-
-func expectMsgs(rw p2p.MsgReadWriter, exps []Expect) error {
- matched := make([]bool, len(exps))
- for {
- msg, err := rw.ReadMsg()
- if err != nil {
- if err == io.EOF {
- break
- }
- return err
- }
- actualContent, err := ioutil.ReadAll(msg.Payload)
- if err != nil {
- return err
- }
- var found bool
- for i, exp := range exps {
- if exp.Code == msg.Code && bytes.Equal(actualContent, mustEncodeMsg(Wrap(exp.Msg))) {
- if matched[i] {
- return fmt.Errorf("message #%d received two times", i)
- }
- matched[i] = true
- found = true
- break
- }
- }
- if !found {
- expected := make([]string, 0)
- for i, exp := range exps {
- if matched[i] {
- continue
- }
- expected = append(expected, fmt.Sprintf("code %d payload %x", exp.Code, mustEncodeMsg(Wrap(exp.Msg))))
- }
- return fmt.Errorf("unexpected message code %d payload %x, expected %s", msg.Code, actualContent, strings.Join(expected, " or "))
- }
- done := true
- for _, m := range matched {
- if !m {
- done = false
- break
- }
- }
- if done {
- return nil
- }
- }
- for i, m := range matched {
- if !m {
- return fmt.Errorf("expected message #%d not received", i)
- }
- }
- return nil
-}
-
-// mustEncodeMsg uses rlp to encode a message.
-// In case of error it panics.
-func mustEncodeMsg(msg interface{}) []byte {
- contentEnc, err := rlp.EncodeToBytes(msg)
- if err != nil {
- panic("content encode error: " + err.Error())
- }
- return contentEnc
-}
-
-type WrappedMsg struct {
- Context []byte
- Size uint32
- Payload []byte
-}
-
-func Wrap(msg interface{}) interface{} {
- data, _ := rlp.EncodeToBytes(msg)
- return &WrappedMsg{
- Size: uint32(len(data)),
- Payload: data,
- }
-}