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 }