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