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  }