github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/comm/comm_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package comm
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/hmac"
    12  	"crypto/sha256"
    13  	"crypto/tls"
    14  	"fmt"
    15  	"math/rand"
    16  	"net"
    17  	"os"
    18  	"strings"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/hyperledger/fabric/bccsp/factory"
    24  	"github.com/hyperledger/fabric/core/config"
    25  	"github.com/hyperledger/fabric/gossip/api"
    26  	"github.com/hyperledger/fabric/gossip/common"
    27  	"github.com/hyperledger/fabric/gossip/identity"
    28  	"github.com/hyperledger/fabric/gossip/util"
    29  	proto "github.com/hyperledger/fabric/protos/gossip"
    30  	"github.com/spf13/viper"
    31  	"github.com/stretchr/testify/assert"
    32  	"golang.org/x/net/context"
    33  	"google.golang.org/grpc"
    34  	"google.golang.org/grpc/credentials"
    35  )
    36  
    37  func init() {
    38  	util.SetupTestLogging()
    39  	rand.Seed(time.Now().UnixNano())
    40  	factory.InitFactories(nil)
    41  }
    42  
    43  func acceptAll(msg interface{}) bool {
    44  	return true
    45  }
    46  
    47  var (
    48  	naiveSec = &naiveSecProvider{}
    49  	hmacKey  = []byte{0, 0, 0}
    50  )
    51  
    52  type naiveSecProvider struct {
    53  }
    54  
    55  func (*naiveSecProvider) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
    56  	return nil
    57  }
    58  
    59  // GetPKIidOfCert returns the PKI-ID of a peer's identity
    60  func (*naiveSecProvider) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common.PKIidType {
    61  	return common.PKIidType(peerIdentity)
    62  }
    63  
    64  // VerifyBlock returns nil if the block is properly signed,
    65  // else returns error
    66  func (*naiveSecProvider) VerifyBlock(chainID common.ChainID, seqNum uint64, signedBlock []byte) error {
    67  	return nil
    68  }
    69  
    70  // Sign signs msg with this peer's signing key and outputs
    71  // the signature if no error occurred.
    72  func (*naiveSecProvider) Sign(msg []byte) ([]byte, error) {
    73  	mac := hmac.New(sha256.New, hmacKey)
    74  	mac.Write(msg)
    75  	return mac.Sum(nil), nil
    76  }
    77  
    78  // Verify checks that signature is a valid signature of message under a peer's verification key.
    79  // If the verification succeeded, Verify returns nil meaning no error occurred.
    80  // If peerCert is nil, then the signature is verified against this peer's verification key.
    81  func (*naiveSecProvider) Verify(peerIdentity api.PeerIdentityType, signature, message []byte) error {
    82  	mac := hmac.New(sha256.New, hmacKey)
    83  	mac.Write(message)
    84  	expected := mac.Sum(nil)
    85  	if !bytes.Equal(signature, expected) {
    86  		return fmt.Errorf("Wrong certificate:%v, %v", signature, message)
    87  	}
    88  	return nil
    89  }
    90  
    91  // VerifyByChannel verifies a peer's signature on a message in the context
    92  // of a specific channel
    93  func (*naiveSecProvider) VerifyByChannel(_ common.ChainID, _ api.PeerIdentityType, _, _ []byte) error {
    94  	return nil
    95  }
    96  
    97  func newCommInstance(port int, sec api.MessageCryptoService) (Comm, error) {
    98  	endpoint := fmt.Sprintf("localhost:%d", port)
    99  	id := []byte(endpoint)
   100  	inst, err := NewCommInstanceWithServer(port, identity.NewIdentityMapper(sec, id), id, nil)
   101  	return inst, err
   102  }
   103  
   104  type msgMutator func(*proto.SignedGossipMessage) *proto.SignedGossipMessage
   105  
   106  type tlsType int
   107  
   108  const (
   109  	none tlsType = iota
   110  	oneWayTLS
   111  	mutualTLS
   112  )
   113  
   114  func handshaker(endpoint string, comm Comm, t *testing.T, connMutator msgMutator, connType tlsType) <-chan proto.ReceivedMessage {
   115  	c := &commImpl{}
   116  	cert := GenerateCertificatesOrPanic()
   117  	tlsCfg := &tls.Config{
   118  		InsecureSkipVerify: true,
   119  	}
   120  	if connType == mutualTLS {
   121  		tlsCfg.Certificates = []tls.Certificate{cert}
   122  	}
   123  	ta := credentials.NewTLS(tlsCfg)
   124  	secureOpts := grpc.WithTransportCredentials(ta)
   125  	if connType == none {
   126  		secureOpts = grpc.WithInsecure()
   127  	}
   128  	acceptChan := comm.Accept(acceptAll)
   129  	conn, err := grpc.Dial("localhost:9611", secureOpts, grpc.WithBlock(), grpc.WithTimeout(time.Second))
   130  	assert.NoError(t, err, "%v", err)
   131  	if err != nil {
   132  		return nil
   133  	}
   134  	cl := proto.NewGossipClient(conn)
   135  	stream, err := cl.GossipStream(context.Background())
   136  	assert.NoError(t, err, "%v", err)
   137  	if err != nil {
   138  		return nil
   139  	}
   140  
   141  	var clientCertHash []byte
   142  	if len(tlsCfg.Certificates) > 0 {
   143  		clientCertHash = certHashFromRawCert(tlsCfg.Certificates[0].Certificate[0])
   144  	}
   145  
   146  	pkiID := common.PKIidType(endpoint)
   147  	assert.NoError(t, err, "%v", err)
   148  	msg, _ := c.createConnectionMsg(pkiID, clientCertHash, []byte(endpoint), func(msg []byte) ([]byte, error) {
   149  		mac := hmac.New(sha256.New, hmacKey)
   150  		mac.Write(msg)
   151  		return mac.Sum(nil), nil
   152  	})
   153  	// Mutate connection message to test negative paths
   154  	msg = connMutator(msg)
   155  	// Send your own connection message
   156  	stream.Send(msg.Envelope)
   157  	// Wait for connection message from the other side
   158  	envelope, err := stream.Recv()
   159  	if err != nil {
   160  		return acceptChan
   161  	}
   162  	assert.NoError(t, err, "%v", err)
   163  	msg, err = envelope.ToGossipMessage()
   164  	assert.NoError(t, err, "%v", err)
   165  	assert.Equal(t, []byte("localhost:9611"), msg.GetConn().PkiId)
   166  	assert.Equal(t, extractCertificateHashFromContext(stream.Context()), msg.GetConn().TlsCertHash)
   167  	msg2Send := createGossipMsg()
   168  	nonce := uint64(rand.Int())
   169  	msg2Send.Nonce = nonce
   170  	go stream.Send(msg2Send.Envelope)
   171  	return acceptChan
   172  }
   173  
   174  func TestViperConfig(t *testing.T) {
   175  	viper.SetConfigName("core")
   176  	viper.SetEnvPrefix("CORE")
   177  	config.AddDevConfigPath(nil)
   178  	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
   179  	viper.AutomaticEnv()
   180  	err := viper.ReadInConfig()
   181  	if err != nil { // Handle errors reading the config file
   182  		panic(fmt.Errorf("fatal error config file: %s", err))
   183  	}
   184  
   185  	assert.Equal(t, time.Duration(2)*time.Second, util.GetDurationOrDefault("peer.gossip.connTimeout", 0))
   186  	assert.Equal(t, time.Duration(300)*time.Millisecond, util.GetDurationOrDefault("peer.gossip.dialTimeout", 0))
   187  	assert.Equal(t, 20, util.GetIntOrDefault("peer.gossip.recvBuffSize", 0))
   188  	assert.Equal(t, 200, util.GetIntOrDefault("peer.gossip.sendBuffSize", 0))
   189  }
   190  
   191  func TestHandshake(t *testing.T) {
   192  	t.Parallel()
   193  	signer := func(msg []byte) ([]byte, error) {
   194  		mac := hmac.New(sha256.New, hmacKey)
   195  		mac.Write(msg)
   196  		return mac.Sum(nil), nil
   197  	}
   198  	mutator := func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   199  		return msg
   200  	}
   201  	assertPositivePath := func(msg proto.ReceivedMessage, endpoint string) {
   202  		expectedPKIID := common.PKIidType(endpoint)
   203  		assert.Equal(t, expectedPKIID, msg.GetConnectionInfo().ID)
   204  		assert.Equal(t, api.PeerIdentityType(endpoint), msg.GetConnectionInfo().Identity)
   205  		assert.NotNil(t, msg.GetConnectionInfo().Auth)
   206  		assert.True(t, msg.GetConnectionInfo().IsAuthenticated())
   207  		sig, _ := (&naiveSecProvider{}).Sign(msg.GetConnectionInfo().Auth.SignedData)
   208  		assert.Equal(t, sig, msg.GetConnectionInfo().Auth.Signature)
   209  	}
   210  
   211  	// Positive path 1 - check authentication without TLS
   212  	ll, err := net.Listen("tcp", fmt.Sprintf("%s:%d", "", 9611))
   213  	assert.NoError(t, err)
   214  	s := grpc.NewServer()
   215  	go s.Serve(ll)
   216  
   217  	id := []byte("localhost:9611")
   218  	idMapper := identity.NewIdentityMapper(naiveSec, id)
   219  	inst, err := NewCommInstance(s, nil, idMapper, api.PeerIdentityType("localhost:9611"), func() []grpc.DialOption {
   220  		return []grpc.DialOption{grpc.WithInsecure()}
   221  	})
   222  	assert.NoError(t, err)
   223  	var msg proto.ReceivedMessage
   224  
   225  	acceptChan := handshaker("localhost:9608", inst, t, mutator, none)
   226  	select {
   227  	case <-time.After(time.Duration(time.Second * 4)):
   228  		assert.FailNow(t, "Didn't receive a message, seems like handshake failed")
   229  	case msg = <-acceptChan:
   230  	}
   231  	assert.Equal(t, common.PKIidType("localhost:9608"), msg.GetConnectionInfo().ID)
   232  	assert.Equal(t, api.PeerIdentityType("localhost:9608"), msg.GetConnectionInfo().Identity)
   233  	assert.Nil(t, msg.GetConnectionInfo().Auth)
   234  	assert.False(t, msg.GetConnectionInfo().IsAuthenticated())
   235  
   236  	inst.Stop()
   237  	s.Stop()
   238  	ll.Close()
   239  	time.Sleep(time.Second)
   240  
   241  	comm, err := newCommInstance(9611, naiveSec)
   242  	assert.NoError(t, err)
   243  	defer comm.Stop()
   244  	// Positive path 2: initiating peer sends its own certificate
   245  	acceptChan = handshaker("localhost:9609", comm, t, mutator, mutualTLS)
   246  
   247  	select {
   248  	case <-time.After(time.Second * 2):
   249  		assert.FailNow(t, "Didn't receive a message, seems like handshake failed")
   250  	case msg = <-acceptChan:
   251  	}
   252  	assertPositivePath(msg, "localhost:9609")
   253  
   254  	// Negative path: initiating peer doesn't send its own certificate
   255  	acceptChan = handshaker("localhost:9610", comm, t, mutator, oneWayTLS)
   256  	time.Sleep(time.Second)
   257  	assert.Equal(t, 0, len(acceptChan))
   258  	// Negative path, signature is wrong
   259  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   260  		msg.Signature = append(msg.Signature, 0)
   261  		return msg
   262  	}
   263  	acceptChan = handshaker("localhost:9612", comm, t, mutator, mutualTLS)
   264  	time.Sleep(time.Second)
   265  	assert.Equal(t, 0, len(acceptChan))
   266  
   267  	// Negative path, the PKIid doesn't match the identity
   268  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   269  		msg.GetConn().PkiId = []byte("localhost:9650")
   270  		// Sign the message again
   271  		msg.Sign(signer)
   272  		return msg
   273  	}
   274  	acceptChan = handshaker("localhost:9613", comm, t, mutator, mutualTLS)
   275  	time.Sleep(time.Second)
   276  	assert.Equal(t, 0, len(acceptChan))
   277  
   278  	// Negative path, the cert hash isn't what is expected
   279  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   280  		msg.GetConn().TlsCertHash = append(msg.GetConn().TlsCertHash, 0)
   281  		msg.Sign(signer)
   282  		return msg
   283  	}
   284  	acceptChan = handshaker("localhost:9615", comm, t, mutator, mutualTLS)
   285  	time.Sleep(time.Second)
   286  	assert.Equal(t, 0, len(acceptChan))
   287  
   288  	// Negative path, no PKI-ID was sent
   289  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   290  		msg.GetConn().PkiId = nil
   291  		msg.Sign(signer)
   292  		return msg
   293  	}
   294  	acceptChan = handshaker("localhost:9616", comm, t, mutator, mutualTLS)
   295  	time.Sleep(time.Second)
   296  	assert.Equal(t, 0, len(acceptChan))
   297  
   298  	// Negative path, connection message is of a different type
   299  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   300  		msg.Content = &proto.GossipMessage_Empty{
   301  			Empty: &proto.Empty{},
   302  		}
   303  		msg.Sign(signer)
   304  		return msg
   305  	}
   306  	acceptChan = handshaker("localhost:9617", comm, t, mutator, mutualTLS)
   307  	time.Sleep(time.Second)
   308  	assert.Equal(t, 0, len(acceptChan))
   309  
   310  	// Negative path, the peer didn't respond to the handshake in due time
   311  	mutator = func(msg *proto.SignedGossipMessage) *proto.SignedGossipMessage {
   312  		time.Sleep(time.Second * 5)
   313  		return msg
   314  	}
   315  	acceptChan = handshaker("localhost:9618", comm, t, mutator, mutualTLS)
   316  	time.Sleep(time.Second)
   317  	assert.Equal(t, 0, len(acceptChan))
   318  }
   319  
   320  func TestBasic(t *testing.T) {
   321  	t.Parallel()
   322  	comm1, _ := newCommInstance(2000, naiveSec)
   323  	comm2, _ := newCommInstance(3000, naiveSec)
   324  	comm1.(*commImpl).SetDialOpts()
   325  	comm2.(*commImpl).SetDialOpts()
   326  	defer comm1.Stop()
   327  	defer comm2.Stop()
   328  	m1 := comm1.Accept(acceptAll)
   329  	m2 := comm2.Accept(acceptAll)
   330  	out := make(chan uint64, 2)
   331  	reader := func(ch <-chan proto.ReceivedMessage) {
   332  		m := <-ch
   333  		out <- m.GetGossipMessage().Nonce
   334  	}
   335  	go reader(m1)
   336  	go reader(m2)
   337  	comm1.Send(createGossipMsg(), remotePeer(3000))
   338  	time.Sleep(time.Second)
   339  	comm2.Send(createGossipMsg(), remotePeer(2000))
   340  	waitForMessages(t, out, 2, "Didn't receive 2 messages")
   341  }
   342  
   343  func TestProdConstructor(t *testing.T) {
   344  	t.Parallel()
   345  	peerIdentity := GenerateCertificatesOrPanic()
   346  	srv, lsnr, dialOpts, certHash := createGRPCLayer(20000)
   347  	defer srv.Stop()
   348  	defer lsnr.Close()
   349  	id := []byte("localhost:20000")
   350  	comm1, _ := NewCommInstance(srv, &peerIdentity, identity.NewIdentityMapper(naiveSec, id), id, dialOpts)
   351  	comm1.(*commImpl).selfCertHash = certHash
   352  	go srv.Serve(lsnr)
   353  
   354  	peerIdentity = GenerateCertificatesOrPanic()
   355  	srv, lsnr, dialOpts, certHash = createGRPCLayer(30000)
   356  	defer srv.Stop()
   357  	defer lsnr.Close()
   358  	id = []byte("localhost:30000")
   359  	comm2, _ := NewCommInstance(srv, &peerIdentity, identity.NewIdentityMapper(naiveSec, id), id, dialOpts)
   360  	comm2.(*commImpl).selfCertHash = certHash
   361  	go srv.Serve(lsnr)
   362  	defer comm1.Stop()
   363  	defer comm2.Stop()
   364  	m1 := comm1.Accept(acceptAll)
   365  	m2 := comm2.Accept(acceptAll)
   366  	out := make(chan uint64, 2)
   367  	reader := func(ch <-chan proto.ReceivedMessage) {
   368  		m := <-ch
   369  		out <- m.GetGossipMessage().Nonce
   370  	}
   371  	go reader(m1)
   372  	go reader(m2)
   373  	comm1.Send(createGossipMsg(), remotePeer(30000))
   374  	time.Sleep(time.Second)
   375  	comm2.Send(createGossipMsg(), remotePeer(20000))
   376  	waitForMessages(t, out, 2, "Didn't receive 2 messages")
   377  }
   378  
   379  func TestGetConnectionInfo(t *testing.T) {
   380  	t.Parallel()
   381  	comm1, _ := newCommInstance(6000, naiveSec)
   382  	comm2, _ := newCommInstance(7000, naiveSec)
   383  	defer comm1.Stop()
   384  	defer comm2.Stop()
   385  	m1 := comm1.Accept(acceptAll)
   386  	comm2.Send(createGossipMsg(), remotePeer(6000))
   387  	select {
   388  	case <-time.After(time.Second * 10):
   389  		t.Fatal("Didn't receive a message in time")
   390  	case msg := <-m1:
   391  		assert.Equal(t, comm2.GetPKIid(), msg.GetConnectionInfo().ID)
   392  		assert.NotNil(t, msg.GetSourceEnvelope())
   393  	}
   394  }
   395  
   396  func TestCloseConn(t *testing.T) {
   397  	t.Parallel()
   398  	comm1, _ := newCommInstance(1611, naiveSec)
   399  	defer comm1.Stop()
   400  	acceptChan := comm1.Accept(acceptAll)
   401  
   402  	cert := GenerateCertificatesOrPanic()
   403  	tlsCfg := &tls.Config{
   404  		InsecureSkipVerify: true,
   405  		Certificates:       []tls.Certificate{cert},
   406  	}
   407  	ta := credentials.NewTLS(tlsCfg)
   408  
   409  	conn, err := grpc.Dial("localhost:1611", grpc.WithTransportCredentials(ta), grpc.WithBlock(), grpc.WithTimeout(time.Second))
   410  	assert.NoError(t, err, "%v", err)
   411  	cl := proto.NewGossipClient(conn)
   412  	stream, err := cl.GossipStream(context.Background())
   413  	assert.NoError(t, err, "%v", err)
   414  	c := &commImpl{}
   415  	tlsCertHash := certHashFromRawCert(tlsCfg.Certificates[0].Certificate[0])
   416  	connMsg, _ := c.createConnectionMsg(common.PKIidType("pkiID"), tlsCertHash, api.PeerIdentityType("pkiID"), func(msg []byte) ([]byte, error) {
   417  		mac := hmac.New(sha256.New, hmacKey)
   418  		mac.Write(msg)
   419  		return mac.Sum(nil), nil
   420  	})
   421  	assert.NoError(t, stream.Send(connMsg.Envelope))
   422  	stream.Send(createGossipMsg().Envelope)
   423  	select {
   424  	case <-acceptChan:
   425  	case <-time.After(time.Second):
   426  		assert.Fail(t, "Didn't receive a message within a timely period")
   427  	}
   428  	comm1.CloseConn(&RemotePeer{PKIID: common.PKIidType("pkiID")})
   429  	time.Sleep(time.Second * 10)
   430  	gotErr := false
   431  	msg2Send := createGossipMsg()
   432  	msg2Send.GetDataMsg().Payload = &proto.Payload{
   433  		Data: make([]byte, 1024*1024),
   434  	}
   435  	msg2Send.NoopSign()
   436  	for i := 0; i < defRecvBuffSize; i++ {
   437  		err := stream.Send(msg2Send.Envelope)
   438  		if err != nil {
   439  			gotErr = true
   440  			break
   441  		}
   442  	}
   443  	assert.True(t, gotErr, "Should have failed because connection is closed")
   444  }
   445  
   446  func TestParallelSend(t *testing.T) {
   447  	t.Parallel()
   448  	comm1, _ := newCommInstance(5411, naiveSec)
   449  	comm2, _ := newCommInstance(5412, naiveSec)
   450  	defer comm1.Stop()
   451  	defer comm2.Stop()
   452  
   453  	messages2Send := util.GetIntOrDefault("peer.gossip.recvBuffSize", defRecvBuffSize)
   454  
   455  	wg := sync.WaitGroup{}
   456  	go func() {
   457  		for i := 0; i < messages2Send; i++ {
   458  			wg.Add(1)
   459  			emptyMsg := createGossipMsg()
   460  			go func() {
   461  				defer wg.Done()
   462  				comm1.Send(emptyMsg, remotePeer(5412))
   463  			}()
   464  		}
   465  		wg.Wait()
   466  	}()
   467  
   468  	c := 0
   469  	waiting := true
   470  	ticker := time.NewTicker(time.Duration(5) * time.Second)
   471  	ch := comm2.Accept(acceptAll)
   472  	for waiting {
   473  		select {
   474  		case <-ch:
   475  			c++
   476  			if c == messages2Send {
   477  				waiting = false
   478  			}
   479  		case <-ticker.C:
   480  			waiting = false
   481  		}
   482  	}
   483  	assert.Equal(t, messages2Send, c)
   484  }
   485  
   486  type nonResponsivePeer struct {
   487  	net.Listener
   488  	*grpc.Server
   489  	port int
   490  }
   491  
   492  func newNonResponsivePeer() *nonResponsivePeer {
   493  	rand.Seed(time.Now().UnixNano())
   494  	port := 50000 + rand.Intn(1000)
   495  	s, l, _, _ := createGRPCLayer(port)
   496  	nrp := &nonResponsivePeer{
   497  		Listener: l,
   498  		Server:   s,
   499  		port:     port,
   500  	}
   501  	proto.RegisterGossipServer(s, nrp)
   502  	go s.Serve(l)
   503  	return nrp
   504  }
   505  
   506  func (bp *nonResponsivePeer) Ping(context.Context, *proto.Empty) (*proto.Empty, error) {
   507  	time.Sleep(time.Second * 15)
   508  	return &proto.Empty{}, nil
   509  }
   510  
   511  func (bp *nonResponsivePeer) GossipStream(stream proto.Gossip_GossipStreamServer) error {
   512  	return nil
   513  }
   514  
   515  func (bp *nonResponsivePeer) stop() {
   516  	bp.Server.Stop()
   517  	bp.Listener.Close()
   518  }
   519  
   520  func TestNonResponsivePing(t *testing.T) {
   521  	t.Parallel()
   522  	port := 50000 - rand.Intn(1000)
   523  	c, _ := newCommInstance(port, naiveSec)
   524  	defer c.Stop()
   525  	nonRespPeer := newNonResponsivePeer()
   526  	defer nonRespPeer.stop()
   527  	s := make(chan struct{})
   528  	go func() {
   529  		c.Probe(remotePeer(nonRespPeer.port))
   530  		s <- struct{}{}
   531  	}()
   532  	select {
   533  	case <-time.After(time.Second * 10):
   534  		assert.Fail(t, "Request wasn't cancelled on time")
   535  	case <-s:
   536  	}
   537  
   538  }
   539  
   540  func TestResponses(t *testing.T) {
   541  	t.Parallel()
   542  	comm1, _ := newCommInstance(8611, naiveSec)
   543  	comm2, _ := newCommInstance(8612, naiveSec)
   544  
   545  	defer comm1.Stop()
   546  	defer comm2.Stop()
   547  
   548  	wg := sync.WaitGroup{}
   549  
   550  	msg := createGossipMsg()
   551  	wg.Add(1)
   552  	go func() {
   553  		inChan := comm1.Accept(acceptAll)
   554  		wg.Done()
   555  		for m := range inChan {
   556  			reply := createGossipMsg()
   557  			reply.Nonce = m.GetGossipMessage().Nonce + 1
   558  			m.Respond(reply.GossipMessage)
   559  		}
   560  	}()
   561  	expectedNOnce := uint64(msg.Nonce + 1)
   562  	responsesFromComm1 := comm2.Accept(acceptAll)
   563  
   564  	ticker := time.NewTicker(10 * time.Second)
   565  	wg.Wait()
   566  	comm2.Send(msg, remotePeer(8611))
   567  
   568  	select {
   569  	case <-ticker.C:
   570  		assert.Fail(t, "Haven't got response from comm1 within a timely manner")
   571  		break
   572  	case resp := <-responsesFromComm1:
   573  		ticker.Stop()
   574  		assert.Equal(t, expectedNOnce, resp.GetGossipMessage().Nonce)
   575  		break
   576  	}
   577  }
   578  
   579  func TestAccept(t *testing.T) {
   580  	t.Parallel()
   581  	comm1, _ := newCommInstance(7611, naiveSec)
   582  	comm2, _ := newCommInstance(7612, naiveSec)
   583  
   584  	evenNONCESelector := func(m interface{}) bool {
   585  		return m.(proto.ReceivedMessage).GetGossipMessage().Nonce%2 == 0
   586  	}
   587  
   588  	oddNONCESelector := func(m interface{}) bool {
   589  		return m.(proto.ReceivedMessage).GetGossipMessage().Nonce%2 != 0
   590  	}
   591  
   592  	evenNONCES := comm1.Accept(evenNONCESelector)
   593  	oddNONCES := comm1.Accept(oddNONCESelector)
   594  
   595  	var evenResults []uint64
   596  	var oddResults []uint64
   597  
   598  	out := make(chan uint64, util.GetIntOrDefault("peer.gossip.recvBuffSize", defRecvBuffSize))
   599  	sem := make(chan struct{}, 0)
   600  
   601  	readIntoSlice := func(a *[]uint64, ch <-chan proto.ReceivedMessage) {
   602  		for m := range ch {
   603  			*a = append(*a, m.GetGossipMessage().Nonce)
   604  			out <- m.GetGossipMessage().Nonce
   605  		}
   606  		sem <- struct{}{}
   607  	}
   608  
   609  	go readIntoSlice(&evenResults, evenNONCES)
   610  	go readIntoSlice(&oddResults, oddNONCES)
   611  
   612  	for i := 0; i < util.GetIntOrDefault("peer.gossip.recvBuffSize", defRecvBuffSize); i++ {
   613  		comm2.Send(createGossipMsg(), remotePeer(7611))
   614  	}
   615  
   616  	waitForMessages(t, out, util.GetIntOrDefault("peer.gossip.recvBuffSize", defRecvBuffSize), "Didn't receive all messages sent")
   617  
   618  	comm1.Stop()
   619  	comm2.Stop()
   620  
   621  	<-sem
   622  	<-sem
   623  
   624  	assert.NotEmpty(t, evenResults)
   625  	assert.NotEmpty(t, oddResults)
   626  
   627  	remainderPredicate := func(a []uint64, rem uint64) {
   628  		for _, n := range a {
   629  			assert.Equal(t, n%2, rem)
   630  		}
   631  	}
   632  
   633  	remainderPredicate(evenResults, 0)
   634  	remainderPredicate(oddResults, 1)
   635  }
   636  
   637  func TestReConnections(t *testing.T) {
   638  	t.Parallel()
   639  	comm1, _ := newCommInstance(3611, naiveSec)
   640  	comm2, _ := newCommInstance(3612, naiveSec)
   641  
   642  	reader := func(out chan uint64, in <-chan proto.ReceivedMessage) {
   643  		for {
   644  			msg := <-in
   645  			if msg == nil {
   646  				return
   647  			}
   648  			out <- msg.GetGossipMessage().Nonce
   649  		}
   650  	}
   651  
   652  	out1 := make(chan uint64, 10)
   653  	out2 := make(chan uint64, 10)
   654  
   655  	go reader(out1, comm1.Accept(acceptAll))
   656  	go reader(out2, comm2.Accept(acceptAll))
   657  
   658  	// comm1 connects to comm2
   659  	comm1.Send(createGossipMsg(), remotePeer(3612))
   660  	waitForMessages(t, out2, 1, "Comm2 didn't receive a message from comm1 in a timely manner")
   661  	time.Sleep(time.Second)
   662  	// comm2 sends to comm1
   663  	comm2.Send(createGossipMsg(), remotePeer(3611))
   664  	waitForMessages(t, out1, 1, "Comm1 didn't receive a message from comm2 in a timely manner")
   665  
   666  	comm1.Stop()
   667  	comm1, _ = newCommInstance(3611, naiveSec)
   668  	time.Sleep(time.Second)
   669  	out1 = make(chan uint64, 1)
   670  	go reader(out1, comm1.Accept(acceptAll))
   671  	comm2.Send(createGossipMsg(), remotePeer(3611))
   672  	waitForMessages(t, out1, 1, "Comm1 didn't receive a message from comm2 in a timely manner")
   673  }
   674  
   675  func TestProbe(t *testing.T) {
   676  	t.Parallel()
   677  	comm1, _ := newCommInstance(6611, naiveSec)
   678  	defer comm1.Stop()
   679  	comm2, _ := newCommInstance(6612, naiveSec)
   680  	time.Sleep(time.Duration(1) * time.Second)
   681  	assert.NoError(t, comm1.Probe(remotePeer(6612)))
   682  	_, err := comm1.Handshake(remotePeer(6612))
   683  	assert.NoError(t, err)
   684  	assert.Error(t, comm1.Probe(remotePeer(9012)))
   685  	_, err = comm1.Handshake(remotePeer(9012))
   686  	assert.Error(t, err)
   687  	comm2.Stop()
   688  	time.Sleep(time.Second)
   689  	assert.Error(t, comm1.Probe(remotePeer(6612)))
   690  	_, err = comm1.Handshake(remotePeer(6612))
   691  	assert.Error(t, err)
   692  	comm2, _ = newCommInstance(6612, naiveSec)
   693  	defer comm2.Stop()
   694  	time.Sleep(time.Duration(1) * time.Second)
   695  	assert.NoError(t, comm2.Probe(remotePeer(6611)))
   696  	_, err = comm2.Handshake(remotePeer(6611))
   697  	assert.NoError(t, err)
   698  	assert.NoError(t, comm1.Probe(remotePeer(6612)))
   699  	_, err = comm1.Handshake(remotePeer(6612))
   700  	assert.NoError(t, err)
   701  	// Now try a deep probe with an expected PKI-ID that doesn't match
   702  	wrongRemotePeer := remotePeer(6612)
   703  	if wrongRemotePeer.PKIID[0] == 0 {
   704  		wrongRemotePeer.PKIID[0] = 1
   705  	} else {
   706  		wrongRemotePeer.PKIID[0] = 0
   707  	}
   708  	_, err = comm1.Handshake(wrongRemotePeer)
   709  	assert.Error(t, err)
   710  	// Try a deep probe with a nil PKI-ID
   711  	id, err := comm1.Handshake(&RemotePeer{Endpoint: "localhost:6612"})
   712  	assert.NoError(t, err)
   713  	assert.Equal(t, api.PeerIdentityType("localhost:6612"), id)
   714  }
   715  
   716  func TestPresumedDead(t *testing.T) {
   717  	t.Parallel()
   718  	comm1, _ := newCommInstance(4611, naiveSec)
   719  	comm2, _ := newCommInstance(4612, naiveSec)
   720  
   721  	wg := sync.WaitGroup{}
   722  	wg.Add(1)
   723  	go func() {
   724  		wg.Wait()
   725  		comm1.Send(createGossipMsg(), remotePeer(4612))
   726  	}()
   727  
   728  	ticker := time.NewTicker(time.Duration(10) * time.Second)
   729  	acceptCh := comm2.Accept(acceptAll)
   730  	wg.Done()
   731  	select {
   732  	case <-acceptCh:
   733  		ticker.Stop()
   734  	case <-ticker.C:
   735  		assert.Fail(t, "Didn't get first message")
   736  	}
   737  
   738  	comm2.Stop()
   739  	go func() {
   740  		for i := 0; i < 5; i++ {
   741  			comm1.Send(createGossipMsg(), remotePeer(4612))
   742  			time.Sleep(time.Millisecond * 200)
   743  		}
   744  	}()
   745  
   746  	ticker = time.NewTicker(time.Second * time.Duration(3))
   747  	select {
   748  	case <-ticker.C:
   749  		assert.Fail(t, "Didn't get a presumed dead message within a timely manner")
   750  		break
   751  	case <-comm1.PresumedDead():
   752  		ticker.Stop()
   753  		break
   754  	}
   755  }
   756  
   757  func createGossipMsg() *proto.SignedGossipMessage {
   758  	msg, _ := (&proto.GossipMessage{
   759  		Tag:   proto.GossipMessage_EMPTY,
   760  		Nonce: uint64(rand.Int()),
   761  		Content: &proto.GossipMessage_DataMsg{
   762  			DataMsg: &proto.DataMessage{},
   763  		},
   764  	}).NoopSign()
   765  	return msg
   766  }
   767  
   768  func remotePeer(port int) *RemotePeer {
   769  	endpoint := fmt.Sprintf("localhost:%d", port)
   770  	return &RemotePeer{Endpoint: endpoint, PKIID: []byte(endpoint)}
   771  }
   772  
   773  func waitForMessages(t *testing.T, msgChan chan uint64, count int, errMsg string) {
   774  	c := 0
   775  	waiting := true
   776  	ticker := time.NewTicker(time.Duration(10) * time.Second)
   777  	for waiting {
   778  		select {
   779  		case <-msgChan:
   780  			c++
   781  			if c == count {
   782  				waiting = false
   783  			}
   784  		case <-ticker.C:
   785  			waiting = false
   786  		}
   787  	}
   788  	assert.Equal(t, count, c, errMsg)
   789  }
   790  
   791  func TestMain(m *testing.M) {
   792  	SetDialTimeout(time.Duration(300) * time.Millisecond)
   793  
   794  	ret := m.Run()
   795  	os.Exit(ret)
   796  }