github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/gossip/privdata/distributor_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package privdata
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"testing"
    13  
    14  	proto "github.com/hyperledger/fabric-protos-go/gossip"
    15  	"github.com/hyperledger/fabric-protos-go/peer"
    16  	"github.com/hyperledger/fabric-protos-go/transientstore"
    17  	"github.com/hyperledger/fabric/core/common/privdata"
    18  	"github.com/hyperledger/fabric/gossip/api"
    19  	gcommon "github.com/hyperledger/fabric/gossip/common"
    20  	"github.com/hyperledger/fabric/gossip/discovery"
    21  	"github.com/hyperledger/fabric/gossip/filter"
    22  	gossip2 "github.com/hyperledger/fabric/gossip/gossip"
    23  	"github.com/hyperledger/fabric/gossip/metrics"
    24  	"github.com/hyperledger/fabric/gossip/metrics/mocks"
    25  	"github.com/hyperledger/fabric/gossip/protoext"
    26  	"github.com/hyperledger/fabric/protoutil"
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/mock"
    29  )
    30  
    31  type collectionAccessFactoryMock struct {
    32  	mock.Mock
    33  }
    34  
    35  func (mock *collectionAccessFactoryMock) AccessPolicy(config *peer.CollectionConfig, chainID string) (privdata.CollectionAccessPolicy, error) {
    36  	res := mock.Called(config, chainID)
    37  	return res.Get(0).(privdata.CollectionAccessPolicy), res.Error(1)
    38  }
    39  
    40  type collectionAccessPolicyMock struct {
    41  	mock.Mock
    42  }
    43  
    44  func (mock *collectionAccessPolicyMock) AccessFilter() privdata.Filter {
    45  	args := mock.Called()
    46  	return args.Get(0).(privdata.Filter)
    47  }
    48  
    49  func (mock *collectionAccessPolicyMock) RequiredPeerCount() int {
    50  	args := mock.Called()
    51  	return args.Int(0)
    52  }
    53  
    54  func (mock *collectionAccessPolicyMock) MaximumPeerCount() int {
    55  	args := mock.Called()
    56  	return args.Int(0)
    57  }
    58  
    59  func (mock *collectionAccessPolicyMock) MemberOrgs() []string {
    60  	args := mock.Called()
    61  	return args.Get(0).([]string)
    62  }
    63  
    64  func (mock *collectionAccessPolicyMock) IsMemberOnlyRead() bool {
    65  	args := mock.Called()
    66  	return args.Get(0).(bool)
    67  }
    68  
    69  func (mock *collectionAccessPolicyMock) IsMemberOnlyWrite() bool {
    70  	args := mock.Called()
    71  	return args.Get(0).(bool)
    72  }
    73  
    74  func (mock *collectionAccessPolicyMock) Setup(requiredPeerCount int, maxPeerCount int,
    75  	accessFilter privdata.Filter, orgs []string, memberOnlyRead bool) {
    76  	mock.On("AccessFilter").Return(accessFilter)
    77  	mock.On("RequiredPeerCount").Return(requiredPeerCount)
    78  	mock.On("MaximumPeerCount").Return(maxPeerCount)
    79  	mock.On("MemberOrgs").Return(orgs)
    80  	mock.On("IsMemberOnlyRead").Return(memberOnlyRead)
    81  }
    82  
    83  type gossipMock struct {
    84  	err error
    85  	mock.Mock
    86  	api.PeerSignature
    87  }
    88  
    89  func (g *gossipMock) IdentityInfo() api.PeerIdentitySet {
    90  	return g.Called().Get(0).(api.PeerIdentitySet)
    91  }
    92  
    93  func (g *gossipMock) PeersOfChannel(channelID gcommon.ChannelID) []discovery.NetworkMember {
    94  	return g.Called(channelID).Get(0).([]discovery.NetworkMember)
    95  }
    96  
    97  func (g *gossipMock) SendByCriteria(message *protoext.SignedGossipMessage, criteria gossip2.SendCriteria) error {
    98  	args := g.Called(message, criteria)
    99  	if args.Get(0) != nil {
   100  		return args.Get(0).(error)
   101  	}
   102  	return nil
   103  }
   104  
   105  func (g *gossipMock) PeerFilter(channel gcommon.ChannelID, messagePredicate api.SubChannelSelectionCriteria) (filter.RoutingFilter, error) {
   106  	if g.err != nil {
   107  		return nil, g.err
   108  	}
   109  	return func(member discovery.NetworkMember) bool {
   110  		return messagePredicate(g.PeerSignature)
   111  	}, nil
   112  }
   113  
   114  func TestDistributor(t *testing.T) {
   115  	channelID := "test"
   116  
   117  	g := &gossipMock{
   118  		Mock: mock.Mock{},
   119  		PeerSignature: api.PeerSignature{
   120  			Signature:    []byte{3, 4, 5},
   121  			Message:      []byte{6, 7, 8},
   122  			PeerIdentity: []byte{0, 1, 2},
   123  		},
   124  	}
   125  	sendings := make(chan struct {
   126  		*proto.PrivatePayload
   127  		gossip2.SendCriteria
   128  	}, 8)
   129  
   130  	g.On("PeersOfChannel", gcommon.ChannelID(channelID)).Return([]discovery.NetworkMember{
   131  		{PKIid: gcommon.PKIidType{1}},
   132  		{PKIid: gcommon.PKIidType{2}},
   133  	})
   134  
   135  	g.On("IdentityInfo").Return(api.PeerIdentitySet{
   136  		{
   137  			PKIId:        gcommon.PKIidType{1},
   138  			Organization: api.OrgIdentityType("org1"),
   139  		},
   140  		{
   141  			PKIId:        gcommon.PKIidType{2},
   142  			Organization: api.OrgIdentityType("org2"),
   143  		},
   144  	})
   145  
   146  	g.On("SendByCriteria", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
   147  		msg := args.Get(0).(*protoext.SignedGossipMessage)
   148  		sendCriteria := args.Get(1).(gossip2.SendCriteria)
   149  		sendings <- struct {
   150  			*proto.PrivatePayload
   151  			gossip2.SendCriteria
   152  		}{
   153  			PrivatePayload: msg.GetPrivateData().Payload,
   154  			SendCriteria:   sendCriteria,
   155  		}
   156  	}).Return(nil)
   157  	accessFactoryMock := &collectionAccessFactoryMock{}
   158  	c1ColConfig := &peer.CollectionConfig{
   159  		Payload: &peer.CollectionConfig_StaticCollectionConfig{
   160  			StaticCollectionConfig: &peer.StaticCollectionConfig{
   161  				Name:              "c1",
   162  				RequiredPeerCount: 1,
   163  				MaximumPeerCount:  1,
   164  			},
   165  		},
   166  	}
   167  
   168  	c2ColConfig := &peer.CollectionConfig{
   169  		Payload: &peer.CollectionConfig_StaticCollectionConfig{
   170  			StaticCollectionConfig: &peer.StaticCollectionConfig{
   171  				Name:              "c2",
   172  				RequiredPeerCount: 1,
   173  				MaximumPeerCount:  1,
   174  			},
   175  		},
   176  	}
   177  
   178  	policyMock := &collectionAccessPolicyMock{}
   179  	policyMock.Setup(1, 2, func(_ protoutil.SignedData) bool {
   180  		return true
   181  	}, []string{"org1", "org2"}, false)
   182  
   183  	accessFactoryMock.On("AccessPolicy", c1ColConfig, channelID).Return(policyMock, nil)
   184  	accessFactoryMock.On("AccessPolicy", c2ColConfig, channelID).Return(policyMock, nil)
   185  
   186  	testMetricProvider := mocks.TestUtilConstructMetricProvider()
   187  	metrics := metrics.NewGossipMetrics(testMetricProvider.FakeProvider).PrivdataMetrics
   188  
   189  	d := NewDistributor(channelID, g, accessFactoryMock, metrics, 0)
   190  	pdFactory := &pvtDataFactory{}
   191  	pvtData := pdFactory.addRWSet().addNSRWSet("ns1", "c1", "c2").addRWSet().addNSRWSet("ns2", "c1", "c2").create()
   192  	err := d.Distribute("tx1", &transientstore.TxPvtReadWriteSetWithConfigInfo{
   193  		PvtRwset: pvtData[0].WriteSet,
   194  		CollectionConfigs: map[string]*peer.CollectionConfigPackage{
   195  			"ns1": {
   196  				Config: []*peer.CollectionConfig{c1ColConfig, c2ColConfig},
   197  			},
   198  		},
   199  	}, 0)
   200  	assert.NoError(t, err)
   201  	err = d.Distribute("tx2", &transientstore.TxPvtReadWriteSetWithConfigInfo{
   202  		PvtRwset: pvtData[1].WriteSet,
   203  		CollectionConfigs: map[string]*peer.CollectionConfigPackage{
   204  			"ns2": {
   205  				Config: []*peer.CollectionConfig{c1ColConfig, c2ColConfig},
   206  			},
   207  		},
   208  	}, 0)
   209  	assert.NoError(t, err)
   210  
   211  	expectedMaxCount := map[string]int{}
   212  	expectedMinAck := map[string]int{}
   213  
   214  	i := 0
   215  	assert.Len(t, sendings, 8)
   216  	for dis := range sendings {
   217  		key := fmt.Sprintf("%s~%s", dis.PrivatePayload.Namespace, dis.PrivatePayload.CollectionName)
   218  		expectedMaxCount[key] += dis.SendCriteria.MaxPeers
   219  		expectedMinAck[key] += dis.SendCriteria.MinAck
   220  		i++
   221  		if i == 8 {
   222  			break
   223  		}
   224  	}
   225  
   226  	// Ensure MaxPeers is maxInternalPeers which is 2
   227  	assert.Equal(t, 2, expectedMaxCount["ns1~c1"])
   228  	assert.Equal(t, 2, expectedMaxCount["ns2~c2"])
   229  
   230  	// and MinAck is minInternalPeers which is 1
   231  	assert.Equal(t, 1, expectedMinAck["ns1~c1"])
   232  	assert.Equal(t, 1, expectedMinAck["ns2~c2"])
   233  
   234  	// Channel is empty after we read 8 times from it
   235  	assert.Len(t, sendings, 0)
   236  
   237  	// Bad path: dependencies (gossip and others) don't work properly
   238  	g.err = errors.New("failed obtaining filter")
   239  	err = d.Distribute("tx1", &transientstore.TxPvtReadWriteSetWithConfigInfo{
   240  		PvtRwset: pvtData[0].WriteSet,
   241  		CollectionConfigs: map[string]*peer.CollectionConfigPackage{
   242  			"ns1": {
   243  				Config: []*peer.CollectionConfig{c1ColConfig, c2ColConfig},
   244  			},
   245  		},
   246  	}, 0)
   247  	assert.Error(t, err)
   248  	assert.Contains(t, err.Error(), "failed obtaining filter")
   249  
   250  	g.Mock = mock.Mock{}
   251  	g.On("SendByCriteria", mock.Anything, mock.Anything).Return(errors.New("failed sending"))
   252  	g.On("PeersOfChannel", gcommon.ChannelID(channelID)).Return([]discovery.NetworkMember{
   253  		{PKIid: gcommon.PKIidType{1}},
   254  	})
   255  
   256  	g.On("IdentityInfo").Return(api.PeerIdentitySet{
   257  		{
   258  			PKIId:        gcommon.PKIidType{1},
   259  			Organization: api.OrgIdentityType("org1"),
   260  		},
   261  	})
   262  
   263  	g.err = nil
   264  	err = d.Distribute("tx1", &transientstore.TxPvtReadWriteSetWithConfigInfo{
   265  		PvtRwset: pvtData[0].WriteSet,
   266  		CollectionConfigs: map[string]*peer.CollectionConfigPackage{
   267  			"ns1": {
   268  				Config: []*peer.CollectionConfig{c1ColConfig, c2ColConfig},
   269  			},
   270  		},
   271  	}, 0)
   272  	assert.Error(t, err)
   273  	assert.Contains(t, err.Error(), "Failed disseminating 2 out of 2 private dissemination plans")
   274  
   275  	assert.Equal(t,
   276  		[]string{"channel", channelID},
   277  		testMetricProvider.FakeSendDuration.WithArgsForCall(0),
   278  	)
   279  	assert.True(t, testMetricProvider.FakeSendDuration.ObserveArgsForCall(0) > 0)
   280  }