github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/peer/channel/create_test.go (about) 1 /* 2 Copyright Digital Asset Holdings, LLC 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package channel 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "io/ioutil" 24 "net" 25 "os" 26 "path/filepath" 27 "regexp" 28 "sync" 29 "testing" 30 31 "github.com/golang/protobuf/proto" 32 "github.com/hyperledger/fabric/msp/mgmt/testtools" 33 "github.com/hyperledger/fabric/peer/common" 34 cb "github.com/hyperledger/fabric/protos/common" 35 "github.com/hyperledger/fabric/protos/orderer" 36 "github.com/stretchr/testify/assert" 37 "google.golang.org/grpc" 38 ) 39 40 type timeoutOrderer struct { 41 counter int 42 net.Listener 43 *grpc.Server 44 nextExpectedSeek uint64 45 t *testing.T 46 blockChannel chan uint64 47 } 48 49 func newOrderer(port int, t *testing.T) *timeoutOrderer { 50 srv := grpc.NewServer() 51 lsnr, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 52 if err != nil { 53 panic(err) 54 } 55 go srv.Serve(lsnr) 56 o := &timeoutOrderer{Server: srv, 57 Listener: lsnr, 58 t: t, 59 nextExpectedSeek: uint64(1), 60 blockChannel: make(chan uint64, 1), 61 counter: int(1), 62 } 63 orderer.RegisterAtomicBroadcastServer(srv, o) 64 return o 65 } 66 67 func (o *timeoutOrderer) Shutdown() { 68 o.Server.Stop() 69 o.Listener.Close() 70 } 71 72 func (*timeoutOrderer) Broadcast(orderer.AtomicBroadcast_BroadcastServer) error { 73 panic("Should not have been called") 74 } 75 76 func (o *timeoutOrderer) SendBlock(seq uint64) { 77 o.blockChannel <- seq 78 } 79 80 func (o *timeoutOrderer) Deliver(stream orderer.AtomicBroadcast_DeliverServer) error { 81 o.timeoutIncrement() 82 if o.counter > 5 { 83 o.sendBlock(stream, 0) 84 } 85 return nil 86 } 87 88 func (o *timeoutOrderer) sendBlock(stream orderer.AtomicBroadcast_DeliverServer, seq uint64) { 89 block := &cb.Block{ 90 Header: &cb.BlockHeader{ 91 Number: seq, 92 }, 93 } 94 stream.Send(&orderer.DeliverResponse{ 95 Type: &orderer.DeliverResponse_Block{Block: block}, 96 }) 97 } 98 99 func (o *timeoutOrderer) timeoutIncrement() { 100 o.counter++ 101 } 102 103 var once sync.Once 104 105 /// mock deliver client for UT 106 type mockDeliverClient struct { 107 err error 108 } 109 110 func (m *mockDeliverClient) readBlock() (*cb.Block, error) { 111 if m.err != nil { 112 return nil, m.err 113 } 114 return &cb.Block{}, nil 115 } 116 117 func (m *mockDeliverClient) getSpecifiedBlock(num uint64) (*cb.Block, error) { 118 return m.readBlock() 119 } 120 121 func (m *mockDeliverClient) getOldestBlock() (*cb.Block, error) { 122 return m.readBlock() 123 } 124 125 func (m *mockDeliverClient) getNewestBlock() (*cb.Block, error) { 126 return m.readBlock() 127 } 128 129 func (m *mockDeliverClient) Close() error { 130 return nil 131 } 132 133 // InitMSP init MSP 134 func InitMSP() { 135 once.Do(initMSP) 136 } 137 138 func initMSP() { 139 err := msptesttools.LoadMSPSetupForTesting() 140 if err != nil { 141 panic(fmt.Errorf("Fatal error when reading MSP config: err %s", err)) 142 } 143 } 144 145 func mockBroadcastClientFactory() (common.BroadcastClient, error) { 146 return common.GetMockBroadcastClient(nil), nil 147 } 148 149 func TestCreateChain(t *testing.T) { 150 InitMSP() 151 152 mockchain := "mockchain" 153 154 defer os.Remove(mockchain + ".block") 155 156 signer, err := common.GetDefaultSigner() 157 if err != nil { 158 t.Fatalf("Get default signer error: %v", err) 159 } 160 161 mockCF := &ChannelCmdFactory{ 162 BroadcastFactory: mockBroadcastClientFactory, 163 Signer: signer, 164 DeliverClient: &mockDeliverClient{}, 165 } 166 167 cmd := createCmd(mockCF) 168 169 AddFlags(cmd) 170 171 args := []string{"-c", mockchain, "-o", "localhost:7050"} 172 cmd.SetArgs(args) 173 174 if err := cmd.Execute(); err != nil { 175 t.Fail() 176 t.Errorf("expected create command to succeed") 177 } 178 } 179 180 func TestCreateChainWithDefaultAnchorPeers(t *testing.T) { 181 InitMSP() 182 183 mockchain := "mockchain" 184 185 defer os.Remove(mockchain + ".block") 186 187 signer, err := common.GetDefaultSigner() 188 if err != nil { 189 t.Fatalf("Get default signer error: %v", err) 190 } 191 192 mockCF := &ChannelCmdFactory{ 193 BroadcastFactory: mockBroadcastClientFactory, 194 Signer: signer, 195 DeliverClient: &mockDeliverClient{}, 196 } 197 198 cmd := createCmd(mockCF) 199 200 AddFlags(cmd) 201 202 args := []string{"-c", mockchain, "-o", "localhost:7050"} 203 cmd.SetArgs(args) 204 205 if err := cmd.Execute(); err != nil { 206 t.Fail() 207 t.Errorf("expected create command to succeed") 208 } 209 } 210 211 func TestCreateChainWithWaitSuccess(t *testing.T) { 212 InitMSP() 213 214 mockchain := "mockchain" 215 216 signer, err := common.GetDefaultSigner() 217 if err != nil { 218 t.Fatalf("Get default signer error: %v", err) 219 } 220 221 sendErr := errors.New("timeout waiting for channel creation") 222 mockCF := &ChannelCmdFactory{ 223 BroadcastFactory: mockBroadcastClientFactory, 224 Signer: signer, 225 DeliverClient: &mockDeliverClient{sendErr}, 226 } 227 fakeOrderer := newOrderer(8101, t) 228 defer fakeOrderer.Shutdown() 229 230 cmd := createCmd(mockCF) 231 232 AddFlags(cmd) 233 234 args := []string{"-c", mockchain, "-o", "localhost:8101", "-t", "10"} 235 cmd.SetArgs(args) 236 237 if err := cmd.Execute(); err != nil { 238 t.Fail() 239 t.Errorf("expected create command to succeed") 240 } 241 } 242 243 func TestCreateChainWithTimeoutErr(t *testing.T) { 244 InitMSP() 245 246 mockchain := "mockchain" 247 248 signer, err := common.GetDefaultSigner() 249 if err != nil { 250 t.Fatalf("Get default signer error: %v", err) 251 } 252 253 sendErr := errors.New("timeout waiting for channel creation") 254 mockCF := &ChannelCmdFactory{ 255 BroadcastFactory: mockBroadcastClientFactory, 256 Signer: signer, 257 DeliverClient: &mockDeliverClient{sendErr}, 258 } 259 fakeOrderer := newOrderer(8102, t) 260 defer fakeOrderer.Shutdown() 261 262 cmd := createCmd(mockCF) 263 AddFlags(cmd) 264 265 args := []string{"-c", mockchain, "-o", "localhost:8102", "-t", "1"} 266 cmd.SetArgs(args) 267 268 expectedErrMsg := sendErr.Error() 269 if err := cmd.Execute(); err == nil { 270 t.Error("expected create chain to fail with broadcast error") 271 } else { 272 if err.Error() != expectedErrMsg { 273 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 274 } 275 } 276 } 277 278 func TestCreateChainBCFail(t *testing.T) { 279 InitMSP() 280 281 mockchain := "mockchain" 282 283 defer os.Remove(mockchain + ".block") 284 285 signer, err := common.GetDefaultSigner() 286 if err != nil { 287 t.Fatalf("Get default signer error: %v", err) 288 } 289 290 sendErr := errors.New("send create tx failed") 291 292 mockCF := &ChannelCmdFactory{ 293 BroadcastFactory: func() (common.BroadcastClient, error) { 294 return common.GetMockBroadcastClient(sendErr), nil 295 }, 296 Signer: signer, 297 DeliverClient: &mockDeliverClient{}, 298 } 299 300 cmd := createCmd(mockCF) 301 302 AddFlags(cmd) 303 304 args := []string{"-c", mockchain, "-o", "localhost:7050"} 305 cmd.SetArgs(args) 306 307 expectedErrMsg := sendErr.Error() 308 if err := cmd.Execute(); err == nil { 309 t.Error("expected create chain to fail with broadcast error") 310 } else { 311 if err.Error() != expectedErrMsg { 312 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 313 } 314 } 315 } 316 317 func TestCreateChainDeliverFail(t *testing.T) { 318 InitMSP() 319 320 mockchain := "mockchain" 321 322 defer os.Remove(mockchain + ".block") 323 324 signer, err := common.GetDefaultSigner() 325 if err != nil { 326 t.Fatalf("Get default signer error: %v", err) 327 } 328 329 sendErr := fmt.Errorf("failed connecting") 330 331 mockCF := &ChannelCmdFactory{ 332 BroadcastFactory: func() (common.BroadcastClient, error) { 333 return common.GetMockBroadcastClient(sendErr), nil 334 }, 335 Signer: signer, 336 DeliverClient: &mockDeliverClient{sendErr}, 337 } 338 339 cmd := createCmd(mockCF) 340 341 AddFlags(cmd) 342 343 args := []string{"-c", mockchain, "-o", "localhost:7050"} 344 cmd.SetArgs(args) 345 346 expectedErrMsg := sendErr.Error() 347 if err := cmd.Execute(); err == nil { 348 t.Errorf("expected create chain to fail with deliver error") 349 } else { 350 if err.Error() != expectedErrMsg { 351 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 352 } 353 } 354 } 355 356 func createTxFile(filename string, typ cb.HeaderType, channelID string) (*cb.Envelope, error) { 357 ch := &cb.ChannelHeader{Type: int32(typ), ChannelId: channelID} 358 data, err := proto.Marshal(ch) 359 if err != nil { 360 return nil, err 361 } 362 363 p := &cb.Payload{Header: &cb.Header{ChannelHeader: data}} 364 data, err = proto.Marshal(p) 365 if err != nil { 366 return nil, err 367 } 368 369 env := &cb.Envelope{Payload: data} 370 data, err = proto.Marshal(env) 371 if err != nil { 372 return nil, err 373 } 374 375 if err = ioutil.WriteFile(filename, data, 0644); err != nil { 376 return nil, err 377 } 378 379 return env, nil 380 } 381 382 func TestCreateChainFromTx(t *testing.T) { 383 InitMSP() 384 385 mockchannel := "mockchannel" 386 dir, err := ioutil.TempDir("/tmp", "createtestfromtx-") 387 if err != nil { 388 t.Fatalf("couldn't create temp dir") 389 } 390 defer os.RemoveAll(dir) // clean up 391 392 //this could be created by the create command 393 defer os.Remove(mockchannel + ".block") 394 395 file := filepath.Join(dir, mockchannel) 396 397 signer, err := common.GetDefaultSigner() 398 if err != nil { 399 t.Fatalf("Get default signer error: %v", err) 400 } 401 mockCF := &ChannelCmdFactory{ 402 BroadcastFactory: mockBroadcastClientFactory, 403 Signer: signer, 404 DeliverClient: &mockDeliverClient{}, 405 } 406 407 cmd := createCmd(mockCF) 408 AddFlags(cmd) 409 410 // Error case 0 411 args := []string{"-c", "", "-f", file, "-o", "localhost:7050"} 412 cmd.SetArgs(args) 413 err = cmd.Execute() 414 assert.Error(t, err, "Create command should have failed because channel ID is not specified") 415 assert.Contains(t, err.Error(), "Must supply channel ID") 416 417 // Error case 1 418 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 419 cmd.SetArgs(args) 420 err = cmd.Execute() 421 assert.Error(t, err, "Create command should have failed because tx file does not exist") 422 var msgExpr = regexp.MustCompile(`channel create configuration tx file not found.*no such file or directory`) 423 assert.True(t, msgExpr.MatchString(err.Error())) 424 425 // Success case: -f option is empty 426 args = []string{"-c", mockchannel, "-f", "", "-o", "localhost:7050"} 427 cmd.SetArgs(args) 428 err = cmd.Execute() 429 assert.NoError(t, err) 430 431 // Success case 432 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 433 cmd.SetArgs(args) 434 _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, mockchannel) 435 assert.NoError(t, err, "Couldn't create tx file") 436 err = cmd.Execute() 437 assert.NoError(t, err) 438 } 439 440 func TestCreateChainInvalidTx(t *testing.T) { 441 InitMSP() 442 443 mockchannel := "mockchannel" 444 445 dir, err := ioutil.TempDir("/tmp", "createinvaltest-") 446 if err != nil { 447 t.Fatalf("couldn't create temp dir") 448 } 449 450 defer os.RemoveAll(dir) // clean up 451 452 //this is created by create command 453 defer os.Remove(mockchannel + ".block") 454 455 file := filepath.Join(dir, mockchannel) 456 457 signer, err := common.GetDefaultSigner() 458 if err != nil { 459 t.Fatalf("Get default signer error: %v", err) 460 } 461 462 mockCF := &ChannelCmdFactory{ 463 BroadcastFactory: mockBroadcastClientFactory, 464 Signer: signer, 465 DeliverClient: &mockDeliverClient{}, 466 } 467 468 cmd := createCmd(mockCF) 469 470 AddFlags(cmd) 471 472 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 473 cmd.SetArgs(args) 474 475 //bad type CONFIG 476 if _, err = createTxFile(file, cb.HeaderType_CONFIG, mockchannel); err != nil { 477 t.Fatalf("couldn't create tx file") 478 } 479 480 defer os.Remove(file) 481 482 if err = cmd.Execute(); err == nil { 483 t.Errorf("expected error") 484 } else if _, ok := err.(InvalidCreateTx); !ok { 485 t.Errorf("invalid error") 486 } 487 488 //bad channel name - does not match one specified in command 489 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, "different_channel"); err != nil { 490 t.Fatalf("couldn't create tx file") 491 } 492 493 if err = cmd.Execute(); err == nil { 494 t.Errorf("expected error") 495 } else if _, ok := err.(InvalidCreateTx); !ok { 496 t.Errorf("invalid error") 497 } 498 499 //empty channel 500 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, ""); err != nil { 501 t.Fatalf("couldn't create tx file") 502 } 503 504 if err := cmd.Execute(); err == nil { 505 t.Errorf("expected error") 506 } else if _, ok := err.(InvalidCreateTx); !ok { 507 t.Errorf("invalid error") 508 } 509 } 510 511 func TestCreateChainNilCF(t *testing.T) { 512 InitMSP() 513 mockchannel := "mockchannel" 514 dir, err := ioutil.TempDir("/tmp", "createinvaltest-") 515 assert.NoError(t, err, "Couldn't create temp dir") 516 defer os.RemoveAll(dir) // clean up 517 518 //this is created by create command 519 defer os.Remove(mockchannel + ".block") 520 file := filepath.Join(dir, mockchannel) 521 522 // Error case: grpc error 523 cmd := createCmd(nil) 524 AddFlags(cmd) 525 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 526 cmd.SetArgs(args) 527 err = cmd.Execute() 528 assert.Error(t, err) 529 assert.Contains(t, err.Error(), "error: code = Unavailable desc = grpc: the connection is unavailable") 530 531 // Error case: invalid ordering service endpoint 532 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost"} 533 cmd.SetArgs(args) 534 err = cmd.Execute() 535 assert.Error(t, err) 536 assert.Contains(t, err.Error(), "Ordering service endpoint localhost is not valid or missing") 537 538 // Error case: invalid ca file 539 defer os.RemoveAll(dir) // clean up 540 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050", "--tls", "true", "--cafile", dir + "/ca.pem"} 541 cmd.SetArgs(args) 542 err = cmd.Execute() 543 assert.Error(t, err) 544 var msgExpr = regexp.MustCompile(`Error connecting.*no such file or directory.*`) 545 assert.True(t, msgExpr.MatchString(err.Error())) 546 } 547 548 func TestSanityCheckAndSignChannelCreateTx(t *testing.T) { 549 // Error case 1 550 env := &cb.Envelope{} 551 env.Payload = make([]byte, 10) 552 var err error 553 env, err = sanityCheckAndSignConfigTx(env) 554 assert.Error(t, err, "Error expected for nil payload") 555 assert.Contains(t, err.Error(), "bad payload") 556 557 // Error case 2 558 p := &cb.Payload{Header: nil} 559 data, err1 := proto.Marshal(p) 560 assert.NoError(t, err1) 561 env = &cb.Envelope{Payload: data} 562 env, err = sanityCheckAndSignConfigTx(env) 563 assert.Error(t, err, "Error expected for bad payload header") 564 assert.Contains(t, err.Error(), "bad header") 565 566 // Error case 3 567 bites := bytes.NewBufferString("foo").Bytes() 568 p = &cb.Payload{Header: &cb.Header{ChannelHeader: bites}} 569 data, err = proto.Marshal(p) 570 assert.NoError(t, err) 571 env = &cb.Envelope{Payload: data} 572 env, err = sanityCheckAndSignConfigTx(env) 573 assert.Error(t, err, "Error expected for bad channel header") 574 assert.Contains(t, err.Error(), "could not unmarshall channel header") 575 576 // Error case 4 577 mockchannel := "mockchannel" 578 cid := chainID 579 chainID = mockchannel 580 defer func() { 581 chainID = cid 582 }() 583 ch := &cb.ChannelHeader{Type: int32(cb.HeaderType_CONFIG_UPDATE), ChannelId: mockchannel} 584 data, err = proto.Marshal(ch) 585 assert.NoError(t, err) 586 p = &cb.Payload{Header: &cb.Header{ChannelHeader: data}, Data: bytes.NewBufferString("foo").Bytes()} 587 data, err = proto.Marshal(p) 588 assert.NoError(t, err) 589 env = &cb.Envelope{Payload: data} 590 env, err = sanityCheckAndSignConfigTx(env) 591 assert.Error(t, err, "Error expected for bad payload data") 592 assert.Contains(t, err.Error(), "Bad config update env") 593 }