github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/orderer/common/cluster/service_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package cluster_test
     8  
     9  import (
    10  	"context"
    11  	"io"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hyperledger/fabric-protos-go/orderer"
    17  	"github.com/hyperledger/fabric/common/crypto/tlsgen"
    18  	"github.com/hyperledger/fabric/common/flogging"
    19  	"github.com/hyperledger/fabric/common/metrics/disabled"
    20  	"github.com/hyperledger/fabric/core/comm"
    21  	"github.com/hyperledger/fabric/orderer/common/cluster"
    22  	"github.com/hyperledger/fabric/orderer/common/cluster/mocks"
    23  	"github.com/pkg/errors"
    24  	"github.com/stretchr/testify/assert"
    25  	"github.com/stretchr/testify/mock"
    26  	"go.uber.org/zap"
    27  	"go.uber.org/zap/zapcore"
    28  )
    29  
    30  var (
    31  	submitRequest1 = &orderer.StepRequest{
    32  		Payload: &orderer.StepRequest_SubmitRequest{
    33  			SubmitRequest: &orderer.SubmitRequest{},
    34  		},
    35  	}
    36  	submitRequest2 = &orderer.StepRequest{
    37  		Payload: &orderer.StepRequest_SubmitRequest{
    38  			SubmitRequest: &orderer.SubmitRequest{},
    39  		},
    40  	}
    41  	submitResponse1 = &orderer.StepResponse{
    42  		Payload: &orderer.StepResponse_SubmitRes{
    43  			SubmitRes: &orderer.SubmitResponse{},
    44  		},
    45  	}
    46  	submitResponse2 = &orderer.StepResponse{
    47  		Payload: &orderer.StepResponse_SubmitRes{
    48  			SubmitRes: &orderer.SubmitResponse{},
    49  		},
    50  	}
    51  	consensusRequest = &orderer.StepRequest{
    52  		Payload: &orderer.StepRequest_ConsensusRequest{
    53  			ConsensusRequest: &orderer.ConsensusRequest{
    54  				Payload: []byte{1, 2, 3},
    55  				Channel: "mychannel",
    56  			},
    57  		},
    58  	}
    59  )
    60  
    61  func TestStep(t *testing.T) {
    62  	t.Parallel()
    63  	dispatcher := &mocks.Dispatcher{}
    64  
    65  	svc := &cluster.Service{
    66  		StreamCountReporter: &cluster.StreamCountReporter{
    67  			Metrics: cluster.NewMetrics(&disabled.Provider{}),
    68  		},
    69  		Logger:     flogging.MustGetLogger("test"),
    70  		StepLogger: flogging.MustGetLogger("test"),
    71  		Dispatcher: dispatcher,
    72  	}
    73  
    74  	t.Run("Success", func(t *testing.T) {
    75  		stream := &mocks.StepStream{}
    76  		stream.On("Context").Return(context.Background())
    77  		stream.On("Recv").Return(consensusRequest, nil).Once()
    78  		stream.On("Recv").Return(consensusRequest, nil).Once()
    79  		dispatcher.On("DispatchConsensus", mock.Anything, consensusRequest.GetConsensusRequest()).Return(nil).Once()
    80  		dispatcher.On("DispatchConsensus", mock.Anything, consensusRequest.GetConsensusRequest()).Return(io.EOF).Once()
    81  		err := svc.Step(stream)
    82  		assert.NoError(t, err)
    83  	})
    84  
    85  	t.Run("Failure", func(t *testing.T) {
    86  		stream := &mocks.StepStream{}
    87  		stream.On("Context").Return(context.Background())
    88  		stream.On("Recv").Return(consensusRequest, nil).Once()
    89  		dispatcher.On("DispatchConsensus", mock.Anything, consensusRequest.GetConsensusRequest()).Return(errors.New("oops")).Once()
    90  		err := svc.Step(stream)
    91  		assert.EqualError(t, err, "oops")
    92  	})
    93  }
    94  
    95  func TestSubmitSuccess(t *testing.T) {
    96  	t.Parallel()
    97  	dispatcher := &mocks.Dispatcher{}
    98  
    99  	stream := &mocks.StepStream{}
   100  	stream.On("Context").Return(context.Background())
   101  	// Send to the stream 2 messages, and afterwards close the stream
   102  	stream.On("Recv").Return(submitRequest1, nil).Once()
   103  	stream.On("Recv").Return(submitRequest2, nil).Once()
   104  	stream.On("Recv").Return(nil, io.EOF).Once()
   105  	// Send should be called for each corresponding receive
   106  	stream.On("Send", submitResponse1).Return(nil).Twice()
   107  
   108  	responses := make(chan *orderer.StepRequest, 2)
   109  	responses <- submitRequest1
   110  	responses <- submitRequest2
   111  
   112  	dispatcher.On("DispatchSubmit", mock.Anything, mock.Anything).Return(nil).Once()
   113  	dispatcher.On("DispatchSubmit", mock.Anything, mock.Anything).Return(nil).Once()
   114  	// Ensure we pass requests to DispatchSubmit in-order
   115  	dispatcher.On("DispatchSubmit", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   116  		expectedRequest := <-responses
   117  		actualRequest := args.Get(1).(*orderer.StepRequest)
   118  		assert.True(t, expectedRequest == actualRequest)
   119  	})
   120  
   121  	svc := &cluster.Service{
   122  		StreamCountReporter: &cluster.StreamCountReporter{
   123  			Metrics: cluster.NewMetrics(&disabled.Provider{}),
   124  		},
   125  		Logger:     flogging.MustGetLogger("test"),
   126  		StepLogger: flogging.MustGetLogger("test"),
   127  		Dispatcher: dispatcher,
   128  	}
   129  
   130  	err := svc.Step(stream)
   131  	assert.NoError(t, err)
   132  	dispatcher.AssertNumberOfCalls(t, "DispatchSubmit", 2)
   133  }
   134  
   135  type tuple struct {
   136  	msg interface{}
   137  	err error
   138  }
   139  
   140  func (t tuple) asArray() []interface{} {
   141  	return []interface{}{t.msg, t.err}
   142  }
   143  
   144  func TestSubmitFailure(t *testing.T) {
   145  	t.Parallel()
   146  	oops := errors.New("oops")
   147  	testCases := []struct {
   148  		name               string
   149  		receiveReturns     []tuple
   150  		sendReturns        []error
   151  		dispatchReturns    error
   152  		expectedDispatches int
   153  	}{
   154  		{
   155  			name: "Recv() fails",
   156  			receiveReturns: []tuple{
   157  				{msg: nil, err: oops},
   158  			},
   159  		},
   160  		{
   161  			name: "DispatchSubmit() fails",
   162  			receiveReturns: []tuple{
   163  				{msg: submitRequest1},
   164  			},
   165  			expectedDispatches: 1,
   166  			dispatchReturns:    oops,
   167  		},
   168  	}
   169  
   170  	for _, testCase := range testCases {
   171  		testCase := testCase
   172  		t.Run(testCase.name, func(t *testing.T) {
   173  			dispatcher := &mocks.Dispatcher{}
   174  			stream := &mocks.StepStream{}
   175  			stream.On("Context").Return(context.Background())
   176  			for _, recv := range testCase.receiveReturns {
   177  				stream.On("Recv").Return(recv.asArray()...).Once()
   178  			}
   179  			for _, send := range testCase.sendReturns {
   180  				stream.On("Send", mock.Anything).Return(send).Once()
   181  			}
   182  			defer dispatcher.AssertNumberOfCalls(t, "DispatchSubmit", testCase.expectedDispatches)
   183  			dispatcher.On("DispatchSubmit", mock.Anything, mock.Anything).Return(testCase.dispatchReturns)
   184  			svc := &cluster.Service{
   185  				StreamCountReporter: &cluster.StreamCountReporter{
   186  					Metrics: cluster.NewMetrics(&disabled.Provider{}),
   187  				},
   188  				Logger:     flogging.MustGetLogger("test"),
   189  				StepLogger: flogging.MustGetLogger("test"),
   190  				Dispatcher: dispatcher,
   191  			}
   192  			err := svc.Step(stream)
   193  			assert.EqualError(t, err, oops.Error())
   194  		})
   195  	}
   196  }
   197  
   198  func TestIngresStreamsMetrics(t *testing.T) {
   199  	t.Parallel()
   200  
   201  	dispatcher := &mocks.Dispatcher{}
   202  	dispatcher.On("DispatchConsensus", mock.Anything, mock.Anything).Return(nil)
   203  
   204  	fakeProvider := &mocks.MetricsProvider{}
   205  	testMetrics := &testMetrics{
   206  		fakeProvider: fakeProvider,
   207  	}
   208  	testMetrics.initialize()
   209  
   210  	metrics := cluster.NewMetrics(fakeProvider)
   211  
   212  	svc := &cluster.Service{
   213  		Logger:     flogging.MustGetLogger("test"),
   214  		StepLogger: flogging.MustGetLogger("test"),
   215  		Dispatcher: dispatcher,
   216  		StreamCountReporter: &cluster.StreamCountReporter{
   217  			Metrics: metrics,
   218  		},
   219  	}
   220  
   221  	stream := &mocks.StepStream{}
   222  	stream.On("Context").Return(context.Background())
   223  	// Upon first receive, return nil to proceed to the next receive.
   224  	stream.On("Recv").Return(nil, nil).Once()
   225  	// Upon the second receive, return EOF to trigger the stream to end
   226  	stream.On("Recv").Return(nil, io.EOF).Once()
   227  
   228  	svc.Step(stream)
   229  	// The stream started so stream count incremented from 0 to 1
   230  	assert.Equal(t, float64(1), testMetrics.ingressStreamsCount.SetArgsForCall(0))
   231  	// The stream ended so stream count is decremented from 1 to 0
   232  	assert.Equal(t, float64(0), testMetrics.ingressStreamsCount.SetArgsForCall(1))
   233  }
   234  
   235  func TestServiceGRPC(t *testing.T) {
   236  	t.Parallel()
   237  	// Check that Service correctly implements the gRPC interface
   238  	srv, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{})
   239  	assert.NoError(t, err)
   240  	orderer.RegisterClusterServer(srv.Server(), &cluster.Service{
   241  		Logger:     flogging.MustGetLogger("test"),
   242  		StepLogger: flogging.MustGetLogger("test"),
   243  	})
   244  }
   245  
   246  func TestExpirationWarningIngress(t *testing.T) {
   247  	t.Parallel()
   248  
   249  	ca, err := tlsgen.NewCA()
   250  	assert.NoError(t, err)
   251  
   252  	serverCert, err := ca.NewServerCertKeyPair("127.0.0.1")
   253  	assert.NoError(t, err)
   254  
   255  	clientCert, err := ca.NewClientCertKeyPair()
   256  	assert.NoError(t, err)
   257  
   258  	dispatcher := &mocks.Dispatcher{}
   259  	dispatcher.On("DispatchConsensus", mock.Anything, mock.Anything).Return(nil)
   260  
   261  	svc := &cluster.Service{
   262  		CertExpWarningThreshold:          time.Until(clientCert.TLSCert.NotAfter),
   263  		MinimumExpirationWarningInterval: time.Second * 2,
   264  		StreamCountReporter: &cluster.StreamCountReporter{
   265  			Metrics: cluster.NewMetrics(&disabled.Provider{}),
   266  		},
   267  		Logger:     flogging.MustGetLogger("test"),
   268  		StepLogger: flogging.MustGetLogger("test"),
   269  		Dispatcher: dispatcher,
   270  	}
   271  
   272  	alerts := make(chan struct{}, 10)
   273  	svc.Logger = svc.Logger.WithOptions(zap.Hooks(func(entry zapcore.Entry) error {
   274  		if strings.Contains(entry.Message, "expires in less than 23h59m") {
   275  			alerts <- struct{}{}
   276  		}
   277  		return nil
   278  	}))
   279  
   280  	srvConf := comm.ServerConfig{
   281  		SecOpts: comm.SecureOptions{
   282  			Certificate:       serverCert.Cert,
   283  			Key:               serverCert.Key,
   284  			UseTLS:            true,
   285  			ClientRootCAs:     [][]byte{ca.CertBytes()},
   286  			RequireClientCert: true,
   287  		},
   288  	}
   289  
   290  	srv, err := comm.NewGRPCServer("127.0.0.1:0", srvConf)
   291  	assert.NoError(t, err)
   292  	orderer.RegisterClusterServer(srv.Server(), svc)
   293  	go srv.Start()
   294  	defer srv.Stop()
   295  
   296  	clientConf := comm.ClientConfig{
   297  		Timeout: time.Second * 3,
   298  		SecOpts: comm.SecureOptions{
   299  			ServerRootCAs:     [][]byte{ca.CertBytes()},
   300  			UseTLS:            true,
   301  			Key:               clientCert.Key,
   302  			Certificate:       clientCert.Cert,
   303  			RequireClientCert: true,
   304  		},
   305  	}
   306  
   307  	client, err := comm.NewGRPCClient(clientConf)
   308  	assert.NoError(t, err)
   309  
   310  	conn, err := client.NewConnection(srv.Address())
   311  	assert.NoError(t, err)
   312  
   313  	cl := orderer.NewClusterClient(conn)
   314  	stream, err := cl.Step(context.Background())
   315  	assert.NoError(t, err)
   316  
   317  	err = stream.Send(consensusRequest)
   318  	assert.NoError(t, err)
   319  
   320  	// An alert is logged at the first time.
   321  	select {
   322  	case <-alerts:
   323  	case <-time.After(time.Second * 5):
   324  		t.Fatal("Should have received an alert")
   325  	}
   326  
   327  	err = stream.Send(consensusRequest)
   328  	assert.NoError(t, err)
   329  
   330  	// No alerts in a consecutive time.
   331  	select {
   332  	case <-alerts:
   333  		t.Fatal("Should have not received an alert")
   334  	case <-time.After(time.Millisecond * 500):
   335  	}
   336  
   337  	// Wait for alert expiration interval to expire.
   338  	time.Sleep(svc.MinimumExpirationWarningInterval + time.Second)
   339  
   340  	err = stream.Send(consensusRequest)
   341  	assert.NoError(t, err)
   342  
   343  	// An alert should be logged now after the timeout expired.
   344  	select {
   345  	case <-alerts:
   346  	case <-time.After(time.Second * 5):
   347  		t.Fatal("Should have received an alert")
   348  	}
   349  }