go_study/fabric-main/discovery/endorsement/collection_test.go

253 lines
8.3 KiB
Go

/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package endorsement
import (
"bytes"
"fmt"
"testing"
"github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric-protos-go/msp"
"github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/gossip/api"
gcommon "github.com/hyperledger/fabric/gossip/common"
disc "github.com/hyperledger/fabric/gossip/discovery"
"github.com/hyperledger/fabric/protoutil"
"github.com/stretchr/testify/require"
)
func TestPrincipalsFromCollectionConfig(t *testing.T) {
t.Run("Empty config", func(t *testing.T) {
res, err := principalsFromCollectionConfig(nil)
require.NoError(t, err)
require.Empty(t, res)
})
t.Run("Not empty config", func(t *testing.T) {
org1AndOrg2 := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
org3AndOrg4 := []*msp.MSPPrincipal{orgPrincipal("Org3MSP"), orgPrincipal("Org4MSP")}
col2principals := map[string][]*msp.MSPPrincipal{
"foo": org1AndOrg2,
"bar": org3AndOrg4,
}
config := buildCollectionConfig(col2principals)
res, err := principalsFromCollectionConfig(config)
require.NoError(t, err)
assertEqualPrincipalSets(t, policies.PrincipalSet(org1AndOrg2), res["foo"])
assertEqualPrincipalSets(t, policies.PrincipalSet(org3AndOrg4), res["bar"])
require.Empty(t, res["baz"])
})
}
func TestNewCollectionFilterInvalidInput(t *testing.T) {
t.Run("Invalid collection type", func(t *testing.T) {
collections := &peer.CollectionConfigPackage{}
collections.Config = []*peer.CollectionConfig{
{
Payload: nil,
},
}
filter, err := principalsFromCollectionConfig(collections)
require.Nil(t, filter)
require.Contains(t, err.Error(), "expected a static collection")
})
t.Run("Invalid membership policy", func(t *testing.T) {
collections := &peer.CollectionConfigPackage{}
collections.Config = []*peer.CollectionConfig{
{
Payload: &peer.CollectionConfig_StaticCollectionConfig{
StaticCollectionConfig: &peer.StaticCollectionConfig{
Name: "foo",
},
},
},
}
filter, err := principalsFromCollectionConfig(collections)
require.Nil(t, filter)
require.Contains(t, err.Error(), "MemberOrgsPolicy of foo is nil")
})
t.Run("Missing policy", func(t *testing.T) {
collections := &peer.CollectionConfigPackage{}
collections.Config = []*peer.CollectionConfig{
{
Payload: &peer.CollectionConfig_StaticCollectionConfig{
StaticCollectionConfig: &peer.StaticCollectionConfig{
Name: "foo",
MemberOrgsPolicy: &peer.CollectionPolicyConfig{},
},
},
},
}
filter, err := principalsFromCollectionConfig(collections)
require.Nil(t, filter)
require.Contains(t, err.Error(), "policy of foo is nil")
})
}
func TestToIdentityFilter(t *testing.T) {
col2principals := make(principalSetsByCollectionName)
col2principals["foo"] = []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
t.Run("collection doesn't exist in mapping", func(t *testing.T) {
filter, err := col2principals.toIdentityFilter("mychannel", &principalEvaluatorMock{}, &peer.ChaincodeCall{
Name: "mycc",
CollectionNames: []string{"bar"},
})
require.Nil(t, filter)
require.Equal(t, "collection bar doesn't exist in collection config for chaincode mycc", err.Error())
})
t.Run("collection exists in mapping", func(t *testing.T) {
filter, err := col2principals.toIdentityFilter("mychannel", &principalEvaluatorMock{}, &peer.ChaincodeCall{
Name: "mycc",
CollectionNames: []string{"foo"},
})
require.NoError(t, err)
identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
Mspid: "Org2MSP",
})
require.True(t, filter(identity))
identity = protoutil.MarshalOrPanic(&msp.SerializedIdentity{
Mspid: "Org3MSP",
})
require.False(t, filter(identity))
})
}
func TestCombine(t *testing.T) {
filter1 := identityFilter(func(identity api.PeerIdentityType) bool {
return bytes.Equal([]byte("p1"), identity) || bytes.Equal([]byte("p2"), identity)
})
filter2 := identityFilter(func(identity api.PeerIdentityType) bool {
return bytes.Equal([]byte("p2"), identity) || bytes.Equal([]byte("p3"), identity)
})
filter := identityFilters{filter1, filter2}.combine()
require.False(t, filter(api.PeerIdentityType("p1")))
require.True(t, filter(api.PeerIdentityType("p2")))
require.False(t, filter(api.PeerIdentityType("p3")))
require.False(t, filter(api.PeerIdentityType("p4")))
}
func TestToMemberFilter(t *testing.T) {
unauthorizedIdentity := api.PeerIdentityType("unauthorizedIdentity")
authorizedIdentity := api.PeerIdentityType("authorizedIdentity")
notPresentIdentity := api.PeerIdentityType("api.PeerIdentityInfo")
filter := identityFilter(func(identity api.PeerIdentityType) bool {
return bytes.Equal(authorizedIdentity, identity)
})
identityInfoByID := map[string]api.PeerIdentityInfo{
"authorizedIdentity": {PKIId: gcommon.PKIidType(authorizedIdentity), Identity: authorizedIdentity},
"unauthorizedIdentity": {PKIId: gcommon.PKIidType(unauthorizedIdentity), Identity: unauthorizedIdentity},
}
memberFilter := filter.toMemberFilter(identityInfoByID)
t.Run("Member is authorized", func(t *testing.T) {
authorized := memberFilter(disc.NetworkMember{
PKIid: gcommon.PKIidType(authorizedIdentity),
})
require.True(t, authorized)
})
t.Run("Member is unauthorized", func(t *testing.T) {
authorized := memberFilter(disc.NetworkMember{
PKIid: gcommon.PKIidType(unauthorizedIdentity),
})
require.False(t, authorized)
})
t.Run("Member is not found in mapping", func(t *testing.T) {
authorized := memberFilter(disc.NetworkMember{
PKIid: gcommon.PKIidType(notPresentIdentity),
})
require.False(t, authorized)
})
}
func TestIsIdentityAuthorizedByPrincipalSet(t *testing.T) {
principals := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
t.Run("Authorized", func(t *testing.T) {
identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
Mspid: "Org1MSP",
})
authorized := isIdentityAuthorizedByPrincipalSet("mychannel", &principalEvaluatorMock{}, principals, identity)
require.True(t, authorized)
})
t.Run("Unauthorized", func(t *testing.T) {
identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
Mspid: "Org3MSP",
})
authorized := isIdentityAuthorizedByPrincipalSet("mychannel", &principalEvaluatorMock{}, principals, identity)
require.False(t, authorized)
})
}
func TestFilterForPrincipalSets(t *testing.T) {
org1AndOrg2 := []*msp.MSPPrincipal{orgPrincipal("Org1MSP"), orgPrincipal("Org2MSP")}
org2AndOrg3 := []*msp.MSPPrincipal{orgPrincipal("Org2MSP"), orgPrincipal("Org3MSP")}
org3AndOrg4 := []*msp.MSPPrincipal{orgPrincipal("Org3MSP"), orgPrincipal("Org4MSP")}
identity := protoutil.MarshalOrPanic(&msp.SerializedIdentity{
Mspid: "Org2MSP",
})
t.Run("Identity is authorized by all principals", func(t *testing.T) {
filter := filterForPrincipalSets("mychannel", &principalEvaluatorMock{}, policies.PrincipalSets{org1AndOrg2, org2AndOrg3})
require.True(t, filter(identity))
})
t.Run("Identity is not authorized by all principals", func(t *testing.T) {
filter := filterForPrincipalSets("mychannel", &principalEvaluatorMock{}, policies.PrincipalSets{org1AndOrg2, org3AndOrg4})
require.False(t, filter(identity))
})
}
func buildCollectionConfig(col2principals map[string][]*msp.MSPPrincipal) *peer.CollectionConfigPackage {
collections := &peer.CollectionConfigPackage{}
for col, principals := range col2principals {
collections.Config = append(collections.Config, &peer.CollectionConfig{
Payload: &peer.CollectionConfig_StaticCollectionConfig{
StaticCollectionConfig: &peer.StaticCollectionConfig{
Name: col,
MemberOrgsPolicy: &peer.CollectionPolicyConfig{
Payload: &peer.CollectionPolicyConfig_SignaturePolicy{
SignaturePolicy: &common.SignaturePolicyEnvelope{
Identities: principals,
},
},
},
},
},
})
}
return collections
}
func orgPrincipal(mspID string) *msp.MSPPrincipal {
return &msp.MSPPrincipal{
PrincipalClassification: msp.MSPPrincipal_ROLE,
Principal: protoutil.MarshalOrPanic(&msp.MSPRole{
MspIdentifier: mspID,
Role: msp.MSPRole_PEER,
}),
}
}
func assertEqualPrincipalSets(t *testing.T, ps1, ps2 policies.PrincipalSet) {
ps1s := fmt.Sprintf("%v", ps1)
ps2s := fmt.Sprintf("%v", ps2)
require.Equal(t, ps1s, ps2s)
}