github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/orderer/common/server/main_test.go (about) 1 // Copyright IBM Corp. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package server 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "net" 10 "net/http" 11 "os" 12 "path/filepath" 13 "strconv" 14 "strings" 15 "testing" 16 "time" 17 18 "github.com/golang/protobuf/proto" 19 "github.com/hyperledger/fabric-protos-go/common" 20 "github.com/hyperledger/fabric/bccsp/factory" 21 "github.com/hyperledger/fabric/bccsp/sw" 22 "github.com/hyperledger/fabric/common/channelconfig" 23 "github.com/hyperledger/fabric/common/crypto/tlsgen" 24 deliver_mocks "github.com/hyperledger/fabric/common/deliver/mock" 25 "github.com/hyperledger/fabric/common/flogging" 26 "github.com/hyperledger/fabric/common/flogging/floggingtest" 27 "github.com/hyperledger/fabric/common/ledger/blockledger" 28 "github.com/hyperledger/fabric/common/ledger/blockledger/fileledger" 29 ledger_mocks "github.com/hyperledger/fabric/common/ledger/blockledger/mocks" 30 "github.com/hyperledger/fabric/common/metrics/disabled" 31 "github.com/hyperledger/fabric/common/metrics/prometheus" 32 "github.com/hyperledger/fabric/core/comm" 33 "github.com/hyperledger/fabric/core/config/configtest" 34 "github.com/hyperledger/fabric/internal/configtxgen/encoder" 35 "github.com/hyperledger/fabric/internal/configtxgen/genesisconfig" 36 "github.com/hyperledger/fabric/internal/pkg/identity" 37 "github.com/hyperledger/fabric/orderer/common/bootstrap/file" 38 "github.com/hyperledger/fabric/orderer/common/cluster" 39 "github.com/hyperledger/fabric/orderer/common/localconfig" 40 "github.com/hyperledger/fabric/orderer/common/multichannel" 41 server_mocks "github.com/hyperledger/fabric/orderer/common/server/mocks" 42 "github.com/hyperledger/fabric/orderer/consensus" 43 "github.com/hyperledger/fabric/protoutil" 44 "github.com/pkg/errors" 45 "github.com/stretchr/testify/assert" 46 "github.com/stretchr/testify/mock" 47 "github.com/stretchr/testify/require" 48 "go.uber.org/zap" 49 "go.uber.org/zap/zapcore" 50 ) 51 52 //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer 53 54 type signerSerializer interface { 55 identity.SignerSerializer 56 } 57 58 func TestInitializeLogging(t *testing.T) { 59 origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC") 60 os.Setenv("FABRIC_LOGGING_SPEC", "foo=debug") 61 initializeLogging() 62 assert.Equal(t, "debug", flogging.LoggerLevel("foo")) 63 os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue) 64 } 65 66 func TestInitializeProfilingService(t *testing.T) { 67 origEnvValue := os.Getenv("FABRIC_LOGGING_SPEC") 68 defer os.Setenv("FABRIC_LOGGING_SPEC", origEnvValue) 69 os.Setenv("FABRIC_LOGGING_SPEC", "debug") 70 // get a free random port 71 listenAddr := func() string { 72 l, _ := net.Listen("tcp", "localhost:0") 73 l.Close() 74 return l.Addr().String() 75 }() 76 go initializeProfilingService( 77 &localconfig.TopLevel{ 78 General: localconfig.General{ 79 Profile: localconfig.Profile{ 80 Enabled: true, 81 Address: listenAddr, 82 }}, 83 Kafka: localconfig.Kafka{Verbose: true}, 84 }, 85 ) 86 time.Sleep(500 * time.Millisecond) 87 if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil { 88 t.Logf("Expected pprof to be up (will retry again in 3 seconds): %s", err) 89 time.Sleep(3 * time.Second) 90 if _, err := http.Get("http://" + listenAddr + "/" + "/debug/"); err != nil { 91 t.Fatalf("Expected pprof to be up: %s", err) 92 } 93 } 94 } 95 96 func TestInitializeServerConfig(t *testing.T) { 97 conf := &localconfig.TopLevel{ 98 General: localconfig.General{ 99 ConnectionTimeout: 7 * time.Second, 100 TLS: localconfig.TLS{ 101 Enabled: true, 102 ClientAuthRequired: true, 103 Certificate: "main.go", 104 PrivateKey: "main.go", 105 RootCAs: []string{"main.go"}, 106 ClientRootCAs: []string{"main.go"}, 107 }, 108 }, 109 } 110 sc := initializeServerConfig(conf, nil) 111 expectedContent, _ := ioutil.ReadFile("main.go") 112 assert.Equal(t, expectedContent, sc.SecOpts.Certificate) 113 assert.Equal(t, expectedContent, sc.SecOpts.Key) 114 assert.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ServerRootCAs) 115 assert.Equal(t, [][]byte{expectedContent}, sc.SecOpts.ClientRootCAs) 116 117 sc = initializeServerConfig(conf, nil) 118 defaultOpts := comm.DefaultKeepaliveOptions 119 assert.Equal(t, defaultOpts.ServerMinInterval, sc.KaOpts.ServerMinInterval) 120 assert.Equal(t, time.Duration(0), sc.KaOpts.ServerInterval) 121 assert.Equal(t, time.Duration(0), sc.KaOpts.ServerTimeout) 122 assert.Equal(t, 7*time.Second, sc.ConnectionTimeout) 123 testDuration := 10 * time.Second 124 conf.General.Keepalive = localconfig.Keepalive{ 125 ServerMinInterval: testDuration, 126 ServerInterval: testDuration, 127 ServerTimeout: testDuration, 128 } 129 sc = initializeServerConfig(conf, nil) 130 assert.Equal(t, testDuration, sc.KaOpts.ServerMinInterval) 131 assert.Equal(t, testDuration, sc.KaOpts.ServerInterval) 132 assert.Equal(t, testDuration, sc.KaOpts.ServerTimeout) 133 134 sc = initializeServerConfig(conf, nil) 135 assert.NotNil(t, sc.Logger) 136 assert.Equal(t, comm.NewServerStatsHandler(&disabled.Provider{}), sc.ServerStatsHandler) 137 assert.Len(t, sc.UnaryInterceptors, 2) 138 assert.Len(t, sc.StreamInterceptors, 2) 139 140 sc = initializeServerConfig(conf, &prometheus.Provider{}) 141 assert.NotNil(t, sc.ServerStatsHandler) 142 143 goodFile := "main.go" 144 badFile := "does_not_exist" 145 146 oldLogger := logger 147 defer func() { logger = oldLogger }() 148 logger, _ = floggingtest.NewTestLogger(t) 149 150 testCases := []struct { 151 name string 152 certificate string 153 privateKey string 154 rootCA string 155 clientRootCert string 156 clusterCert string 157 clusterKey string 158 clusterCA string 159 }{ 160 {"BadCertificate", badFile, goodFile, goodFile, goodFile, "", "", ""}, 161 {"BadPrivateKey", goodFile, badFile, goodFile, goodFile, "", "", ""}, 162 {"BadRootCA", goodFile, goodFile, badFile, goodFile, "", "", ""}, 163 {"BadClientRootCertificate", goodFile, goodFile, goodFile, badFile, "", "", ""}, 164 {"ClusterBadCertificate", goodFile, goodFile, goodFile, goodFile, badFile, goodFile, goodFile}, 165 {"ClusterBadPrivateKey", goodFile, goodFile, goodFile, goodFile, goodFile, badFile, goodFile}, 166 {"ClusterBadRootCA", goodFile, goodFile, goodFile, goodFile, goodFile, goodFile, badFile}, 167 } 168 for _, tc := range testCases { 169 t.Run(tc.name, func(t *testing.T) { 170 conf := &localconfig.TopLevel{ 171 General: localconfig.General{ 172 TLS: localconfig.TLS{ 173 Enabled: true, 174 ClientAuthRequired: true, 175 Certificate: tc.certificate, 176 PrivateKey: tc.privateKey, 177 RootCAs: []string{tc.rootCA}, 178 ClientRootCAs: []string{tc.clientRootCert}, 179 }, 180 Cluster: localconfig.Cluster{ 181 ClientCertificate: tc.clusterCert, 182 ClientPrivateKey: tc.clusterKey, 183 RootCAs: []string{tc.clusterCA}, 184 }, 185 }, 186 } 187 assert.Panics(t, func() { 188 if tc.clusterCert == "" { 189 initializeServerConfig(conf, nil) 190 } else { 191 initializeClusterClientConfig(conf) 192 } 193 }, 194 ) 195 }) 196 } 197 } 198 199 func TestInitializeBootstrapChannel(t *testing.T) { 200 cleanup := configtest.SetDevFabricConfigPath(t) 201 defer cleanup() 202 203 genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid") 204 defer os.Remove(genesisFile) 205 206 fileLedgerLocation, _ := ioutil.TempDir("", "main_test-") 207 ledgerFactory, _, err := createLedgerFactory( 208 &localconfig.TopLevel{ 209 FileLedger: localconfig.FileLedger{ 210 Location: fileLedgerLocation, 211 }, 212 }, 213 &disabled.Provider{}, 214 ) 215 assert.NoError(t, err) 216 bootstrapConfig := &localconfig.TopLevel{ 217 General: localconfig.General{ 218 BootstrapMethod: "file", 219 BootstrapFile: genesisFile, 220 }, 221 } 222 223 bootstrapBlock := extractBootstrapBlock(bootstrapConfig) 224 initializeBootstrapChannel(bootstrapBlock, ledgerFactory) 225 226 ledger, err := ledgerFactory.GetOrCreate("testchannelid") 227 assert.NoError(t, err) 228 assert.Equal(t, uint64(1), ledger.Height()) 229 } 230 231 func TestExtractBootstrapBlock(t *testing.T) { 232 cleanup := configtest.SetDevFabricConfigPath(t) 233 defer cleanup() 234 235 genesisFile := produceGenesisFile(t, genesisconfig.SampleSingleMSPSoloProfile, "testchannelid") 236 defer os.Remove(genesisFile) 237 238 tests := []struct { 239 config *localconfig.TopLevel 240 block *common.Block 241 }{ 242 { 243 config: &localconfig.TopLevel{ 244 General: localconfig.General{BootstrapMethod: "file", BootstrapFile: genesisFile}, 245 }, 246 block: file.New(genesisFile).GenesisBlock(), 247 }, 248 { 249 config: &localconfig.TopLevel{ 250 General: localconfig.General{BootstrapMethod: "none"}, 251 }, 252 block: nil, 253 }, 254 } 255 for _, tt := range tests { 256 b := extractBootstrapBlock(tt.config) 257 assert.Truef(t, proto.Equal(tt.block, b), "wanted %v, got %v", tt.block, b) 258 } 259 } 260 261 func TestExtractSysChanLastConfig(t *testing.T) { 262 tmpdir, err := ioutil.TempDir("", "main_test-") 263 require.NoError(t, err) 264 defer os.RemoveAll(tmpdir) 265 266 rlf, err := fileledger.New(tmpdir, &disabled.Provider{}) 267 require.NoError(t, err) 268 269 conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 270 genesisBlock := encoder.New(conf).GenesisBlock() 271 272 lastConf := extractSysChanLastConfig(rlf, genesisBlock) 273 assert.Nil(t, lastConf) 274 275 rl, err := rlf.GetOrCreate("testchannelid") 276 require.NoError(t, err) 277 278 err = rl.Append(genesisBlock) 279 require.NoError(t, err) 280 281 lastConf = extractSysChanLastConfig(rlf, genesisBlock) 282 assert.NotNil(t, lastConf) 283 assert.Equal(t, uint64(0), lastConf.Header.Number) 284 285 assert.Panics(t, func() { 286 _ = extractSysChanLastConfig(rlf, nil) 287 }) 288 289 configTx, err := protoutil.CreateSignedEnvelope(common.HeaderType_CONFIG, "testchannelid", nil, &common.ConfigEnvelope{}, 0, 0) 290 require.NoError(t, err) 291 292 nextBlock := blockledger.CreateNextBlock(rl, []*common.Envelope{configTx}) 293 nextBlock.Metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{ 294 Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: rl.Height()}), 295 }) 296 err = rl.Append(nextBlock) 297 require.NoError(t, err) 298 299 lastConf = extractSysChanLastConfig(rlf, genesisBlock) 300 assert.NotNil(t, lastConf) 301 assert.Equal(t, uint64(1), lastConf.Header.Number) 302 } 303 304 func TestSelectClusterBootBlock(t *testing.T) { 305 bootstrapBlock := &common.Block{Header: &common.BlockHeader{Number: 100}} 306 lastConfBlock := &common.Block{Header: &common.BlockHeader{Number: 100}} 307 308 clusterBoot := selectClusterBootBlock(bootstrapBlock, nil) 309 assert.NotNil(t, clusterBoot) 310 assert.Equal(t, uint64(100), clusterBoot.Header.Number) 311 assert.True(t, bootstrapBlock == clusterBoot) 312 313 clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock) 314 assert.NotNil(t, clusterBoot) 315 assert.Equal(t, uint64(100), clusterBoot.Header.Number) 316 assert.True(t, bootstrapBlock == clusterBoot) 317 318 lastConfBlock.Header.Number = 200 319 clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock) 320 assert.NotNil(t, clusterBoot) 321 assert.Equal(t, uint64(200), clusterBoot.Header.Number) 322 assert.True(t, lastConfBlock == clusterBoot) 323 324 bootstrapBlock.Header.Number = 300 325 clusterBoot = selectClusterBootBlock(bootstrapBlock, lastConfBlock) 326 assert.NotNil(t, clusterBoot) 327 assert.Equal(t, uint64(300), clusterBoot.Header.Number) 328 assert.True(t, bootstrapBlock == clusterBoot) 329 } 330 331 func TestLoadLocalMSP(t *testing.T) { 332 t.Run("Happy", func(t *testing.T) { 333 localMSPDir := configtest.GetDevMspDir() 334 localMSP := loadLocalMSP( 335 &localconfig.TopLevel{ 336 General: localconfig.General{ 337 LocalMSPDir: localMSPDir, 338 LocalMSPID: "SampleOrg", 339 BCCSP: &factory.FactoryOpts{ 340 ProviderName: "SW", 341 SwOpts: &factory.SwOpts{ 342 HashFamily: "SHA2", 343 SecLevel: 256, 344 Ephemeral: true, 345 }, 346 }, 347 }, 348 }, 349 ) 350 require.NotNil(t, localMSP) 351 id, err := localMSP.GetIdentifier() 352 require.NoError(t, err) 353 require.Equal(t, id, "SampleOrg") 354 }) 355 356 t.Run("Error", func(t *testing.T) { 357 oldLogger := logger 358 defer func() { logger = oldLogger }() 359 logger, _ = floggingtest.NewTestLogger(t) 360 361 assert.Panics(t, func() { 362 loadLocalMSP( 363 &localconfig.TopLevel{ 364 General: localconfig.General{ 365 LocalMSPDir: "", 366 LocalMSPID: "", 367 }, 368 }, 369 ) 370 }) 371 }) 372 } 373 374 func TestInitializeMultichannelRegistrar(t *testing.T) { 375 cleanup := configtest.SetDevFabricConfigPath(t) 376 defer cleanup() 377 genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid") 378 defer os.Remove(genesisFile) 379 380 conf := genesisConfig(t, genesisFile) 381 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 382 assert.NoError(t, err) 383 384 signer := &server_mocks.SignerSerializer{} 385 386 t.Run("registrar with a system channel", func(t *testing.T) { 387 lf, _, err := createLedgerFactory(conf, &disabled.Provider{}) 388 assert.NoError(t, err) 389 bootBlock := file.New(genesisFile).GenesisBlock() 390 initializeBootstrapChannel(bootBlock, lf) 391 registrar := initializeMultichannelRegistrar( 392 bootBlock, 393 &replicationInitiator{cryptoProvider: cryptoProvider}, 394 &cluster.PredicateDialer{}, 395 comm.ServerConfig{}, 396 nil, 397 conf, 398 signer, 399 &disabled.Provider{}, 400 &server_mocks.HealthChecker{}, 401 lf, 402 cryptoProvider, 403 ) 404 assert.NotNil(t, registrar) 405 assert.Equal(t, "testchannelid", registrar.SystemChannelID()) 406 }) 407 408 t.Run("registrar without a system channel", func(t *testing.T) { 409 conf.General.BootstrapMethod = "none" 410 conf.General.GenesisFile = "" 411 lf, _, err := createLedgerFactory(conf, &disabled.Provider{}) 412 assert.NoError(t, err) 413 registrar := initializeMultichannelRegistrar( 414 nil, 415 &replicationInitiator{cryptoProvider: cryptoProvider}, 416 &cluster.PredicateDialer{}, 417 comm.ServerConfig{}, 418 nil, 419 conf, 420 signer, 421 &disabled.Provider{}, 422 &server_mocks.HealthChecker{}, 423 lf, 424 cryptoProvider, 425 ) 426 assert.NotNil(t, registrar) 427 assert.Empty(t, registrar.SystemChannelID()) 428 }) 429 } 430 431 func TestInitializeGrpcServer(t *testing.T) { 432 // get a free random port 433 listenAddr := func() string { 434 l, _ := net.Listen("tcp", "localhost:0") 435 l.Close() 436 return l.Addr().String() 437 }() 438 host := strings.Split(listenAddr, ":")[0] 439 port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16) 440 conf := &localconfig.TopLevel{ 441 General: localconfig.General{ 442 ListenAddress: host, 443 ListenPort: uint16(port), 444 TLS: localconfig.TLS{ 445 Enabled: false, 446 ClientAuthRequired: false, 447 }, 448 }, 449 } 450 assert.NotPanics(t, func() { 451 grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil)) 452 grpcServer.Listener().Close() 453 }) 454 } 455 456 func TestUpdateTrustedRoots(t *testing.T) { 457 cleanup := configtest.SetDevFabricConfigPath(t) 458 defer cleanup() 459 460 genesisFile := produceGenesisFile(t, genesisconfig.SampleDevModeSoloProfile, "testchannelid") 461 defer os.Remove(genesisFile) 462 463 // get a free random port 464 listenAddr := func() string { 465 l, _ := net.Listen("tcp", "localhost:0") 466 l.Close() 467 return l.Addr().String() 468 }() 469 port, _ := strconv.ParseUint(strings.Split(listenAddr, ":")[1], 10, 16) 470 conf := &localconfig.TopLevel{ 471 General: localconfig.General{ 472 BootstrapMethod: "file", 473 BootstrapFile: genesisFile, 474 ListenAddress: "localhost", 475 ListenPort: uint16(port), 476 TLS: localconfig.TLS{ 477 Enabled: false, 478 ClientAuthRequired: false, 479 }, 480 }, 481 } 482 grpcServer := initializeGrpcServer(conf, initializeServerConfig(conf, nil)) 483 caMgr := &caManager{ 484 appRootCAsByChain: make(map[string][][]byte), 485 ordererRootCAsByChain: make(map[string][][]byte), 486 } 487 callback := func(bundle *channelconfig.Bundle) { 488 if grpcServer.MutualTLSRequired() { 489 t.Log("callback called") 490 caMgr.updateTrustedRoots(bundle, grpcServer) 491 } 492 } 493 lf, _, err := createLedgerFactory(conf, &disabled.Provider{}) 494 assert.NoError(t, err) 495 bootBlock := file.New(genesisFile).GenesisBlock() 496 initializeBootstrapChannel(bootBlock, lf) 497 signer := &server_mocks.SignerSerializer{} 498 499 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 500 assert.NoError(t, err) 501 502 initializeMultichannelRegistrar( 503 bootBlock, 504 &replicationInitiator{cryptoProvider: cryptoProvider}, 505 &cluster.PredicateDialer{}, 506 comm.ServerConfig{}, 507 nil, 508 genesisConfig(t, genesisFile), 509 signer, 510 &disabled.Provider{}, 511 &server_mocks.HealthChecker{}, 512 lf, 513 cryptoProvider, 514 callback, 515 ) 516 t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"])) 517 t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"])) 518 // mutual TLS not required so no updates should have occurred 519 assert.Equal(t, 0, len(caMgr.appRootCAsByChain["testchannelid"])) 520 assert.Equal(t, 0, len(caMgr.ordererRootCAsByChain["testchannelid"])) 521 grpcServer.Listener().Close() 522 523 conf = &localconfig.TopLevel{ 524 General: localconfig.General{ 525 ListenAddress: "localhost", 526 ListenPort: uint16(port), 527 TLS: localconfig.TLS{ 528 Enabled: true, 529 ClientAuthRequired: true, 530 PrivateKey: filepath.Join(".", "testdata", "example.com", "tls", "server.key"), 531 Certificate: filepath.Join(".", "testdata", "example.com", "tls", "server.crt"), 532 }, 533 }, 534 } 535 grpcServer = initializeGrpcServer(conf, initializeServerConfig(conf, nil)) 536 caMgr = &caManager{ 537 appRootCAsByChain: make(map[string][][]byte), 538 ordererRootCAsByChain: make(map[string][][]byte), 539 } 540 541 clusterConf := initializeClusterClientConfig(conf) 542 predDialer := &cluster.PredicateDialer{ 543 Config: clusterConf, 544 } 545 546 callback = func(bundle *channelconfig.Bundle) { 547 if grpcServer.MutualTLSRequired() { 548 t.Log("callback called") 549 caMgr.updateTrustedRoots(bundle, grpcServer) 550 caMgr.updateClusterDialer(predDialer, clusterConf.SecOpts.ServerRootCAs) 551 } 552 } 553 initializeMultichannelRegistrar( 554 bootBlock, 555 &replicationInitiator{cryptoProvider: cryptoProvider}, 556 predDialer, 557 comm.ServerConfig{}, 558 nil, 559 genesisConfig(t, genesisFile), 560 signer, 561 &disabled.Provider{}, 562 &server_mocks.HealthChecker{}, 563 lf, 564 cryptoProvider, 565 callback, 566 ) 567 t.Logf("# app CAs: %d", len(caMgr.appRootCAsByChain["testchannelid"])) 568 t.Logf("# orderer CAs: %d", len(caMgr.ordererRootCAsByChain["testchannelid"])) 569 // mutual TLS is required so updates should have occurred 570 // we expect an intermediate and root CA for apps and orderers 571 assert.Equal(t, 2, len(caMgr.appRootCAsByChain["testchannelid"])) 572 assert.Equal(t, 2, len(caMgr.ordererRootCAsByChain["testchannelid"])) 573 assert.Len(t, predDialer.Config.SecOpts.ServerRootCAs, 2) 574 grpcServer.Listener().Close() 575 } 576 577 func TestConfigureClusterListener(t *testing.T) { 578 logEntries := make(chan string, 100) 579 580 allocatePort := func() uint16 { 581 l, err := net.Listen("tcp", "127.0.0.1:0") 582 assert.NoError(t, err) 583 _, portStr, err := net.SplitHostPort(l.Addr().String()) 584 assert.NoError(t, err) 585 port, err := strconv.ParseInt(portStr, 10, 64) 586 assert.NoError(t, err) 587 assert.NoError(t, l.Close()) 588 t.Log("picked unused port", port) 589 return uint16(port) 590 } 591 592 unUsedPort := allocatePort() 593 594 backupLogger := logger 595 logger = logger.With(zap.Hooks(func(entry zapcore.Entry) error { 596 logEntries <- entry.Message 597 return nil 598 })) 599 600 defer func() { 601 logger = backupLogger 602 }() 603 604 ca, err := tlsgen.NewCA() 605 assert.NoError(t, err) 606 serverKeyPair, err := ca.NewServerCertKeyPair("127.0.0.1") 607 assert.NoError(t, err) 608 609 loadPEM := func(fileName string) ([]byte, error) { 610 switch fileName { 611 case "cert": 612 return serverKeyPair.Cert, nil 613 case "key": 614 return serverKeyPair.Key, nil 615 case "ca": 616 return ca.CertBytes(), nil 617 default: 618 return nil, errors.New("I/O error") 619 } 620 } 621 622 for _, testCase := range []struct { 623 name string 624 conf *localconfig.TopLevel 625 generalConf comm.ServerConfig 626 generalSrv *comm.GRPCServer 627 shouldBeEqual bool 628 expectedPanic string 629 expectedLogEntries []string 630 }{ 631 { 632 name: "invalid certificate", 633 generalConf: comm.ServerConfig{}, 634 conf: &localconfig.TopLevel{ 635 General: localconfig.General{ 636 Cluster: localconfig.Cluster{ 637 ListenAddress: "127.0.0.1", 638 ListenPort: 5000, 639 ServerPrivateKey: "key", 640 ServerCertificate: "bad", 641 RootCAs: []string{"ca"}, 642 }, 643 }, 644 }, 645 expectedPanic: "Failed to load cluster server certificate from 'bad' (I/O error)", 646 generalSrv: &comm.GRPCServer{}, 647 expectedLogEntries: []string{"Failed to load cluster server certificate from 'bad' (I/O error)"}, 648 }, 649 { 650 name: "invalid key", 651 generalConf: comm.ServerConfig{}, 652 conf: &localconfig.TopLevel{ 653 General: localconfig.General{ 654 Cluster: localconfig.Cluster{ 655 ListenAddress: "127.0.0.1", 656 ListenPort: 5000, 657 ServerPrivateKey: "bad", 658 ServerCertificate: "cert", 659 RootCAs: []string{"ca"}, 660 }, 661 }, 662 }, 663 expectedPanic: "Failed to load cluster server key from 'bad' (I/O error)", 664 generalSrv: &comm.GRPCServer{}, 665 expectedLogEntries: []string{"Failed to load cluster server certificate from 'bad' (I/O error)"}, 666 }, 667 { 668 name: "invalid ca cert", 669 generalConf: comm.ServerConfig{}, 670 conf: &localconfig.TopLevel{ 671 General: localconfig.General{ 672 Cluster: localconfig.Cluster{ 673 ListenAddress: "127.0.0.1", 674 ListenPort: 5000, 675 ServerPrivateKey: "key", 676 ServerCertificate: "cert", 677 RootCAs: []string{"bad"}, 678 }, 679 }, 680 }, 681 expectedPanic: "Failed to load CA cert file 'bad' (I/O error)", 682 generalSrv: &comm.GRPCServer{}, 683 expectedLogEntries: []string{"Failed to load CA cert file 'bad' (I/O error)"}, 684 }, 685 { 686 name: "bad listen address", 687 generalConf: comm.ServerConfig{}, 688 conf: &localconfig.TopLevel{ 689 General: localconfig.General{ 690 Cluster: localconfig.Cluster{ 691 ListenAddress: "99.99.99.99", 692 ListenPort: unUsedPort, 693 ServerPrivateKey: "key", 694 ServerCertificate: "cert", 695 RootCAs: []string{"ca"}, 696 }, 697 }, 698 }, 699 expectedPanic: fmt.Sprintf("Failed creating gRPC server on 99.99.99.99:%d due "+ 700 "to listen tcp 99.99.99.99:%d:", unUsedPort, unUsedPort), 701 generalSrv: &comm.GRPCServer{}, 702 }, 703 { 704 name: "green path", 705 generalConf: comm.ServerConfig{}, 706 conf: &localconfig.TopLevel{ 707 General: localconfig.General{ 708 Cluster: localconfig.Cluster{ 709 ListenAddress: "127.0.0.1", 710 ListenPort: 5000, 711 ServerPrivateKey: "key", 712 ServerCertificate: "cert", 713 RootCAs: []string{"ca"}, 714 }, 715 }, 716 }, 717 generalSrv: &comm.GRPCServer{}, 718 }, 719 } { 720 t.Run(testCase.name, func(t *testing.T) { 721 if testCase.shouldBeEqual { 722 conf, srv := configureClusterListener(testCase.conf, testCase.generalConf, loadPEM) 723 assert.Equal(t, conf, testCase.generalConf) 724 assert.Equal(t, srv, testCase.generalSrv) 725 } 726 727 if testCase.expectedPanic != "" { 728 f := func() { 729 configureClusterListener(testCase.conf, testCase.generalConf, loadPEM) 730 } 731 assert.Contains(t, panicMsg(f), testCase.expectedPanic) 732 } else { 733 configureClusterListener(testCase.conf, testCase.generalConf, loadPEM) 734 } 735 // Ensure logged messages that are expected were all logged 736 var loggedMessages []string 737 for len(logEntries) > 0 { 738 logEntry := <-logEntries 739 loggedMessages = append(loggedMessages, logEntry) 740 } 741 assert.Subset(t, testCase.expectedLogEntries, loggedMessages) 742 }) 743 } 744 } 745 746 func TestReuseListener(t *testing.T) { 747 t.Run("good to reuse", func(t *testing.T) { 748 top := &localconfig.TopLevel{General: localconfig.General{TLS: localconfig.TLS{Enabled: true}}} 749 require.True(t, reuseListener(top, "foo")) 750 }) 751 752 t.Run("reuse tls disabled", func(t *testing.T) { 753 top := &localconfig.TopLevel{} 754 require.PanicsWithValue( 755 t, 756 "TLS is required for running ordering nodes of type foo.", 757 func() { reuseListener(top, "foo") }, 758 ) 759 }) 760 761 t.Run("good not to reuse", func(t *testing.T) { 762 top := &localconfig.TopLevel{ 763 General: localconfig.General{ 764 Cluster: localconfig.Cluster{ 765 ListenAddress: "127.0.0.1", 766 ListenPort: 5000, 767 ServerPrivateKey: "key", 768 ServerCertificate: "bad", 769 }, 770 }, 771 } 772 require.False(t, reuseListener(top, "foo")) 773 }) 774 775 t.Run("partial config", func(t *testing.T) { 776 top := &localconfig.TopLevel{ 777 General: localconfig.General{ 778 Cluster: localconfig.Cluster{ 779 ListenAddress: "127.0.0.1", 780 ListenPort: 5000, 781 ServerCertificate: "bad", 782 }, 783 }, 784 } 785 require.PanicsWithValue( 786 t, 787 "Options: General.Cluster.ListenPort, General.Cluster.ListenAddress,"+ 788 " General.Cluster.ServerCertificate, General.Cluster.ServerPrivateKey, should be defined altogether.", 789 func() { reuseListener(top, "foo") }, 790 ) 791 }) 792 } 793 794 func TestInitializeEtcdraftConsenter(t *testing.T) { 795 consenters := make(map[string]consensus.Consenter) 796 797 tmpdir, err := ioutil.TempDir("", "main_test-") 798 require.NoError(t, err) 799 defer os.RemoveAll(tmpdir) 800 rlf, err := fileledger.New(tmpdir, &disabled.Provider{}) 801 require.NoError(t, err) 802 803 conf := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 804 genesisBlock := encoder.New(conf).GenesisBlock() 805 806 ca, _ := tlsgen.NewCA() 807 crt, _ := ca.NewServerCertKeyPair("127.0.0.1") 808 809 srv, err := comm.NewGRPCServer("127.0.0.1:0", comm.ServerConfig{}) 810 assert.NoError(t, err) 811 812 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 813 assert.NoError(t, err) 814 815 initializeEtcdraftConsenter(consenters, 816 &localconfig.TopLevel{}, 817 rlf, 818 &cluster.PredicateDialer{}, 819 genesisBlock, &replicationInitiator{cryptoProvider: cryptoProvider}, 820 comm.ServerConfig{ 821 SecOpts: comm.SecureOptions{ 822 Certificate: crt.Cert, 823 Key: crt.Key, 824 UseTLS: true, 825 }, 826 }, 827 srv, 828 &multichannel.Registrar{}, 829 &disabled.Provider{}, 830 cryptoProvider, 831 ) 832 assert.NotNil(t, consenters["etcdraft"]) 833 } 834 835 func genesisConfig(t *testing.T, genesisFile string) *localconfig.TopLevel { 836 t.Helper() 837 localMSPDir := configtest.GetDevMspDir() 838 return &localconfig.TopLevel{ 839 General: localconfig.General{ 840 BootstrapMethod: "file", 841 BootstrapFile: genesisFile, 842 LocalMSPDir: localMSPDir, 843 LocalMSPID: "SampleOrg", 844 BCCSP: &factory.FactoryOpts{ 845 ProviderName: "SW", 846 SwOpts: &factory.SwOpts{ 847 HashFamily: "SHA2", 848 SecLevel: 256, 849 Ephemeral: true, 850 }, 851 }, 852 }, 853 } 854 } 855 856 func panicMsg(f func()) string { 857 var message interface{} 858 func() { 859 860 defer func() { 861 message = recover() 862 }() 863 864 f() 865 866 }() 867 868 return message.(string) 869 870 } 871 872 func TestCreateReplicator(t *testing.T) { 873 cleanup := configtest.SetDevFabricConfigPath(t) 874 defer cleanup() 875 bootBlock := encoder.New(genesisconfig.Load(genesisconfig.SampleDevModeSoloProfile)).GenesisBlockForChannel("system") 876 877 iterator := &deliver_mocks.BlockIterator{} 878 iterator.NextReturnsOnCall(0, bootBlock, common.Status_SUCCESS) 879 iterator.NextReturnsOnCall(1, bootBlock, common.Status_SUCCESS) 880 881 ledger := &ledger_mocks.ReadWriter{} 882 ledger.On("Height").Return(uint64(1)) 883 ledger.On("Iterator", mock.Anything).Return(iterator, uint64(1)) 884 885 ledgerFactory := &server_mocks.Factory{} 886 ledgerFactory.On("GetOrCreate", "mychannel").Return(ledger, nil) 887 ledgerFactory.On("ChannelIDs").Return([]string{"mychannel"}) 888 889 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 890 assert.NoError(t, err) 891 892 signer := &server_mocks.SignerSerializer{} 893 r := createReplicator(ledgerFactory, bootBlock, &localconfig.TopLevel{}, comm.SecureOptions{}, signer, cryptoProvider) 894 895 err = r.verifierRetriever.RetrieveVerifier("mychannel").VerifyBlockSignature(nil, nil) 896 assert.EqualError(t, err, "implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Writers' sub-policies to be satisfied") 897 898 err = r.verifierRetriever.RetrieveVerifier("system").VerifyBlockSignature(nil, nil) 899 assert.NoError(t, err) 900 } 901 902 func produceGenesisFile(t *testing.T, profile, channelID string) string { 903 conf := genesisconfig.Load(profile, configtest.GetDevConfigDir()) 904 f, err := ioutil.TempFile("", fmt.Sprintf("%s-genesis_block-", t.Name())) 905 require.NoError(t, err) 906 _, err = f.Write(protoutil.MarshalOrPanic(encoder.New(conf).GenesisBlockForChannel(channelID))) 907 require.NoError(t, err) 908 err = f.Close() 909 require.NoError(t, err) 910 return f.Name() 911 }