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 }