737 lines
25 KiB
Go
737 lines
25 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package peer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric-protos-go/orderer"
|
|
"github.com/hyperledger/fabric-protos-go/peer"
|
|
"github.com/hyperledger/fabric/common/deliver"
|
|
"github.com/hyperledger/fabric/common/ledger/blockledger"
|
|
"github.com/hyperledger/fabric/common/metrics/disabled"
|
|
"github.com/hyperledger/fabric/common/policies"
|
|
"github.com/hyperledger/fabric/common/util"
|
|
"github.com/hyperledger/fabric/core/ledger"
|
|
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
|
|
fake "github.com/hyperledger/fabric/core/peer/mock"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc/metadata"
|
|
peer2 "google.golang.org/grpc/peer"
|
|
)
|
|
|
|
// defaultPolicyCheckerProvider policy checker provider used by default,
|
|
// generates policy checker which always accepts regardless of arguments
|
|
// passed in
|
|
var defaultPolicyCheckerProvider = func(_ string) deliver.PolicyCheckerFunc {
|
|
return func(_ *common.Envelope, _ string) error {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
//go:generate counterfeiter -o mock/peer_ledger.go -fake-name PeerLedger . peerLedger
|
|
|
|
type peerLedger interface {
|
|
ledger.PeerLedger
|
|
}
|
|
|
|
//go:generate counterfeiter -o mock/identity_deserializer_manager.go -fake-name IdentityDeserializerManager . identityDeserializerManager
|
|
|
|
type identityDeserializerManager interface {
|
|
IdentityDeserializerManager
|
|
}
|
|
|
|
//go:generate counterfeiter -o mock/collection_policy_checker.go -fake-name CollectionPolicyChecker . collectionPolicyChecker
|
|
|
|
type collectionPolicyChecker interface {
|
|
CollectionPolicyChecker
|
|
}
|
|
|
|
// mockIterator mock structure implementing
|
|
// the blockledger.Iterator interface
|
|
type mockIterator struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockIterator) Next() (*common.Block, common.Status) {
|
|
args := m.Called()
|
|
return args.Get(0).(*common.Block), args.Get(1).(common.Status)
|
|
}
|
|
|
|
func (m *mockIterator) ReadyChan() <-chan struct{} {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (m *mockIterator) Close() {
|
|
}
|
|
|
|
// mockReader mock structure implementing
|
|
// the blockledger.Reader interface
|
|
type mockReader struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockReader) Iterator(startType *orderer.SeekPosition) (blockledger.Iterator, uint64) {
|
|
args := m.Called(startType)
|
|
return args.Get(0).(blockledger.Iterator), args.Get(1).(uint64)
|
|
}
|
|
|
|
func (m *mockReader) Height() uint64 {
|
|
args := m.Called()
|
|
return args.Get(0).(uint64)
|
|
}
|
|
|
|
func (m *mockReader) RetrieveBlockByNumber(blockNum uint64) (*common.Block, error) {
|
|
args := m.Called()
|
|
return args.Get(0).(*common.Block), args.Error(1)
|
|
}
|
|
|
|
// mockChainSupport
|
|
type mockChainSupport struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockChainSupport) Sequence() uint64 {
|
|
return m.Called().Get(0).(uint64)
|
|
}
|
|
|
|
func (m *mockChainSupport) Ledger() ledger.PeerLedger {
|
|
return m.Called().Get(0).(ledger.PeerLedger)
|
|
}
|
|
|
|
func (m *mockChainSupport) PolicyManager() policies.Manager {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (m *mockChainSupport) Reader() blockledger.Reader {
|
|
return m.Called().Get(0).(blockledger.Reader)
|
|
}
|
|
|
|
func (*mockChainSupport) Errored() <-chan struct{} {
|
|
return make(chan struct{})
|
|
}
|
|
|
|
// mockChainManager mock implementation of the ChainManager interface
|
|
type mockChainManager struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockChainManager) GetChain(channelID string) deliver.Chain {
|
|
args := m.Called(channelID)
|
|
return args.Get(0).(deliver.Chain)
|
|
}
|
|
|
|
// mockDeliverServer mock implementation of the Deliver_DeliverServer
|
|
type mockDeliverServer struct {
|
|
mock.Mock
|
|
}
|
|
|
|
func (m *mockDeliverServer) Context() context.Context {
|
|
return m.Called().Get(0).(context.Context)
|
|
}
|
|
|
|
func (m *mockDeliverServer) Recv() (*common.Envelope, error) {
|
|
args := m.Called()
|
|
if args.Get(0) == nil {
|
|
return nil, args.Error(1)
|
|
}
|
|
return args.Get(0).(*common.Envelope), args.Error(1)
|
|
}
|
|
|
|
func (m *mockDeliverServer) Send(response *peer.DeliverResponse) error {
|
|
args := m.Called(response)
|
|
return args.Error(0)
|
|
}
|
|
|
|
func (*mockDeliverServer) RecvMsg(m interface{}) error {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (*mockDeliverServer) SendHeader(metadata.MD) error {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (*mockDeliverServer) SendMsg(m interface{}) error {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (*mockDeliverServer) SetHeader(metadata.MD) error {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (*mockDeliverServer) SetTrailer(metadata.MD) {
|
|
panic("implement me")
|
|
}
|
|
|
|
type testConfig struct {
|
|
channelID string
|
|
eventName string
|
|
chaincodeName string
|
|
txID string
|
|
payload *common.Payload
|
|
*require.Assertions
|
|
}
|
|
|
|
type testCase struct {
|
|
name string
|
|
prepare func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer)
|
|
}
|
|
|
|
func TestFilteredBlockResponseSenderIsFiltered(t *testing.T) {
|
|
var fbrs interface{} = &filteredBlockResponseSender{}
|
|
filtered, ok := fbrs.(deliver.Filtered)
|
|
require.True(t, ok, "should be filtered")
|
|
require.True(t, filtered.IsFiltered(), "should return true from IsFiltered")
|
|
}
|
|
|
|
func TestEventsServer_DeliverFiltered(t *testing.T) {
|
|
tests := []testCase{
|
|
{
|
|
name: "Testing deliver of the filtered block events",
|
|
prepare: func(config testConfig) func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
return func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
wg.Add(2)
|
|
p := &peer2.Peer{}
|
|
chaincodeActionPayload, err := createChaincodeAction(config.chaincodeName, config.eventName, config.txID)
|
|
config.NoError(err)
|
|
|
|
chainManager := createDefaultSupportMamangerMock(config, chaincodeActionPayload, nil)
|
|
// setup mock deliver server
|
|
deliverServer := &mockDeliverServer{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
|
|
deliverServer.On("Recv").Return(&common.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(config.payload),
|
|
}, nil).Run(func(_ mock.Arguments) {
|
|
// once we are getting new message we need to mock
|
|
// Recv call to get io.EOF to stop the looping for
|
|
// next message and we can assert for the DeliverResponse
|
|
// value we are getting from the deliver server
|
|
deliverServer.Mock = mock.Mock{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{}, io.EOF)
|
|
deliverServer.On("Send", mock.Anything).Run(func(args mock.Arguments) {
|
|
defer wg.Done()
|
|
response := args.Get(0).(*peer.DeliverResponse)
|
|
switch response.Type.(type) {
|
|
case *peer.DeliverResponse_Status:
|
|
config.Equal(common.Status_SUCCESS, response.GetStatus())
|
|
case *peer.DeliverResponse_FilteredBlock:
|
|
block := response.GetFilteredBlock()
|
|
config.Equal(uint64(0), block.Number)
|
|
config.Equal(config.channelID, block.ChannelId)
|
|
config.Equal(1, len(block.FilteredTransactions))
|
|
tx := block.FilteredTransactions[0]
|
|
config.Equal(config.txID, tx.Txid)
|
|
config.Equal(peer.TxValidationCode_VALID, tx.TxValidationCode)
|
|
config.Equal(common.HeaderType_ENDORSER_TRANSACTION, tx.Type)
|
|
transactionActions := tx.GetTransactionActions()
|
|
config.NotNil(transactionActions)
|
|
chaincodeActions := transactionActions.ChaincodeActions
|
|
config.Equal(1, len(chaincodeActions))
|
|
config.Equal(config.eventName, chaincodeActions[0].ChaincodeEvent.EventName)
|
|
config.Equal(config.txID, chaincodeActions[0].ChaincodeEvent.TxId)
|
|
config.Equal(config.chaincodeName, chaincodeActions[0].ChaincodeEvent.ChaincodeId)
|
|
default:
|
|
config.FailNow("Unexpected response type")
|
|
}
|
|
}).Return(nil)
|
|
})
|
|
|
|
return chainManager, deliverServer
|
|
}
|
|
}(testConfig{
|
|
channelID: "testChannelID",
|
|
eventName: "testEvent",
|
|
chaincodeName: "mycc",
|
|
txID: "testID",
|
|
payload: &common.Payload{
|
|
Header: &common.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{
|
|
ChannelId: "testChannelID",
|
|
Timestamp: util.CreateUtcTimestamp(),
|
|
}),
|
|
SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{}),
|
|
},
|
|
Data: protoutil.MarshalOrPanic(&orderer.SeekInfo{
|
|
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
|
|
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{Newest: &orderer.SeekNewest{}}},
|
|
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
|
|
}),
|
|
},
|
|
Assertions: require.New(t),
|
|
}),
|
|
},
|
|
{
|
|
name: "Testing deliver of the filtered block events with nil chaincode action payload",
|
|
prepare: func(config testConfig) func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
return func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
wg.Add(2)
|
|
p := &peer2.Peer{}
|
|
chainManager := createDefaultSupportMamangerMock(config, nil, nil)
|
|
|
|
// setup mock deliver server
|
|
deliverServer := &mockDeliverServer{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
|
|
deliverServer.On("Recv").Return(&common.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(config.payload),
|
|
}, nil).Run(func(_ mock.Arguments) {
|
|
// once we are getting new message we need to mock
|
|
// Recv call to get io.EOF to stop the looping for
|
|
// next message and we can assert for the DeliverResponse
|
|
// value we are getting from the deliver server
|
|
deliverServer.Mock = mock.Mock{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{}, io.EOF)
|
|
deliverServer.On("Send", mock.Anything).Run(func(args mock.Arguments) {
|
|
defer wg.Done()
|
|
response := args.Get(0).(*peer.DeliverResponse)
|
|
switch response.Type.(type) {
|
|
case *peer.DeliverResponse_Status:
|
|
config.Equal(common.Status_SUCCESS, response.GetStatus())
|
|
case *peer.DeliverResponse_FilteredBlock:
|
|
block := response.GetFilteredBlock()
|
|
config.Equal(uint64(0), block.Number)
|
|
config.Equal(config.channelID, block.ChannelId)
|
|
config.Equal(1, len(block.FilteredTransactions))
|
|
tx := block.FilteredTransactions[0]
|
|
config.Equal(config.txID, tx.Txid)
|
|
config.Equal(peer.TxValidationCode_VALID, tx.TxValidationCode)
|
|
config.Equal(common.HeaderType_ENDORSER_TRANSACTION, tx.Type)
|
|
transactionActions := tx.GetTransactionActions()
|
|
config.NotNil(transactionActions)
|
|
chaincodeActions := transactionActions.ChaincodeActions
|
|
// we expecting to get zero chaincode action,
|
|
// since provided nil payload
|
|
config.Equal(0, len(chaincodeActions))
|
|
default:
|
|
config.FailNow("Unexpected response type")
|
|
}
|
|
}).Return(nil)
|
|
})
|
|
|
|
return chainManager, deliverServer
|
|
}
|
|
}(testConfig{
|
|
channelID: "testChannelID",
|
|
eventName: "testEvent",
|
|
chaincodeName: "mycc",
|
|
txID: "testID",
|
|
payload: &common.Payload{
|
|
Header: &common.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{
|
|
ChannelId: "testChannelID",
|
|
Timestamp: util.CreateUtcTimestamp(),
|
|
}),
|
|
SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{}),
|
|
},
|
|
Data: protoutil.MarshalOrPanic(&orderer.SeekInfo{
|
|
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
|
|
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{Newest: &orderer.SeekNewest{}}},
|
|
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
|
|
}),
|
|
},
|
|
Assertions: require.New(t),
|
|
}),
|
|
},
|
|
{
|
|
name: "Testing deliver of the filtered block events with nil payload header",
|
|
prepare: func(config testConfig) func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
return func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
wg.Add(1)
|
|
p := &peer2.Peer{}
|
|
chainManager := createDefaultSupportMamangerMock(config, nil, nil)
|
|
|
|
// setup mock deliver server
|
|
deliverServer := &mockDeliverServer{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
|
|
deliverServer.On("Recv").Return(&common.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(config.payload),
|
|
}, nil).Run(func(_ mock.Arguments) {
|
|
// once we are getting new message we need to mock
|
|
// Recv call to get io.EOF to stop the looping for
|
|
// next message and we can assert for the DeliverResponse
|
|
// value we are getting from the deliver server
|
|
deliverServer.Mock = mock.Mock{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{}, io.EOF)
|
|
deliverServer.On("Send", mock.Anything).Run(func(args mock.Arguments) {
|
|
defer wg.Done()
|
|
response := args.Get(0).(*peer.DeliverResponse)
|
|
switch response.Type.(type) {
|
|
case *peer.DeliverResponse_Status:
|
|
config.Equal(common.Status_BAD_REQUEST, response.GetStatus())
|
|
case *peer.DeliverResponse_FilteredBlock:
|
|
config.FailNow("Unexpected response type")
|
|
default:
|
|
config.FailNow("Unexpected response type")
|
|
}
|
|
}).Return(nil)
|
|
})
|
|
|
|
return chainManager, deliverServer
|
|
}
|
|
}(testConfig{
|
|
channelID: "testChannelID",
|
|
eventName: "testEvent",
|
|
chaincodeName: "mycc",
|
|
txID: "testID",
|
|
payload: &common.Payload{
|
|
Header: nil,
|
|
Data: protoutil.MarshalOrPanic(&orderer.SeekInfo{
|
|
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
|
|
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{Newest: &orderer.SeekNewest{}}},
|
|
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
|
|
}),
|
|
},
|
|
Assertions: require.New(t),
|
|
}),
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
wg := &sync.WaitGroup{}
|
|
chainManager, deliverServer := test.prepare(wg)
|
|
|
|
metrics := deliver.NewMetrics(&disabled.Provider{})
|
|
server := &DeliverServer{
|
|
DeliverHandler: deliver.NewHandler(chainManager, time.Second, false, metrics, false),
|
|
PolicyCheckerProvider: defaultPolicyCheckerProvider,
|
|
}
|
|
|
|
err := server.DeliverFiltered(deliverServer)
|
|
wg.Wait()
|
|
// no error expected
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEventsServer_DeliverWithPrivateData(t *testing.T) {
|
|
fakeDeserializerMgr := &fake.IdentityDeserializerManager{}
|
|
fakeDeserializerMgr.DeserializerReturns(nil, nil)
|
|
fakeCollPolicyChecker := &fake.CollectionPolicyChecker{}
|
|
fakeCollPolicyChecker.CheckCollectionPolicyReturns(true, nil)
|
|
tests := []testCase{
|
|
{
|
|
name: "Testing deliver block with private data events",
|
|
prepare: func(config testConfig) func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
return func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
wg.Add(2)
|
|
p := &peer2.Peer{}
|
|
chaincodeActionPayload, err := createChaincodeAction(config.chaincodeName, config.eventName, config.txID)
|
|
config.NoError(err)
|
|
|
|
pvtData := []*ledger.TxPvtData{
|
|
produceSamplePvtdataOrPanic(0, []string{"ns-0:coll-0", "ns-2:coll-20", "ns-2:coll-21"}),
|
|
}
|
|
chainManager := createDefaultSupportMamangerMock(config, chaincodeActionPayload, pvtData)
|
|
|
|
deliverServer := &mockDeliverServer{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(config.payload),
|
|
}, nil).Run(func(_ mock.Arguments) {
|
|
// mock Recv calls to get io.EOF to stop the looping for next message
|
|
deliverServer.Mock = mock.Mock{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{}, io.EOF)
|
|
deliverServer.On("Send", mock.Anything).Run(func(args mock.Arguments) {
|
|
defer wg.Done()
|
|
response := args.Get(0).(*peer.DeliverResponse)
|
|
switch response.Type.(type) {
|
|
case *peer.DeliverResponse_Status:
|
|
config.Equal(common.Status_SUCCESS, response.GetStatus())
|
|
case *peer.DeliverResponse_BlockAndPrivateData:
|
|
blockAndPvtData := response.GetBlockAndPrivateData()
|
|
block := blockAndPvtData.Block
|
|
config.Equal(uint64(0), block.Header.Number)
|
|
config.Equal(1, len(blockAndPvtData.PrivateDataMap))
|
|
config.NotNil(blockAndPvtData.PrivateDataMap[uint64(0)])
|
|
txPvtRwset := blockAndPvtData.PrivateDataMap[uint64(0)]
|
|
// expect to have 2 NsPvtRwset (i.e., 2 namespaces)
|
|
config.Equal(2, len(txPvtRwset.NsPvtRwset))
|
|
// check namespace because the index may be out of order
|
|
for _, nsPvtRwset := range txPvtRwset.NsPvtRwset {
|
|
switch nsPvtRwset.Namespace {
|
|
case "ns-0":
|
|
config.Equal(1, len(nsPvtRwset.CollectionPvtRwset))
|
|
config.Equal("coll-0", nsPvtRwset.CollectionPvtRwset[0].CollectionName)
|
|
case "ns-2":
|
|
config.Equal(2, len(nsPvtRwset.CollectionPvtRwset))
|
|
config.Equal("coll-20", nsPvtRwset.CollectionPvtRwset[0].CollectionName)
|
|
config.Equal("coll-21", nsPvtRwset.CollectionPvtRwset[1].CollectionName)
|
|
default:
|
|
config.FailNow("Wrong namespace " + nsPvtRwset.Namespace)
|
|
}
|
|
}
|
|
default:
|
|
config.FailNow("Unexpected response type")
|
|
}
|
|
}).Return(nil)
|
|
})
|
|
|
|
return chainManager, deliverServer
|
|
}
|
|
}(testConfig{
|
|
channelID: "testChannelID",
|
|
eventName: "testEvent",
|
|
chaincodeName: "mycc",
|
|
txID: "testID",
|
|
payload: &common.Payload{
|
|
Header: &common.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{
|
|
ChannelId: "testChannelID",
|
|
Timestamp: util.CreateUtcTimestamp(),
|
|
}),
|
|
SignatureHeader: protoutil.MarshalOrPanic(&common.SignatureHeader{}),
|
|
},
|
|
Data: protoutil.MarshalOrPanic(&orderer.SeekInfo{
|
|
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
|
|
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{Newest: &orderer.SeekNewest{}}},
|
|
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
|
|
}),
|
|
},
|
|
Assertions: require.New(t),
|
|
}),
|
|
},
|
|
{
|
|
name: "Testing deliver of block with private data events with nil header",
|
|
prepare: func(config testConfig) func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
return func(wg *sync.WaitGroup) (deliver.ChainManager, peer.Deliver_DeliverServer) {
|
|
wg.Add(1)
|
|
p := &peer2.Peer{}
|
|
chainManager := createDefaultSupportMamangerMock(config, nil, nil)
|
|
|
|
deliverServer := &mockDeliverServer{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(config.payload),
|
|
}, nil).Run(func(_ mock.Arguments) {
|
|
// mock Recv calls to get io.EOF to stop the looping for next message
|
|
deliverServer.Mock = mock.Mock{}
|
|
deliverServer.On("Context").Return(peer2.NewContext(context.TODO(), p))
|
|
deliverServer.On("Recv").Return(&common.Envelope{}, io.EOF)
|
|
deliverServer.On("Send", mock.Anything).Run(func(args mock.Arguments) {
|
|
defer wg.Done()
|
|
response := args.Get(0).(*peer.DeliverResponse)
|
|
switch response.Type.(type) {
|
|
case *peer.DeliverResponse_Status:
|
|
config.Equal(common.Status_BAD_REQUEST, response.GetStatus())
|
|
case *peer.DeliverResponse_BlockAndPrivateData:
|
|
config.FailNow("Unexpected response type")
|
|
default:
|
|
config.FailNow("Unexpected response type")
|
|
}
|
|
}).Return(nil)
|
|
})
|
|
|
|
return chainManager, deliverServer
|
|
}
|
|
}(testConfig{
|
|
channelID: "testChannelID",
|
|
eventName: "testEvent",
|
|
chaincodeName: "mycc",
|
|
txID: "testID",
|
|
payload: &common.Payload{
|
|
Header: nil,
|
|
Data: protoutil.MarshalOrPanic(&orderer.SeekInfo{
|
|
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
|
|
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Newest{Newest: &orderer.SeekNewest{}}},
|
|
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
|
|
}),
|
|
},
|
|
Assertions: require.New(t),
|
|
}),
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
wg := &sync.WaitGroup{}
|
|
chainManager, deliverServer := test.prepare(wg)
|
|
|
|
metrics := deliver.NewMetrics(&disabled.Provider{})
|
|
handler := deliver.NewHandler(chainManager, time.Second, false, metrics, false)
|
|
server := &DeliverServer{
|
|
DeliverHandler: handler,
|
|
PolicyCheckerProvider: defaultPolicyCheckerProvider,
|
|
CollectionPolicyChecker: fakeCollPolicyChecker,
|
|
IdentityDeserializerMgr: fakeDeserializerMgr,
|
|
}
|
|
|
|
err := server.DeliverWithPrivateData(deliverServer)
|
|
wg.Wait()
|
|
// no error expected
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func createDefaultSupportMamangerMock(config testConfig, chaincodeActionPayload *peer.ChaincodeActionPayload, pvtData []*ledger.TxPvtData) *mockChainManager {
|
|
chainManager := &mockChainManager{}
|
|
iter := &mockIterator{}
|
|
reader := &mockReader{}
|
|
chain := &mockChainSupport{}
|
|
ldgr := &fake.PeerLedger{}
|
|
|
|
payload, err := createEndorsement(config.channelID, config.txID, chaincodeActionPayload)
|
|
config.NoError(err)
|
|
|
|
payloadBytes, err := proto.Marshal(payload)
|
|
config.NoError(err)
|
|
|
|
block, err := createTestBlock([]*common.Envelope{{
|
|
Payload: payloadBytes,
|
|
Signature: []byte{},
|
|
}})
|
|
config.NoError(err)
|
|
|
|
iter.On("Next").Return(block, common.Status_SUCCESS)
|
|
reader.On("Iterator", mock.Anything).Return(iter, uint64(1))
|
|
reader.On("Height").Return(uint64(1))
|
|
chain.On("Sequence").Return(uint64(0))
|
|
chain.On("Reader").Return(reader)
|
|
chain.On("Ledger").Return(ldgr)
|
|
chainManager.On("GetChain", config.channelID).Return(chain, true)
|
|
|
|
ldgr.GetPvtDataByNumReturns(pvtData, nil)
|
|
|
|
return chainManager
|
|
}
|
|
|
|
func createEndorsement(channelID string, txID string, chaincodeActionPayload *peer.ChaincodeActionPayload) (*common.Payload, error) {
|
|
var chActionBytes []byte
|
|
var err error
|
|
if chaincodeActionPayload != nil {
|
|
chActionBytes, err = proto.Marshal(chaincodeActionPayload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// the transaction
|
|
txBytes, err := proto.Marshal(&peer.Transaction{
|
|
Actions: []*peer.TransactionAction{
|
|
{
|
|
Payload: chActionBytes,
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// channel header
|
|
chdrBytes, err := proto.Marshal(&common.ChannelHeader{
|
|
ChannelId: channelID,
|
|
TxId: txID,
|
|
Type: int32(common.HeaderType_ENDORSER_TRANSACTION),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// the payload
|
|
payload := &common.Payload{
|
|
Header: &common.Header{
|
|
ChannelHeader: chdrBytes,
|
|
},
|
|
Data: txBytes,
|
|
}
|
|
return payload, nil
|
|
}
|
|
|
|
func createChaincodeAction(chaincodeName string, eventName string, txID string) (*peer.ChaincodeActionPayload, error) {
|
|
// chaincode events
|
|
eventsBytes, err := proto.Marshal(&peer.ChaincodeEvent{
|
|
ChaincodeId: chaincodeName,
|
|
EventName: eventName,
|
|
TxId: txID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// chaincode action
|
|
actionBytes, err := proto.Marshal(&peer.ChaincodeAction{
|
|
ChaincodeId: &peer.ChaincodeID{
|
|
Name: chaincodeName,
|
|
},
|
|
Events: eventsBytes,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// proposal response
|
|
proposalResBytes, err := proto.Marshal(&peer.ProposalResponsePayload{
|
|
Extension: actionBytes,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// chaincode action
|
|
chaincodeActionPayload := &peer.ChaincodeActionPayload{
|
|
Action: &peer.ChaincodeEndorsedAction{
|
|
ProposalResponsePayload: proposalResBytes,
|
|
Endorsements: []*peer.Endorsement{},
|
|
},
|
|
}
|
|
return chaincodeActionPayload, err
|
|
}
|
|
|
|
func createTestBlock(data []*common.Envelope) (*common.Block, error) {
|
|
// block
|
|
block := &common.Block{
|
|
Header: &common.BlockHeader{
|
|
Number: 0,
|
|
DataHash: []byte{},
|
|
},
|
|
Data: &common.BlockData{},
|
|
Metadata: &common.BlockMetadata{},
|
|
}
|
|
for _, d := range data {
|
|
envBytes, err := proto.Marshal(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
block.Data.Data = append(block.Data.Data, envBytes)
|
|
}
|
|
// making up metadata
|
|
block.Metadata.Metadata = make([][]byte, 4)
|
|
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = make([]byte, len(data))
|
|
return block, nil
|
|
}
|
|
|
|
func produceSamplePvtdataOrPanic(txNum uint64, nsColls []string) *ledger.TxPvtData {
|
|
builder := rwsetutil.NewRWSetBuilder()
|
|
for _, nsColl := range nsColls {
|
|
nsCollSplit := strings.Split(nsColl, ":")
|
|
ns := nsCollSplit[0]
|
|
coll := nsCollSplit[1]
|
|
builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll)))
|
|
}
|
|
simRes, err := builder.GetTxSimulationResults()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}
|
|
}
|