From 5cc3579451b3760d52bfd0110bc22112603f22ce Mon Sep 17 00:00:00 2001 From: Sudesh Shetty Date: Tue, 4 Jul 2017 12:21:31 -0400 Subject: [PATCH] [FAB-5115] Added more test case coverage to channel Change-Id: Ib16dd7ebdadee94682b196cf024f1e3a38a07052 Signed-off-by: Sudesh Shetty --- pkg/fabric-client/channel/channel_test.go | 776 +++++++++++++++++++++- pkg/fabric-client/mocks/mockclient.go | 21 +- pkg/fabric-client/mocks/mockdata.go | 104 ++- pkg/fabric-client/mocks/mockuser.go | 5 + 4 files changed, 898 insertions(+), 8 deletions(-) diff --git a/pkg/fabric-client/channel/channel_test.go b/pkg/fabric-client/channel/channel_test.go index 7fd1d49511..dc3221a6ab 100644 --- a/pkg/fabric-client/channel/channel_test.go +++ b/pkg/fabric-client/channel/channel_test.go @@ -19,6 +19,14 @@ import ( mocks "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/mocks" peer "github.com/hyperledger/fabric-sdk-go/pkg/fabric-client/peer" + "io/ioutil" + "time" + + "strings" + + "github.com/golang/mock/gomock" + "github.com/hyperledger/fabric-sdk-go/api/apitxn/mocks" + "github.com/hyperledger/fabric/protos/common" pb "github.com/hyperledger/fabric/protos/peer" ) @@ -98,9 +106,718 @@ func TestQueryMethods(t *testing.T) { } +func TestChannelQueryBlock(t *testing.T) { + + channel, _ := setupTestChannel() + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + err := channel.AddPeer(&peer) + + _, err = channel.QueryBlock(1) + + if err != nil { + t.Fatal("Test channel query block failed,") + } + + _, err = channel.QueryBlockByHash([]byte("")) + + if err != nil { + t.Fatal("Test channel query block by hash failed,") + } + +} + +func TestChannelConfigs(t *testing.T) { + + client := mocks.NewMockClient() + user := mocks.NewMockUser("test") + cryptoSuite := &mocks.MockCryptoSuite{} + client.SaveUserToStateStore(user, true) + client.SetCryptoSuite(cryptoSuite) + + channel, _ := NewChannel("testChannel", client) + + if client.GetConfig().IsSecurityEnabled() != channel.IsSecurityEnabled() { + t.Fatal("Is Security Enabled flag is incorrect in channel") + } + + if client.GetConfig().TcertBatchSize() != channel.TCertBatchSize() { + t.Fatal("Tcert batch size is incorrect") + } + + channel.SetTCertBatchSize(22) + + if channel.TCertBatchSize() != 22 { + t.Fatal("TCert batch size update on channel is not working") + } + + if channel.IsReadonly() { + //TODO: Rightnow it is returning false always, need to revisit test once actual implementation is provided + t.Fatal("Is Readonly test failed") + } + + if channel.UpdateChannel() { + //TODO: Rightnow it is returning false always, need to revisit test once actual implementation is provided + t.Fatal("UpdateChannel test failed") + } + + if channel.QueryExtensionInterface().ClientContext() != client { + t.Fatal("Client context not matching with client") + } + + channel.SetMSPManager(nil) + +} + +func TestCreateTransactionProposal(t *testing.T) { + + channel, _ := setupTestChannel() + + tProposal, err := channel.CreateTransactionProposal("qscc", "testChannel", nil, true, nil) + + if err != nil { + t.Fatal("Create Transaction Proposal Failed", err) + } + + _, errx := channel.QueryExtensionInterface().ProposalBytes(tProposal) + + if errx != nil { + t.Fatal("Call to proposal bytes from channel extension failed") + } + +} + +func TestAddRemoveOrderer(t *testing.T) { + + //Setup channel + channel, _ := setupTestChannel() + + //Create mock orderer + orderer := mocks.NewMockOrderer("", nil) + + //Add an orderer + channel.AddOrderer(orderer) + + //Check if orderer is being added successfully + if len(channel.Orderers()) != 1 { + t.Fatal("Adding orderers to channel failed") + } + + //Remove the orderer now + channel.RemoveOrderer(orderer) + + //Check if list of orderers is empty now + if len(channel.Orderers()) != 0 { + t.Fatal("Removing orderers from channel failed") + } +} + +func TestAnchorAndRemovePeers(t *testing.T) { + //Setup channel + channel, _ := setupTestChannel() + + //Add a Peer + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + channel.AddPeer(&peer) + + //Remove and Test + channel.RemovePeer(&peer) + if len(channel.Peers()) != 0 { + t.Fatal("Remove Peer failed") + } + + //Add the Peer again + channel.AddPeer(&peer) + + channel.Initialize(nil) + if len(channel.AnchorPeers()) != 0 { + //Currently testing only for empty anchor list + t.Fatal("Anchor peer list is incorrect") + } +} + +func TestSendInstantiateProposal(t *testing.T) { + //Setup channel + client := mocks.NewMockClient() + user := mocks.NewMockUserWithMSPID("test", "1234") + cryptoSuite := &mocks.MockCryptoSuite{} + client.SaveUserToStateStore(user, true) + client.SetCryptoSuite(cryptoSuite) + client.SetUserContext(user) + channel, _ := NewChannel("testChannel", client) + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + proc := mock_apitxn.NewMockProposalProcessor(mockCtrl) + + tp := apitxn.TransactionProposal{SignedProposal: &pb.SignedProposal{}} + tpr := apitxn.TransactionProposalResult{Endorser: "example.com", Status: 99, Proposal: tp, ProposalResponse: nil} + + proc.EXPECT().ProcessTransactionProposal(gomock.Any()).Return(tpr, nil) + targets := []apitxn.ProposalProcessor{proc} + + //Add a Peer + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + channel.AddPeer(&peer) + + tresponse, str, err := channel.SendInstantiateProposal("", "testChannel", nil, "", + "", targets) + + if err == nil || err.Error() != "Missing 'chaincodeName' parameter" { + t.Fatal("Validation for chain code name parameter for send Instantiate Proposal failed") + } + + tresponse, str, err = channel.SendInstantiateProposal("qscc", "", nil, "", + "", targets) + + if err == nil || err.Error() != "Missing 'channelID' parameter" { + t.Fatal("Validation for chain id parameter for send Instantiate Proposal failed") + } + + tresponse, str, err = channel.SendInstantiateProposal("qscc", "1234", nil, "", + "", targets) + + if err == nil || err.Error() != "Missing 'chaincodePath' parameter" { + t.Fatal("Validation for chain code path for send Instantiate Proposal failed") + } + + tresponse, str, err = channel.SendInstantiateProposal("qscc", "1234", nil, "test", + "", targets) + + if err == nil || err.Error() != "Missing 'chaincodeVersion' parameter" { + t.Fatal("Validation for chain code version for send Instantiate Proposal failed") + } + + tresponse, str, err = channel.SendInstantiateProposal("qscc", "1234", nil, "test", + "1", targets) + + if err != nil || len(tresponse) == 0 || str == "" { + t.Fatal("Send Instantiate Proposal Test failed") + } + + tresponse, str, err = channel.SendInstantiateProposal("qscc", "1234", nil, "test", + "1", nil) + if err == nil || err.Error() != "Missing peer objects for instantiate CC proposal" { + t.Fatal("Missing peer objects validation is not working as expected") + } + +} + +func TestQueryInstantiatedChaincodes(t *testing.T) { + channel, _ := setupTestChannel() + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + err := channel.AddPeer(&peer) + + res, err := channel.QueryInstantiatedChaincodes() + + if err != nil || res == nil { + t.Fatal("Test QueryInstatiated chaincode failed") + } + +} + +func TestQueryTransaction(t *testing.T) { + channel, _ := setupTestChannel() + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + err := channel.AddPeer(&peer) + + res, err := channel.QueryTransaction("txid") + + if err != nil || res == nil { + t.Fatal("Test QueryTransaction failed") + } +} + +func TestQueryInfo(t *testing.T) { + channel, _ := setupTestChannel() + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + err := channel.AddPeer(&peer) + + res, err := channel.QueryInfo() + + if err != nil || res == nil { + t.Fatal("Test QueryInfo failed") + } +} + +func TestCreateTransaction(t *testing.T) { + channel, _ := setupTestChannel() + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + channel.AddPeer(&peer) + + //Test Empty proposal response scenario + _, err := channel.CreateTransaction([]*apitxn.TransactionProposalResponse{}) + + if err == nil || err.Error() != "At least one proposal response is necessary" { + t.Fatal("Proposal response was supposed to fail in Create Transaction, for empty proposal response scenario") + } + + //Test invalid proposal header scenario + + test := &apitxn.TransactionProposalResponse{ + TransactionProposalResult: apitxn.TransactionProposalResult{ + Endorser: "http://peer1.com", + Proposal: apitxn.TransactionProposal{ + TransactionID: "1234", + Proposal: &pb.Proposal{Header: []byte("TEST"), Extension: []byte(""), Payload: []byte("")}, + SignedProposal: &pb.SignedProposal{Signature: []byte(""), ProposalBytes: []byte("")}, + }, + ProposalResponse: &pb.ProposalResponse{Response: &pb.Response{Message: "success", Status: 99, Payload: []byte("")}}, + }, + } + + input := []*apitxn.TransactionProposalResponse{test} + + _, err = channel.CreateTransaction(input) + + if err == nil || err.Error() != "Could not unmarshal the proposal header" { + t.Fatal("Proposal response was supposed to fail in Create Transaction, invalid proposal header scenario") + } + + //Test invalid proposal payload scenario + test = &apitxn.TransactionProposalResponse{ + TransactionProposalResult: apitxn.TransactionProposalResult{ + Endorser: "http://peer1.com", + Proposal: apitxn.TransactionProposal{ + TransactionID: "1234", + Proposal: &pb.Proposal{Header: []byte(""), Extension: []byte(""), Payload: []byte("TEST")}, + SignedProposal: &pb.SignedProposal{Signature: []byte(""), ProposalBytes: []byte("")}, + }, + ProposalResponse: &pb.ProposalResponse{Response: &pb.Response{Message: "success", Status: 99, Payload: []byte("")}}, + }, + } + + input = []*apitxn.TransactionProposalResponse{test} + + _, err = channel.CreateTransaction(input) + if err == nil || err.Error() != "Could not unmarshal the proposal payload" { + t.Fatal("Proposal response was supposed to fail in Create Transaction, invalid proposal payload scenario") + } + + //Test proposal response + test = &apitxn.TransactionProposalResponse{ + TransactionProposalResult: apitxn.TransactionProposalResult{ + Endorser: "http://peer1.com", + Proposal: apitxn.TransactionProposal{ + Proposal: &pb.Proposal{Header: []byte(""), Extension: []byte(""), Payload: []byte("")}, + SignedProposal: &pb.SignedProposal{Signature: []byte(""), ProposalBytes: []byte("")}, TransactionID: "1234", + }, + ProposalResponse: &pb.ProposalResponse{Response: &pb.Response{Message: "success", Status: 99, Payload: []byte("")}}, + }, + } + + input = []*apitxn.TransactionProposalResponse{test} + _, err = channel.CreateTransaction(input) + + if err == nil || err.Error() != "Proposal response was not successful, error code 99, msg success" { + t.Fatal("Proposal response was supposed to fail in Create Transaction") + } + + //Test repeated field header nil scenario + + test = &apitxn.TransactionProposalResponse{ + TransactionProposalResult: apitxn.TransactionProposalResult{ + Endorser: "http://peer1.com", + Proposal: apitxn.TransactionProposal{ + Proposal: &pb.Proposal{Header: []byte(""), Extension: []byte(""), Payload: []byte("")}, + SignedProposal: &pb.SignedProposal{Signature: []byte(""), ProposalBytes: []byte("")}, TransactionID: "1234", + }, + ProposalResponse: &pb.ProposalResponse{Response: &pb.Response{Message: "success", Status: 200, Payload: []byte("")}}, + }, + } + + _, err = channel.CreateTransaction([]*apitxn.TransactionProposalResponse{test}) + + if err == nil || err.Error() != "repeated field endorsements has nil element" { + t.Fatal("Proposal response was supposed to fail in Create Transaction") + } + + //TODO: Need actual sample payload for success case + +} + +func TestLoadConfigUpdateEnvelope(t *testing.T) { + //Get Channel + channel, _ := setupTestChannel() + + //Read config file from test directory + fileLoc := "../../../test/fixtures/channel/mychanneltx.tx" + res, err := ioutil.ReadFile(fileLoc) + + //Pass config to LoadConfigUpdateEnvelope and test + err = channel.LoadConfigUpdateEnvelope(res) + + if err != nil { + t.Fatalf("LoadConfigUpdateEnvelope Test Failed with, Cause '%s'", err.Error()) + } + + err = channel.Initialize(res) + + if err == nil { + t.Fatalf("Initialize Negative Test Failed with, Cause '%s'", err.Error()) + } + + org1MSPID := "ORG1MSP" + org2MSPID := "ORG2MSP" + + builder := &mocks.MockConfigUpdateEnvelopeBuilder{} + + err = channel.LoadConfigUpdateEnvelope(builder.BuildBytes()) + + if err == nil { + t.Fatal("Expected error was : channel initialization error: unable to load MSPs from config") + } + + builder = &mocks.MockConfigUpdateEnvelopeBuilder{ + ChannelID: "mychannel", + MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ + ModPolicy: "Admins", + MSPNames: []string{ + org1MSPID, + org2MSPID, + }, + OrdererAddress: "localhost:7054", + RootCA: validRootCA, + }, + } + + //Create mock orderer + configBuilder := &mocks.MockConfigBlockBuilder{ + MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ + ModPolicy: "Admins", + MSPNames: []string{ + org1MSPID, + org2MSPID, + }, + OrdererAddress: "localhost:7054", + //RootCA: validRootCA, + }, + Index: 0, + LastConfigIndex: 0, + } + orderer := mocks.NewMockOrderer("", nil) + orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) + orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) + channel.AddOrderer(orderer) + + //Add a second orderer + configBuilder = &mocks.MockConfigBlockBuilder{ + MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ + ModPolicy: "Admins", + MSPNames: []string{ + org1MSPID, + org2MSPID, + }, + OrdererAddress: "localhost:7054", + //RootCA: validRootCA, + }, + Index: 0, + LastConfigIndex: 0, + } + orderer = mocks.NewMockOrderer("", nil) + orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) + orderer.(mocks.MockOrderer).EnqueueForSendDeliver(configBuilder.Build()) + channel.AddOrderer(orderer) + err = channel.Initialize(nil) + + if err == nil { + t.Fatal("Initialize on orderers config supposed to fail with 'could not decode pem bytes'") + } + +} + +func TestBroadcastEnvelope(t *testing.T) { + + //Setup channel + channel, _ := setupTestChannel() + + //Create mock orderer + orderer := mocks.NewMockOrderer("", nil) + + //Add an orderer + channel.AddOrderer(orderer) + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + channel.AddPeer(&peer) + + sigEnvelope := &api.SignedEnvelope{ + Signature: []byte(""), + Payload: []byte(""), + } + res, err := channel.QueryExtensionInterface().BroadcastEnvelope(sigEnvelope) + + if err != nil || res == nil { + t.Fatalf("Test Broadcast Envelope Failed, cause %s", err.Error()) + } + + channel.RemoveOrderer(orderer) + _, err = channel.QueryExtensionInterface().BroadcastEnvelope(sigEnvelope) + + if err == nil || err.Error() != "orderers not set" { + t.Fatal("orderers not set validation on broadcast envelope is not working as expected") + } + +} + +func TestSendTransaction(t *testing.T) { + + channel, _ := setupTestChannel() + + response, err := channel.SendTransaction(nil) + + //Expect orderer is nil error + if response != nil || err == nil || err.Error() != "orderers is nil" { + t.Fatal("Test SendTransaction failed, it was supposed to fail with 'orderers is nil' error") + } + + //Create mock orderer + orderer := mocks.NewMockOrderer("", nil) + + //Add an orderer + channel.AddOrderer(orderer) + + //Call Send Transaction with nil tx + response, err = channel.SendTransaction(nil) + + //Expect tx is nil error + if response != nil || err == nil || err.Error() != "Transaction is nil" { + t.Fatal("Test SendTransaction failed, it was supposed to fail with 'Transaction is nil' error") + } + + //Create tx with nil proposal + txn := apitxn.Transaction{ + Proposal: &apitxn.TransactionProposal{ + Proposal: nil, + }, + Transaction: &pb.Transaction{}, + } + + //Call Send Transaction with nil proposal + response, err = channel.SendTransaction(&txn) + + //Expect proposal is nil error + if response != nil || err == nil || err.Error() != "proposal is nil" { + t.Fatal("Test SendTransaction failed, it was supposed to fail with 'proposal is nil' error") + } + + //Create tx with improper proposal header + txn = apitxn.Transaction{ + Proposal: &apitxn.TransactionProposal{ + Proposal: &pb.Proposal{Header: []byte("TEST")}, + }, + Transaction: &pb.Transaction{}, + } + //Call Send Transaction + response, err = channel.SendTransaction(&txn) + + //Expect header unmarshal error + if response != nil || err == nil || err.Error() != "Could not unmarshal the proposal header" { + t.Fatal("Test SendTransaction failed, it was supposed to fail with 'Could not unmarshal the proposal header' error") + } + + //Create tx with proper proposal header + txn = apitxn.Transaction{ + Proposal: &apitxn.TransactionProposal{ + Proposal: &pb.Proposal{Header: []byte(""), Payload: []byte(""), Extension: []byte("")}, + }, + Transaction: &pb.Transaction{}, + } + + //Call Send Transaction + response, err = channel.SendTransaction(&txn) + + if response == nil || err != nil { + t.Fatalf("Test SendTransaction failed, reason : '%s'", err.Error()) + } +} + +func TestSendTransactionProposal(t *testing.T) { + + channel, _ := setupTestChannel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + proc := mock_apitxn.NewMockProposalProcessor(mockCtrl) + + tp := apitxn.TransactionProposal{ + SignedProposal: &pb.SignedProposal{}, + } + tpr := apitxn.TransactionProposalResult{Endorser: "example.com", Status: 99, Proposal: tp, ProposalResponse: nil} + proc.EXPECT().ProcessTransactionProposal(tp).Return(tpr, nil) + targets := []apitxn.ProposalProcessor{proc} + + result, err := channel.SendTransactionProposal(&apitxn.TransactionProposal{ + SignedProposal: &pb.SignedProposal{}, + }, 1, nil) + + if result != nil || err == nil || err.Error() != "peers and target peers is nil or empty" { + t.Fatal("Test SendTransactionProposal failed, validation on peer is nil is not working as expected") + } + + result, err = SendTransactionProposal(&apitxn.TransactionProposal{ + SignedProposal: &pb.SignedProposal{}, + }, 1, []apitxn.ProposalProcessor{}) + + if result != nil || err == nil || err.Error() != "Missing peer objects for sending transaction proposal" { + t.Fatal("Test SendTransactionProposal failed, validation on missing peer objects is not working") + } + + peer := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} + channel.AddPeer(&peer) + + err = channel.AddPeer(&peer) + + if err == nil || err.Error() != "Peer with URL http://peer1.com already exists" { + t.Fatal("Duplicate Peer check is not working as expected") + } + + result, err = channel.SendTransactionProposal(&apitxn.TransactionProposal{ + SignedProposal: nil, + }, 1, nil) + + if result != nil || err == nil || err.Error() != "signedProposal is nil" { + t.Fatal("Test SendTransactionProposal failed, validation on signedProposal is nil is not working as expected") + } + + result, err = SendTransactionProposal(&apitxn.TransactionProposal{ + SignedProposal: nil, + }, 1, nil) + + if result != nil || err == nil || err.Error() != "signedProposal is nil" { + t.Fatal("Test SendTransactionProposal failed, validation on signedProposal is nil is not working as expected") + } + + targetPeer := mocks.MockPeer{MockName: "Peer2", MockURL: "http://peer2.com", MockRoles: []string{}, MockCert: nil} + + channel.AddPeer(&targetPeer) + result, err = channel.SendTransactionProposal(&apitxn.TransactionProposal{ + SignedProposal: &pb.SignedProposal{}, + }, 1, targets) + + if result == nil || err != nil { + t.Fatalf("Test SendTransactionProposal failed, with error '%s'", err.Error()) + } + +} + +func TestBuildChannelHeader(t *testing.T) { + + header, err := BuildChannelHeader(common.HeaderType_CHAINCODE_PACKAGE, "test", "", 1, "1234", time.Time{}) + + if err != nil || header == nil { + t.Fatalf("Test Build Channel Header failed, cause : '%s'", err.Error()) + } + +} + +func TestSignPayload(t *testing.T) { + + client := mocks.NewMockInvalidClient() + user := mocks.NewMockUser("test") + cryptoSuite := &mocks.MockCryptoSuite{} + client.SaveUserToStateStore(user, true) + client.SetCryptoSuite(cryptoSuite) + channel, _ := NewChannel("testChannel", client) + + signedEnv, err := channel.QueryExtensionInterface().SignPayload([]byte("")) + + if err == nil { + t.Fatal("Test Sign Payload was supposed to fail") + } + + channel, _ = setupTestChannel() + signedEnv, err = channel.QueryExtensionInterface().SignPayload([]byte("")) + + if err != nil || signedEnv == nil { + t.Fatal("Test Sign Payload Failed") + } + +} + +func TestGenesisBlock(t *testing.T) { + var peers []api.Peer + channel, _ := setupTestChannel() + peer, _ := peer.NewPeer(testAddress, mocks.NewMockConfig()) + peers = append(peers, peer) + orderer := mocks.NewMockOrderer("", nil) + orderer.(mocks.MockOrderer).EnqueueForSendDeliver(mocks.NewSimpleMockError()) + nonce, _ := fc.GenerateRandomNonce() + txID, _ := fc.ComputeTxID(nonce, []byte("testID")) + + genesisBlockReq := &api.GenesisBlockRequest{ + TxID: txID, + Nonce: nonce, + } + + channel.AddOrderer(orderer) + + //Call get Genesis block + _, err := channel.GenesisBlock(genesisBlockReq) + + //Expecting error + if err == nil { + t.Fatal("GenesisBlock Test supposed to fail with error") + } + + //Remove existing orderer + channel.RemoveOrderer(orderer) + + //Create new orderer + orderer = mocks.NewMockOrderer("", nil) + + channel.AddOrderer(orderer) + + //Call get Genesis block + _, err = channel.GenesisBlock(genesisBlockReq) + + //It should fail with timeout + if err == nil || !strings.HasSuffix(err.Error(), "Timeout waiting for response from orderer") { + t.Fatal("GenesisBlock Test supposed to fail with timeout error") + } + + //Validation test + genesisBlockReq = &api.GenesisBlockRequest{} + _, err = channel.GenesisBlock(genesisBlockReq) + + if err == nil || err.Error() != "GenesisBlock - error: Missing txId input parameter with the required transaction identifier" { + t.Fatal("validation on missing txID input parameter is not working as expected") + } + + genesisBlockReq = &api.GenesisBlockRequest{ + TxID: txID, + } + _, err = channel.GenesisBlock(genesisBlockReq) + + if err == nil || err.Error() != "GenesisBlock - error: Missing nonce input parameter with the required single use number" { + t.Fatal("validation on missing nonce input parameter is not working as expected") + } + + channel.RemoveOrderer(orderer) + + genesisBlockReq = &api.GenesisBlockRequest{ + TxID: txID, + Nonce: nonce, + } + + _, err = channel.GenesisBlock(genesisBlockReq) + + if err == nil || err.Error() != "GenesisBlock - error: Missing orderer assigned to this channel for the GenesisBlock request" { + t.Fatal("validation on no ordererds on channel is not working as expected") + } + +} + func TestPrimaryPeer(t *testing.T) { channel, _ := setupTestChannel() + if channel.PrimaryPeer() != nil { + t.Fatal("Call to Primary peer on empty channel should always return nil") + } + // Channel had one peer peer1 := mocks.MockPeer{MockName: "Peer1", MockURL: "http://peer1.com", MockRoles: []string{}, MockCert: nil} err := channel.AddPeer(&peer1) @@ -160,6 +877,14 @@ func TestConcurrentPeers(t *testing.T) { if len(result) != numPeers { t.Error("SendTransactionProposal returned an unexpected amount of responses") } + + //Negative scenarios + _, err = channel.SendTransactionProposal(nil, 1, nil) + + if err == nil || err.Error() != "signedProposal is nil" { + t.Fatal("nil signedProposal validation check not working as expected") + } + } func TestConcurrentOrderers(t *testing.T) { @@ -318,6 +1043,10 @@ func TestChannelInitializeFromOrderer(t *testing.T) { if err != nil { t.Fatalf("channel Initialize failed : %v", err) } + if !channel.IsInitialized() { + t.Fatalf("channel Initialize failed : channel initialized flag not set") + } + mspManager := channel.MSPManager() if mspManager == nil { t.Fatalf("nil MSPManager on new channel") @@ -340,6 +1069,12 @@ func TestChannelInitializeFromOrderer(t *testing.T) { if identifier, _ := msp.GetIdentifier(); identifier != org2MSPID { t.Fatalf("Expecting MSP identifier to be %s but got %s", org2MSPID, identifier) } + + channel.SetMSPManager(nil) + if channel.MSPManager() != nil { + t.Fatal("Set MSPManager is not working as expected") + } + } func TestOrganizationUnits(t *testing.T) { @@ -348,6 +1083,7 @@ func TestOrganizationUnits(t *testing.T) { channel, _ := setupTestChannel() orgUnits, err := channel.OrganizationUnits() + if len(orgUnits) > 0 { t.Fatalf("Returned non configured organizational unit : %v", err) } @@ -402,7 +1138,7 @@ func isValueInList(value string, list []string) bool { return false } -func TestChannelInitializeFromUpdate(t *testing.T) { +func TestChannelInitialize(t *testing.T) { org1MSPID := "ORG1MSP" org2MSPID := "ORG2MSP" @@ -424,12 +1160,50 @@ func TestChannelInitializeFromUpdate(t *testing.T) { if err != nil { t.Fatalf("channel Initialize failed : %v", err) } + mspManager := channel.MSPManager() if mspManager == nil { t.Fatalf("nil MSPManager on new channel") } + } +//func TestChannelInitializeFromUpdate(t *testing.T) { +// org1MSPID := "ORG1MSP" +// org2MSPID := "ORG2MSP" +// +// client := mocks.NewMockClient() +// user := mocks.NewMockUser("test", ) +// cryptoSuite := &mocks.MockCryptoSuite{} +// client.SaveUserToStateStore(user, true) +// client.SetCryptoSuite(cryptoSuite) +// channel, _ := NewChannel("testChannel", client) +// +// builder := &mocks.MockConfigUpdateEnvelopeBuilder{ +// ChannelID: "mychannel", +// MockConfigGroupBuilder: mocks.MockConfigGroupBuilder{ +// ModPolicy: "Admins", +// MSPNames: []string{ +// org1MSPID, +// org2MSPID, +// }, +// OrdererAddress: "localhost:7054", +// RootCA: validRootCA, +// }, +// } +// +// err := channel.Initialize(builder.BuildBytes()) +// if err != nil { +// t.Fatalf("channel Initialize failed : %v", err) +// } +// +// mspManager := channel.MSPManager() +// if mspManager == nil { +// t.Fatalf("nil MSPManager on new channel") +// } +// +//} + func setupTestChannel() (api.Channel, error) { client := mocks.NewMockClient() user := mocks.NewMockUser("test") diff --git a/pkg/fabric-client/mocks/mockclient.go b/pkg/fabric-client/mocks/mockclient.go index 9eebd14880..81e45ed050 100644 --- a/pkg/fabric-client/mocks/mockclient.go +++ b/pkg/fabric-client/mocks/mockclient.go @@ -19,11 +19,12 @@ import ( // MockClient ... type MockClient struct { - channels map[string]api.Channel - cryptoSuite bccsp.BCCSP - stateStore api.KeyValueStore - userContext api.User - config api.Config + channels map[string]api.Channel + cryptoSuite bccsp.BCCSP + stateStore api.KeyValueStore + userContext api.User + config api.Config + errorScenario bool } // NewMockClient ... @@ -36,6 +37,13 @@ func NewMockClient() api.FabricClient { return c } +//NewMockInvalidClient : Returns new Mock FabricClient with error flag on used to test invalid scenarios +func NewMockInvalidClient() api.FabricClient { + channels := make(map[string]api.Channel) + c := &MockClient{channels: channels, cryptoSuite: nil, stateStore: nil, userContext: nil, config: NewMockConfig(), errorScenario: true} + return c +} + // NewChannel ... func (c *MockClient) NewChannel(name string) (api.Channel, error) { return nil, nil @@ -84,6 +92,9 @@ func (c *MockClient) SaveUserToStateStore(user api.User, skipPersistence bool) e // LoadUserFromStateStore ... func (c *MockClient) LoadUserFromStateStore(name string) (api.User, error) { + if c.errorScenario { + return nil, fmt.Errorf("just to test error scenario") + } return NewMockUser("test"), nil } diff --git a/pkg/fabric-client/mocks/mockdata.go b/pkg/fabric-client/mocks/mockdata.go index 52bc6c318c..c86e4748cf 100644 --- a/pkg/fabric-client/mocks/mockdata.go +++ b/pkg/fabric-client/mocks/mockdata.go @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package mocks import ( + "fmt" + "github.com/golang/protobuf/proto" fabric_config "github.com/hyperledger/fabric/common/config" ledger_util "github.com/hyperledger/fabric/core/ledger/util" @@ -22,9 +24,22 @@ func NewSimpleMockBlock() *common.Block { Data: &common.BlockData{ Data: [][]byte{[]byte("test")}, }, + Header: &common.BlockHeader{ + DataHash: []byte(""), + PreviousHash: []byte(""), + Number: 1, + }, + Metadata: &common.BlockMetadata{ + Metadata: [][]byte{[]byte("test")}, + }, } } +// NewSimpleMockError returns a error +func NewSimpleMockError() error { + return fmt.Errorf("Test Error") +} + // MockConfigGroupBuilder is used to build a mock ConfigGroup type MockConfigGroupBuilder struct { Version uint64 @@ -32,6 +47,7 @@ type MockConfigGroupBuilder struct { OrdererAddress string MSPNames []string RootCA string + Groups map[string]*common.ConfigGroup } // MockConfigBlockBuilder is used to build a mock Chain configuration block @@ -184,8 +200,13 @@ func (b *MockConfigGroupBuilder) buildOrdererGroup() *common.ConfigGroup { "Admins": b.buildBasicConfigPolicy(), }, Values: map[string]*common.ConfigValue{ - fabric_config.BatchSizeKey: b.buildBatchSizeConfigValue(), - // TODO: More + fabric_config.BatchSizeKey: b.buildBatchSizeConfigValue(), + fabric_config.AnchorPeersKey: b.buildAnchorPeerConfigValue(), + fabric_config.ConsensusTypeKey: b.buildConsensusTypeConfigValue(), + fabric_config.BatchTimeoutKey: b.buildBatchTimeoutConfigValue(), + fabric_config.ChannelRestrictionsKey: b.buildChannelRestrictionsConfigValue(), + fabric_config.HashingAlgorithmKey: b.buildHashingAlgorithmConfigValue(), + fabric_config.BlockDataHashingStructureKey: b.buildBlockDataHashingStructureConfigValue(), }, Version: b.Version, ModPolicy: b.ModPolicy, @@ -223,6 +244,48 @@ func (b *MockConfigGroupBuilder) buildBatchSizeConfigValue() *common.ConfigValue Value: marshalOrPanic(b.buildBatchSize())} } +func (b *MockConfigGroupBuilder) buildAnchorPeerConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildAnchorPeer())} +} + +func (b *MockConfigGroupBuilder) buildConsensusTypeConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildConsensusType())} +} + +func (b *MockConfigGroupBuilder) buildBatchTimeoutConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildBatchTimeout())} +} + +func (b *MockConfigGroupBuilder) buildChannelRestrictionsConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildChannelRestrictions())} +} + +func (b *MockConfigGroupBuilder) buildHashingAlgorithmConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildHashingAlgorithm())} +} + +func (b *MockConfigGroupBuilder) buildBlockDataHashingStructureConfigValue() *common.ConfigValue { + return &common.ConfigValue{ + Version: b.Version, + ModPolicy: b.ModPolicy, + Value: marshalOrPanic(b.buildBlockDataHashingStructure())} +} + func (b *MockConfigGroupBuilder) buildBatchSize() *ab.BatchSize { return &ab.BatchSize{ MaxMessageCount: 10, @@ -231,6 +294,43 @@ func (b *MockConfigGroupBuilder) buildBatchSize() *ab.BatchSize { } } +func (b *MockConfigGroupBuilder) buildAnchorPeer() *pp.AnchorPeers { + ap := pp.AnchorPeer{Host: "sample-host", Port: 22} + return &pp.AnchorPeers{ + AnchorPeers: []*pp.AnchorPeer{&ap}, + } +} + +func (b *MockConfigGroupBuilder) buildConsensusType() *ab.ConsensusType { + return &ab.ConsensusType{ + Type: "sample-Consensus-Type", + } +} + +func (b *MockConfigGroupBuilder) buildBatchTimeout() *ab.BatchTimeout { + return &ab.BatchTimeout{ + Timeout: "123", + } +} + +func (b *MockConfigGroupBuilder) buildChannelRestrictions() *ab.ChannelRestrictions { + return &ab.ChannelRestrictions{ + MaxCount: 200, + } +} + +func (b *MockConfigGroupBuilder) buildHashingAlgorithm() *common.HashingAlgorithm { + return &common.HashingAlgorithm{ + Name: "SHA2", + } +} + +func (b *MockConfigGroupBuilder) buildBlockDataHashingStructure() *common.BlockDataHashingStructure { + return &common.BlockDataHashingStructure{ + Width: 64, + } +} + func (b *MockConfigGroupBuilder) buildMSPConfig(name string) *mb.MSPConfig { return &mb.MSPConfig{ Type: 0, diff --git a/pkg/fabric-client/mocks/mockuser.go b/pkg/fabric-client/mocks/mockuser.go index b759ca109b..c794368811 100644 --- a/pkg/fabric-client/mocks/mockuser.go +++ b/pkg/fabric-client/mocks/mockuser.go @@ -30,6 +30,11 @@ func NewMockUser(name string) api.User { return &MockUser{name: name} } +//NewMockUserWithMSPID to return mock user with MSP ids +func NewMockUserWithMSPID(name string, mspid string) api.User { + return &MockUser{name: name, mspID: mspid} +} + // GetName ... /** * Get the user name.