github.com/lzy4123/fabric@v2.1.1+incompatible/internal/peer/channel/create_test.go (about) 1 /* 2 Copyright Digital Asset Holdings, LLC All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package channel 8 9 import ( 10 "bytes" 11 "errors" 12 "fmt" 13 "io/ioutil" 14 "net" 15 "os" 16 "path/filepath" 17 "regexp" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/golang/protobuf/proto" 23 cb "github.com/hyperledger/fabric-protos-go/common" 24 "github.com/hyperledger/fabric-protos-go/orderer" 25 "github.com/hyperledger/fabric/core/config/configtest" 26 "github.com/hyperledger/fabric/internal/peer/common" 27 "github.com/hyperledger/fabric/internal/peer/common/mock" 28 "github.com/hyperledger/fabric/internal/pkg/identity" 29 msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools" 30 "github.com/hyperledger/fabric/protoutil" 31 "github.com/spf13/viper" 32 "github.com/stretchr/testify/assert" 33 "google.golang.org/grpc" 34 ) 35 36 //go:generate counterfeiter -o mock/signer_serializer.go --fake-name SignerSerializer . signerSerializer 37 38 type signerSerializer interface { 39 identity.SignerSerializer 40 } 41 42 type timeoutOrderer struct { 43 counter int 44 net.Listener 45 *grpc.Server 46 nextExpectedSeek uint64 47 t *testing.T 48 blockChannel chan uint64 49 } 50 51 func newOrderer(port int, t *testing.T) *timeoutOrderer { 52 srv := grpc.NewServer() 53 lsnr, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 54 if err != nil { 55 panic(err) 56 } 57 o := &timeoutOrderer{Server: srv, 58 Listener: lsnr, 59 t: t, 60 nextExpectedSeek: uint64(1), 61 blockChannel: make(chan uint64, 1), 62 counter: int(1), 63 } 64 orderer.RegisterAtomicBroadcastServer(srv, o) 65 go srv.Serve(lsnr) 66 return o 67 } 68 69 func (o *timeoutOrderer) Shutdown() { 70 o.Server.Stop() 71 o.Listener.Close() 72 } 73 74 func (*timeoutOrderer) Broadcast(orderer.AtomicBroadcast_BroadcastServer) error { 75 panic("Should not have been called") 76 } 77 78 func (o *timeoutOrderer) SendBlock(seq uint64) { 79 o.blockChannel <- seq 80 } 81 82 func (o *timeoutOrderer) Deliver(stream orderer.AtomicBroadcast_DeliverServer) error { 83 o.timeoutIncrement() 84 if o.counter > 5 { 85 o.sendBlock(stream, 0) 86 } 87 return nil 88 } 89 90 func (o *timeoutOrderer) sendBlock(stream orderer.AtomicBroadcast_DeliverServer, seq uint64) { 91 block := &cb.Block{ 92 Header: &cb.BlockHeader{ 93 Number: seq, 94 }, 95 } 96 stream.Send(&orderer.DeliverResponse{ 97 Type: &orderer.DeliverResponse_Block{Block: block}, 98 }) 99 } 100 101 func (o *timeoutOrderer) timeoutIncrement() { 102 o.counter++ 103 } 104 105 var once sync.Once 106 107 /// mock deliver client for UT 108 type mockDeliverClient struct { 109 err error 110 } 111 112 func (m *mockDeliverClient) readBlock() (*cb.Block, error) { 113 if m.err != nil { 114 return nil, m.err 115 } 116 return &cb.Block{}, nil 117 } 118 119 func (m *mockDeliverClient) GetSpecifiedBlock(num uint64) (*cb.Block, error) { 120 return m.readBlock() 121 } 122 123 func (m *mockDeliverClient) GetOldestBlock() (*cb.Block, error) { 124 return m.readBlock() 125 } 126 127 func (m *mockDeliverClient) GetNewestBlock() (*cb.Block, error) { 128 return m.readBlock() 129 } 130 131 func (m *mockDeliverClient) Close() error { 132 return nil 133 } 134 135 // InitMSP init MSP 136 func InitMSP() { 137 once.Do(initMSP) 138 } 139 140 func initMSP() { 141 err := msptesttools.LoadMSPSetupForTesting() 142 if err != nil { 143 panic(fmt.Errorf("Fatal error when reading MSP config: err %s", err)) 144 } 145 } 146 147 func mockBroadcastClientFactory() (common.BroadcastClient, error) { 148 return common.GetMockBroadcastClient(nil), nil 149 } 150 151 func TestCreateChain(t *testing.T) { 152 defer resetFlags() 153 154 InitMSP() 155 cleanup := configtest.SetDevFabricConfigPath(t) 156 defer cleanup() 157 158 mockchain := "mockchain" 159 160 defer os.Remove(mockchain + ".block") 161 162 signer, err := common.GetDefaultSigner() 163 if err != nil { 164 t.Fatalf("Get default signer error: %v", err) 165 } 166 167 mockCF := &ChannelCmdFactory{ 168 BroadcastFactory: mockBroadcastClientFactory, 169 Signer: signer, 170 DeliverClient: &mockDeliverClient{}, 171 } 172 173 cmd := createCmd(mockCF) 174 175 AddFlags(cmd) 176 177 args := []string{"-c", mockchain, "-o", "localhost:7050"} 178 cmd.SetArgs(args) 179 180 if err := cmd.Execute(); err != nil { 181 t.Fail() 182 t.Errorf("expected create command to succeed") 183 } 184 185 filename := mockchain + ".block" 186 if _, err := os.Stat(filename); err != nil { 187 t.Fail() 188 t.Errorf("expected %s to exist", filename) 189 } 190 } 191 192 func TestCreateChainWithOutputBlock(t *testing.T) { 193 defer resetFlags() 194 195 InitMSP() 196 cleanup := configtest.SetDevFabricConfigPath(t) 197 defer cleanup() 198 199 mockchain := "mockchain" 200 201 signer, err := common.GetDefaultSigner() 202 if err != nil { 203 t.Fatalf("Get default signer error: %v", err) 204 } 205 206 mockCF := &ChannelCmdFactory{ 207 BroadcastFactory: mockBroadcastClientFactory, 208 Signer: signer, 209 DeliverClient: &mockDeliverClient{}, 210 } 211 212 cmd := createCmd(mockCF) 213 AddFlags(cmd) 214 215 tempDir, err := ioutil.TempDir("", "create-output") 216 if err != nil { 217 t.Fatalf("failed to create temporary directory") 218 } 219 defer os.RemoveAll(tempDir) 220 221 outputBlockPath := filepath.Join(tempDir, "output.block") 222 args := []string{"-c", mockchain, "-o", "localhost:7050", "--outputBlock", outputBlockPath} 223 cmd.SetArgs(args) 224 defer func() { outputBlock = "" }() 225 226 err = cmd.Execute() 227 assert.NoError(t, err, "execute should succeed") 228 229 _, err = os.Stat(outputBlockPath) 230 assert.NoErrorf(t, err, "expected %s to exist", outputBlockPath) 231 } 232 233 func TestCreateChainWithDefaultAnchorPeers(t *testing.T) { 234 defer resetFlags() 235 236 InitMSP() 237 cleanup := configtest.SetDevFabricConfigPath(t) 238 defer cleanup() 239 240 mockchain := "mockchain" 241 242 defer os.Remove(mockchain + ".block") 243 244 signer, err := common.GetDefaultSigner() 245 if err != nil { 246 t.Fatalf("Get default signer error: %v", err) 247 } 248 249 mockCF := &ChannelCmdFactory{ 250 BroadcastFactory: mockBroadcastClientFactory, 251 Signer: signer, 252 DeliverClient: &mockDeliverClient{}, 253 } 254 255 cmd := createCmd(mockCF) 256 AddFlags(cmd) 257 args := []string{"-c", mockchain, "-o", "localhost:7050"} 258 cmd.SetArgs(args) 259 260 if err := cmd.Execute(); err != nil { 261 t.Fail() 262 t.Errorf("expected create command to succeed") 263 } 264 } 265 266 func TestCreateChainWithWaitSuccess(t *testing.T) { 267 defer resetFlags() 268 269 InitMSP() 270 cleanup := configtest.SetDevFabricConfigPath(t) 271 defer cleanup() 272 273 mockchain := "mockchain" 274 275 signer, err := common.GetDefaultSigner() 276 if err != nil { 277 t.Fatalf("Get default signer error: %v", err) 278 } 279 280 mockCF := &ChannelCmdFactory{ 281 BroadcastFactory: mockBroadcastClientFactory, 282 Signer: signer, 283 DeliverClient: &mockDeliverClient{err: nil}, 284 } 285 fakeOrderer := newOrderer(8101, t) 286 defer fakeOrderer.Shutdown() 287 288 cmd := createCmd(mockCF) 289 AddFlags(cmd) 290 args := []string{"-c", mockchain, "-o", "localhost:8101", "-t", "10s"} 291 cmd.SetArgs(args) 292 293 if err := cmd.Execute(); err != nil { 294 t.Fail() 295 t.Errorf("expected create command to succeed") 296 } 297 } 298 299 func TestCreateChainWithTimeoutErr(t *testing.T) { 300 defer viper.Reset() 301 defer resetFlags() 302 303 InitMSP() 304 cleanup := configtest.SetDevFabricConfigPath(t) 305 defer cleanup() 306 307 mockchain := "mockchain" 308 309 signer, err := common.GetDefaultSigner() 310 if err != nil { 311 t.Fatalf("Get default signer error: %v", err) 312 } 313 314 mockCF := &ChannelCmdFactory{ 315 BroadcastFactory: mockBroadcastClientFactory, 316 Signer: signer, 317 DeliverClient: &mockDeliverClient{err: errors.New("bobsled")}, 318 } 319 fakeOrderer := newOrderer(8102, t) 320 defer fakeOrderer.Shutdown() 321 322 // failure - connects to orderer but times out waiting for channel to 323 // be created 324 cmd := createCmd(mockCF) 325 AddFlags(cmd) 326 channelCmd.AddCommand(cmd) 327 args := []string{"create", "-c", mockchain, "-o", "localhost:8102", "-t", "10ms", "--connTimeout", "1s"} 328 channelCmd.SetArgs(args) 329 330 if err := channelCmd.Execute(); err == nil { 331 t.Error("expected create chain to fail with deliver error") 332 } else { 333 assert.Contains(t, err.Error(), "timeout waiting for channel creation") 334 } 335 336 // failure - point to bad port and time out connecting to orderer 337 args = []string{"create", "-c", mockchain, "-o", "localhost:0", "-t", "1s", "--connTimeout", "10ms"} 338 channelCmd.SetArgs(args) 339 340 if err := channelCmd.Execute(); err == nil { 341 t.Error("expected create chain to fail with deliver error") 342 } else { 343 assert.Contains(t, err.Error(), "failed connecting") 344 } 345 } 346 347 func TestCreateChainBCFail(t *testing.T) { 348 defer resetFlags() 349 350 InitMSP() 351 cleanup := configtest.SetDevFabricConfigPath(t) 352 defer cleanup() 353 354 mockchain := "mockchain" 355 356 defer os.Remove(mockchain + ".block") 357 358 signer, err := common.GetDefaultSigner() 359 if err != nil { 360 t.Fatalf("Get default signer error: %v", err) 361 } 362 363 sendErr := errors.New("luge") 364 mockCF := &ChannelCmdFactory{ 365 BroadcastFactory: func() (common.BroadcastClient, error) { 366 return common.GetMockBroadcastClient(sendErr), nil 367 }, 368 Signer: signer, 369 DeliverClient: &mockDeliverClient{}, 370 } 371 372 cmd := createCmd(mockCF) 373 AddFlags(cmd) 374 args := []string{"-c", mockchain, "-o", "localhost:7050"} 375 cmd.SetArgs(args) 376 377 expectedErrMsg := sendErr.Error() 378 if err := cmd.Execute(); err == nil { 379 t.Error("expected create chain to fail with broadcast error") 380 } else { 381 if err.Error() != expectedErrMsg { 382 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 383 } 384 } 385 } 386 387 func TestCreateChainDeliverFail(t *testing.T) { 388 defer resetFlags() 389 390 InitMSP() 391 cleanup := configtest.SetDevFabricConfigPath(t) 392 defer cleanup() 393 394 mockchain := "mockchain" 395 396 defer os.Remove(mockchain + ".block") 397 398 signer, err := common.GetDefaultSigner() 399 if err != nil { 400 t.Fatalf("Get default signer error: %v", err) 401 } 402 403 sendErr := fmt.Errorf("skeleton") 404 mockCF := &ChannelCmdFactory{ 405 BroadcastFactory: func() (common.BroadcastClient, error) { 406 return common.GetMockBroadcastClient(sendErr), nil 407 }, 408 Signer: signer, 409 DeliverClient: &mockDeliverClient{err: sendErr}, 410 } 411 cmd := createCmd(mockCF) 412 AddFlags(cmd) 413 args := []string{"-c", mockchain, "-o", "localhost:7050"} 414 cmd.SetArgs(args) 415 416 expectedErrMsg := sendErr.Error() 417 if err := cmd.Execute(); err == nil { 418 t.Errorf("expected create chain to fail with deliver error") 419 } else { 420 if err.Error() != expectedErrMsg { 421 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 422 } 423 } 424 } 425 426 func createTxFile(filename string, typ cb.HeaderType, channelID string) (*cb.Envelope, error) { 427 ch := &cb.ChannelHeader{Type: int32(typ), ChannelId: channelID} 428 data, err := proto.Marshal(ch) 429 if err != nil { 430 return nil, err 431 } 432 433 p := &cb.Payload{Header: &cb.Header{ChannelHeader: data}} 434 data, err = proto.Marshal(p) 435 if err != nil { 436 return nil, err 437 } 438 439 env := &cb.Envelope{Payload: data} 440 data, err = proto.Marshal(env) 441 if err != nil { 442 return nil, err 443 } 444 445 if err = ioutil.WriteFile(filename, data, 0644); err != nil { 446 return nil, err 447 } 448 449 return env, nil 450 } 451 452 func TestCreateChainFromTx(t *testing.T) { 453 defer resetFlags() 454 InitMSP() 455 cleanup := configtest.SetDevFabricConfigPath(t) 456 defer cleanup() 457 458 mockchannel := "mockchannel" 459 dir, err := ioutil.TempDir("", "createtestfromtx-") 460 if err != nil { 461 t.Fatalf("couldn't create temp dir") 462 } 463 defer os.RemoveAll(dir) // clean up 464 465 //this could be created by the create command 466 defer os.Remove(mockchannel + ".block") 467 468 file := filepath.Join(dir, mockchannel) 469 470 signer, err := common.GetDefaultSigner() 471 if err != nil { 472 t.Fatalf("Get default signer error: %v", err) 473 } 474 mockCF := &ChannelCmdFactory{ 475 BroadcastFactory: mockBroadcastClientFactory, 476 Signer: signer, 477 DeliverClient: &mockDeliverClient{}, 478 } 479 480 cmd := createCmd(mockCF) 481 AddFlags(cmd) 482 483 // Error case 0 484 args := []string{"-c", "", "-f", file, "-o", "localhost:7050"} 485 cmd.SetArgs(args) 486 err = cmd.Execute() 487 assert.Error(t, err, "Create command should have failed because channel ID is not specified") 488 assert.Contains(t, err.Error(), "must supply channel ID") 489 490 // Error case 1 491 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 492 cmd.SetArgs(args) 493 err = cmd.Execute() 494 assert.Error(t, err, "Create command should have failed because tx file does not exist") 495 var msgExpr = regexp.MustCompile(`channel create configuration tx file not found.*no such file or directory`) 496 assert.True(t, msgExpr.MatchString(err.Error())) 497 498 // Success case: -f option is empty 499 args = []string{"-c", mockchannel, "-f", "", "-o", "localhost:7050"} 500 cmd.SetArgs(args) 501 err = cmd.Execute() 502 assert.NoError(t, err) 503 504 // Success case 505 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 506 cmd.SetArgs(args) 507 _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, mockchannel) 508 assert.NoError(t, err, "Couldn't create tx file") 509 err = cmd.Execute() 510 assert.NoError(t, err) 511 } 512 513 func TestCreateChainInvalidTx(t *testing.T) { 514 defer resetFlags() 515 516 InitMSP() 517 cleanup := configtest.SetDevFabricConfigPath(t) 518 defer cleanup() 519 520 mockchannel := "mockchannel" 521 522 dir, err := ioutil.TempDir("", "createinvaltest-") 523 if err != nil { 524 t.Fatalf("couldn't create temp dir") 525 } 526 527 defer os.RemoveAll(dir) // clean up 528 529 //this is created by create command 530 defer os.Remove(mockchannel + ".block") 531 532 file := filepath.Join(dir, mockchannel) 533 534 signer, err := common.GetDefaultSigner() 535 if err != nil { 536 t.Fatalf("Get default signer error: %v", err) 537 } 538 539 mockCF := &ChannelCmdFactory{ 540 BroadcastFactory: mockBroadcastClientFactory, 541 Signer: signer, 542 DeliverClient: &mockDeliverClient{}, 543 } 544 545 cmd := createCmd(mockCF) 546 547 AddFlags(cmd) 548 549 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 550 cmd.SetArgs(args) 551 552 //bad type CONFIG 553 if _, err = createTxFile(file, cb.HeaderType_CONFIG, mockchannel); err != nil { 554 t.Fatalf("couldn't create tx file") 555 } 556 557 defer os.Remove(file) 558 559 if err = cmd.Execute(); err == nil { 560 t.Errorf("expected error") 561 } else if _, ok := err.(InvalidCreateTx); !ok { 562 t.Errorf("invalid error") 563 } 564 565 //bad channel name - does not match one specified in command 566 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, "different_channel"); err != nil { 567 t.Fatalf("couldn't create tx file") 568 } 569 570 if err = cmd.Execute(); err == nil { 571 t.Errorf("expected error") 572 } else if _, ok := err.(InvalidCreateTx); !ok { 573 t.Errorf("invalid error") 574 } 575 576 //empty channel 577 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, ""); err != nil { 578 t.Fatalf("couldn't create tx file") 579 } 580 581 if err := cmd.Execute(); err == nil { 582 t.Errorf("expected error") 583 } else if _, ok := err.(InvalidCreateTx); !ok { 584 t.Errorf("invalid error") 585 } 586 } 587 588 func TestCreateChainNilCF(t *testing.T) { 589 defer viper.Reset() 590 defer resetFlags() 591 592 InitMSP() 593 cleanup := configtest.SetDevFabricConfigPath(t) 594 defer cleanup() 595 596 mockchannel := "mockchannel" 597 dir, err := ioutil.TempDir("", "createinvaltest-") 598 assert.NoError(t, err, "Couldn't create temp dir") 599 defer os.RemoveAll(dir) // clean up 600 601 //this is created by create command 602 defer os.Remove(mockchannel + ".block") 603 file := filepath.Join(dir, mockchannel) 604 605 // Error case: grpc error 606 viper.Set("orderer.client.connTimeout", 10*time.Millisecond) 607 cmd := createCmd(nil) 608 AddFlags(cmd) 609 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 610 cmd.SetArgs(args) 611 err = cmd.Execute() 612 assert.Error(t, err) 613 assert.Contains(t, err.Error(), "failed to create deliver client") 614 615 // Error case: invalid ordering service endpoint 616 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost"} 617 cmd.SetArgs(args) 618 err = cmd.Execute() 619 assert.Error(t, err) 620 assert.Contains(t, err.Error(), "ordering service endpoint localhost is not valid or missing") 621 622 // Error case: invalid ca file 623 defer os.RemoveAll(dir) // clean up 624 channelCmd.AddCommand(cmd) 625 args = []string{"create", "-c", mockchannel, "-f", file, "-o", "localhost:7050", "--tls", "true", "--cafile", dir + "/ca.pem"} 626 channelCmd.SetArgs(args) 627 err = channelCmd.Execute() 628 assert.Error(t, err) 629 t.Log(err) 630 assert.Contains(t, err.Error(), "no such file or directory") 631 } 632 633 func TestSanityCheckAndSignChannelCreateTx(t *testing.T) { 634 defer resetFlags() 635 636 signer := &mock.SignerSerializer{} 637 env := &cb.Envelope{} 638 env.Payload = make([]byte, 10) 639 var err error 640 641 // Error case 1 642 env, err = sanityCheckAndSignConfigTx(env, signer) 643 assert.Error(t, err, "Error expected for nil payload") 644 assert.Contains(t, err.Error(), "bad payload") 645 646 // Error case 2 647 p := &cb.Payload{Header: nil} 648 data, err1 := proto.Marshal(p) 649 assert.NoError(t, err1) 650 env = &cb.Envelope{Payload: data} 651 env, err = sanityCheckAndSignConfigTx(env, signer) 652 assert.Error(t, err, "Error expected for bad payload header") 653 assert.Contains(t, err.Error(), "bad header") 654 655 // Error case 3 656 bites := bytes.NewBufferString("foo").Bytes() 657 p = &cb.Payload{Header: &cb.Header{ChannelHeader: bites}} 658 data, err = proto.Marshal(p) 659 assert.NoError(t, err) 660 env = &cb.Envelope{Payload: data} 661 env, err = sanityCheckAndSignConfigTx(env, signer) 662 assert.Error(t, err, "Error expected for bad channel header") 663 assert.Contains(t, err.Error(), "could not unmarshall channel header") 664 665 // Error case 4 666 mockchannel := "mockchannel" 667 cid := channelID 668 channelID = mockchannel 669 defer func() { 670 channelID = cid 671 }() 672 ch := &cb.ChannelHeader{Type: int32(cb.HeaderType_CONFIG_UPDATE), ChannelId: mockchannel} 673 data, err = proto.Marshal(ch) 674 assert.NoError(t, err) 675 p = &cb.Payload{Header: &cb.Header{ChannelHeader: data}, Data: bytes.NewBufferString("foo").Bytes()} 676 data, err = proto.Marshal(p) 677 assert.NoError(t, err) 678 env = &cb.Envelope{Payload: data} 679 env, err = sanityCheckAndSignConfigTx(env, signer) 680 assert.Error(t, err, "Error expected for bad payload data") 681 assert.Contains(t, err.Error(), "Bad config update env") 682 683 // Error case 5 684 signer = &mock.SignerSerializer{} 685 signer.SerializeReturns(nil, errors.New("bad signer header")) 686 env, err = protoutil.CreateSignedEnvelope( 687 cb.HeaderType_CONFIG_UPDATE, 688 "mockchannel", 689 nil, 690 &cb.ConfigEnvelope{}, 691 0, 692 0) 693 assert.NoError(t, err) 694 env, err = sanityCheckAndSignConfigTx(env, signer) 695 assert.EqualError(t, err, "bad signer header") 696 697 // Error case 6 698 signer = &mock.SignerSerializer{} 699 signer.SignReturns(nil, errors.New("signer failed to sign")) 700 env, err = protoutil.CreateSignedEnvelope( 701 cb.HeaderType_CONFIG_UPDATE, 702 "mockchannel", 703 nil, 704 &cb.ConfigEnvelope{}, 705 0, 706 0) 707 assert.NoError(t, err) 708 env, err = sanityCheckAndSignConfigTx(env, signer) 709 assert.EqualError(t, err, "signer failed to sign") 710 }