github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/discovery/support/config/support_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package config_test
     8  
     9  import (
    10  	"crypto/rand"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"testing"
    17  
    18  	"github.com/golang/protobuf/proto"
    19  	"github.com/hechain20/hechain/common/channelconfig"
    20  	"github.com/hechain20/hechain/common/configtx/test"
    21  	"github.com/hechain20/hechain/discovery/support/config"
    22  	"github.com/hechain20/hechain/discovery/support/mocks"
    23  	"github.com/hechain20/hechain/internal/configtxgen/encoder"
    24  	"github.com/hechain20/hechain/internal/configtxgen/genesisconfig"
    25  	"github.com/hechain20/hechain/protoutil"
    26  	"github.com/hyperledger/fabric-protos-go/common"
    27  	"github.com/hyperledger/fabric-protos-go/discovery"
    28  	"github.com/hyperledger/fabric-protos-go/msp"
    29  	"github.com/onsi/gomega/gexec"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  func TestMSPIDMapping(t *testing.T) {
    34  	randString := func() string {
    35  		buff := make([]byte, 10)
    36  		rand.Read(buff)
    37  		return hex.EncodeToString(buff)
    38  	}
    39  
    40  	dir := filepath.Join(os.TempDir(), fmt.Sprintf("TestMSPIDMapping_%s", randString()))
    41  	os.Mkdir(dir, 0o700)
    42  	defer os.RemoveAll(dir)
    43  
    44  	cryptogen, err := gexec.Build("github.com/hechain20/hechain/cmd/cryptogen")
    45  	require.NoError(t, err)
    46  	defer os.Remove(cryptogen)
    47  
    48  	idemixgen, err := gexec.Build("github.com/IBM/idemix/tools/idemixgen", "-mod=mod")
    49  	require.NoError(t, err)
    50  	defer os.Remove(idemixgen)
    51  
    52  	cryptoConfigDir := filepath.Join(dir, "crypto-config")
    53  	b, err := exec.Command(cryptogen, "generate", fmt.Sprintf("--output=%s", cryptoConfigDir)).CombinedOutput()
    54  	require.NoError(t, err, string(b))
    55  
    56  	idemixConfigDir := filepath.Join(dir, "crypto-config", "idemix")
    57  	b, err = exec.Command(idemixgen, "ca-keygen", fmt.Sprintf("--output=%s", idemixConfigDir)).CombinedOutput()
    58  	require.NoError(t, err, string(b))
    59  
    60  	profileConfig := genesisconfig.Load("TwoOrgsChannel", "testdata/")
    61  	ordererConfig := genesisconfig.Load("TwoOrgsOrdererGenesis", "testdata/")
    62  	profileConfig.Orderer = ordererConfig.Orderer
    63  
    64  	// Override the MSP directory with our randomly generated and populated path
    65  	for _, org := range ordererConfig.Orderer.Organizations {
    66  		org.MSPDir = filepath.Join(cryptoConfigDir, "ordererOrganizations", "example.com", "msp")
    67  		org.Name = randString()
    68  	}
    69  
    70  	// Randomize organization names
    71  	for _, org := range profileConfig.Application.Organizations {
    72  		org.Name = randString()
    73  		// Non bccsp-msp orgs don't have the crypto material produced by cryptogen,
    74  		// we need to use the idemix crypto folder instead.
    75  		if org.MSPType != "bccsp" {
    76  			org.MSPDir = filepath.Join(idemixConfigDir)
    77  			continue
    78  		}
    79  		org.MSPDir = filepath.Join(cryptoConfigDir, "peerOrganizations", "org1.example.com", "msp")
    80  	}
    81  
    82  	channelGroup, err := encoder.NewChannelGroup(profileConfig)
    83  	require.NoError(t, err)
    84  	fakeConfigGetter := &mocks.ConfigGetter{}
    85  	fakeConfigGetter.GetCurrConfigReturnsOnCall(
    86  		0,
    87  		&common.Config{
    88  			ChannelGroup: channelGroup,
    89  		},
    90  	)
    91  
    92  	cs := config.NewDiscoverySupport(fakeConfigGetter)
    93  	res, err := cs.Config("mychannel")
    94  	require.NoError(t, err)
    95  
    96  	actualKeys := make(map[string]struct{})
    97  	for key := range res.Orderers {
    98  		actualKeys[key] = struct{}{}
    99  	}
   100  
   101  	for key := range res.Msps {
   102  		actualKeys[key] = struct{}{}
   103  	}
   104  
   105  	// Note that Org3MSP is an idemix org, but it shouldn't be listed here
   106  	// because peers can't have idemix credentials
   107  	expected := map[string]struct{}{
   108  		"OrdererMSP": {},
   109  		"Org1MSP":    {},
   110  		"Org2MSP":    {},
   111  	}
   112  	require.Equal(t, expected, actualKeys)
   113  }
   114  
   115  func TestSupportGreenPath(t *testing.T) {
   116  	fakeConfigGetter := &mocks.ConfigGetter{}
   117  	fakeConfigGetter.GetCurrConfigReturnsOnCall(0, nil)
   118  
   119  	cs := config.NewDiscoverySupport(fakeConfigGetter)
   120  	res, err := cs.Config("test")
   121  	require.Nil(t, res)
   122  	require.Equal(t, "could not get last config for channel test", err.Error())
   123  
   124  	config, err := test.MakeChannelConfig("test")
   125  	require.NoError(t, err)
   126  	require.NotNil(t, config)
   127  
   128  	fakeConfigGetter.GetCurrConfigReturnsOnCall(1, config)
   129  	res, err = cs.Config("test")
   130  	require.NoError(t, err)
   131  	require.NotNil(t, res)
   132  }
   133  
   134  func TestValidateConfig(t *testing.T) {
   135  	tests := []struct {
   136  		name          string
   137  		config        *common.Config
   138  		containsError string
   139  	}{
   140  		{
   141  			name:          "nil Config field",
   142  			config:        &common.Config{},
   143  			containsError: "field Config.ChannelGroup is nil",
   144  		},
   145  		{
   146  			name: "nil Groups field",
   147  			config: &common.Config{
   148  				ChannelGroup: &common.ConfigGroup{},
   149  			},
   150  			containsError: "field Config.ChannelGroup.Groups is nil",
   151  		},
   152  		{
   153  			name: "no orderer group key",
   154  			config: &common.Config{
   155  				ChannelGroup: &common.ConfigGroup{
   156  					Groups: map[string]*common.ConfigGroup{
   157  						channelconfig.ApplicationGroupKey: {},
   158  					},
   159  				},
   160  			},
   161  			containsError: "key Config.ChannelGroup.Groups[Orderer] is missing",
   162  		},
   163  		{
   164  			name: "no application group key",
   165  			config: &common.Config{
   166  				ChannelGroup: &common.ConfigGroup{
   167  					Groups: map[string]*common.ConfigGroup{
   168  						channelconfig.OrdererGroupKey: {
   169  							Groups: map[string]*common.ConfigGroup{},
   170  						},
   171  					},
   172  				},
   173  			},
   174  			containsError: "key Config.ChannelGroup.Groups[Application] is missing",
   175  		},
   176  		{
   177  			name: "no groups key in orderer group",
   178  			config: &common.Config{
   179  				ChannelGroup: &common.ConfigGroup{
   180  					Groups: map[string]*common.ConfigGroup{
   181  						channelconfig.ApplicationGroupKey: {
   182  							Groups: map[string]*common.ConfigGroup{},
   183  						},
   184  						channelconfig.OrdererGroupKey: {},
   185  					},
   186  				},
   187  			},
   188  			containsError: "key Config.ChannelGroup.Groups[Orderer].Groups is nil",
   189  		},
   190  		{
   191  			name: "no groups key in application group",
   192  			config: &common.Config{
   193  				ChannelGroup: &common.ConfigGroup{
   194  					Groups: map[string]*common.ConfigGroup{
   195  						channelconfig.ApplicationGroupKey: {},
   196  						channelconfig.OrdererGroupKey: {
   197  							Groups: map[string]*common.ConfigGroup{},
   198  						},
   199  					},
   200  				},
   201  			},
   202  			containsError: "key Config.ChannelGroup.Groups[Application].Groups is nil",
   203  		},
   204  		{
   205  			name: "no Values in ChannelGroup",
   206  			config: &common.Config{
   207  				ChannelGroup: &common.ConfigGroup{
   208  					Groups: map[string]*common.ConfigGroup{
   209  						channelconfig.ApplicationGroupKey: {
   210  							Groups: map[string]*common.ConfigGroup{},
   211  						},
   212  						channelconfig.OrdererGroupKey: {
   213  							Groups: map[string]*common.ConfigGroup{},
   214  						},
   215  					},
   216  				},
   217  			},
   218  			containsError: "field Config.ChannelGroup.Values is nil",
   219  		},
   220  	}
   221  
   222  	for _, test := range tests {
   223  		test := test
   224  		t.Run(test.name, func(t *testing.T) {
   225  			err := config.ValidateConfig(test.config)
   226  			require.Contains(t, test.containsError, err.Error())
   227  		})
   228  	}
   229  }
   230  
   231  func TestOrdererEndpoints(t *testing.T) {
   232  	t.Run("Global endpoints", func(t *testing.T) {
   233  		channelConfig, err := test.MakeChannelConfig("mychannel")
   234  		require.NoError(t, err)
   235  
   236  		fakeConfigGetter := &mocks.ConfigGetter{}
   237  		cs := config.NewDiscoverySupport(fakeConfigGetter)
   238  
   239  		fakeConfigGetter.GetCurrConfigReturnsOnCall(0, channelConfig)
   240  
   241  		injectGlobalOrdererEndpoint(t, channelConfig, "globalEndpoint:7050")
   242  
   243  		res, err := cs.Config("test")
   244  		require.NoError(t, err)
   245  		require.Equal(t, map[string]*discovery.Endpoints{
   246  			"SampleOrg": {Endpoint: []*discovery.Endpoint{{Host: "globalEndpoint", Port: 7050}}},
   247  		}, res.Orderers)
   248  	})
   249  
   250  	t.Run("Per org endpoints alongside global endpoints", func(t *testing.T) {
   251  		channelConfig, err := test.MakeChannelConfig("mychannel")
   252  		require.NoError(t, err)
   253  
   254  		fakeConfigGetter := &mocks.ConfigGetter{}
   255  		cs := config.NewDiscoverySupport(fakeConfigGetter)
   256  
   257  		fakeConfigGetter.GetCurrConfigReturnsOnCall(0, channelConfig)
   258  
   259  		injectAdditionalEndpointPair(t, channelConfig, "perOrgEndpoint:7050", "anotherOrg")
   260  		injectAdditionalEndpointPair(t, channelConfig, "endpointWithoutAPortName", "aBadOrg")
   261  
   262  		res, err := cs.Config("test")
   263  		require.NoError(t, err)
   264  		require.Equal(t, map[string]*discovery.Endpoints{
   265  			"SampleOrg":  {Endpoint: []*discovery.Endpoint{{Host: "127.0.0.1", Port: 7050}}},
   266  			"anotherOrg": {Endpoint: []*discovery.Endpoint{{Host: "perOrgEndpoint", Port: 7050}}},
   267  			"aBadOrg":    {},
   268  		}, res.Orderers)
   269  	})
   270  
   271  	t.Run("Per org endpoints without global endpoints", func(t *testing.T) {
   272  		channelConfig, err := test.MakeChannelConfig("mychannel")
   273  		require.NoError(t, err)
   274  
   275  		fakeConfigGetter := &mocks.ConfigGetter{}
   276  		cs := config.NewDiscoverySupport(fakeConfigGetter)
   277  
   278  		fakeConfigGetter.GetCurrConfigReturnsOnCall(0, channelConfig)
   279  
   280  		removeGlobalEndpoints(t, channelConfig)
   281  		injectAdditionalEndpointPair(t, channelConfig, "perOrgEndpoint:7050", "SampleOrg")
   282  		injectAdditionalEndpointPair(t, channelConfig, "endpointWithoutAPortName", "aBadOrg")
   283  
   284  		res, err := cs.Config("test")
   285  		require.NoError(t, err)
   286  		require.Equal(t, map[string]*discovery.Endpoints{
   287  			"SampleOrg": {Endpoint: []*discovery.Endpoint{{Host: "perOrgEndpoint", Port: 7050}}},
   288  			"aBadOrg":   {},
   289  		}, res.Orderers)
   290  	})
   291  }
   292  
   293  func removeGlobalEndpoints(t *testing.T, config *common.Config) {
   294  	// Remove the orderer addresses
   295  	delete(config.ChannelGroup.Values, channelconfig.OrdererAddressesKey)
   296  }
   297  
   298  func injectGlobalOrdererEndpoint(t *testing.T, config *common.Config, endpoint string) {
   299  	ordererAddresses := channelconfig.OrdererAddressesValue([]string{endpoint})
   300  	// Replace the orderer addresses
   301  	config.ChannelGroup.Values[ordererAddresses.Key()] = &common.ConfigValue{
   302  		Value:     protoutil.MarshalOrPanic(ordererAddresses.Value()),
   303  		ModPolicy: "/Channel/Orderer/Admins",
   304  	}
   305  	// Remove the per org addresses, if applicable
   306  	ordererGrps := config.ChannelGroup.Groups[channelconfig.OrdererGroupKey].Groups
   307  	for _, grp := range ordererGrps {
   308  		if grp.Values[channelconfig.EndpointsKey] == nil {
   309  			continue
   310  		}
   311  		grp.Values[channelconfig.EndpointsKey].Value = nil
   312  	}
   313  }
   314  
   315  func injectAdditionalEndpointPair(t *testing.T, config *common.Config, endpoint string, orgName string) {
   316  	ordererGrp := config.ChannelGroup.Groups[channelconfig.OrdererGroupKey].Groups
   317  	// Get the first orderer org config
   318  	var firstOrdererConfig *common.ConfigGroup
   319  	for _, grp := range ordererGrp {
   320  		firstOrdererConfig = grp
   321  		break
   322  	}
   323  	// Duplicate it.
   324  	secondOrdererConfig := proto.Clone(firstOrdererConfig).(*common.ConfigGroup)
   325  	ordererGrp[orgName] = secondOrdererConfig
   326  	// Reach the FabricMSPConfig buried in it.
   327  	mspConfig := &msp.MSPConfig{}
   328  	err := proto.Unmarshal(secondOrdererConfig.Values[channelconfig.MSPKey].Value, mspConfig)
   329  	require.NoError(t, err)
   330  
   331  	fabricConfig := &msp.FabricMSPConfig{}
   332  	err = proto.Unmarshal(mspConfig.Config, fabricConfig)
   333  	require.NoError(t, err)
   334  
   335  	// Rename it.
   336  	fabricConfig.Name = orgName
   337  
   338  	// Pack the MSP config back into the config
   339  	secondOrdererConfig.Values[channelconfig.MSPKey].Value = protoutil.MarshalOrPanic(&msp.MSPConfig{
   340  		Config: protoutil.MarshalOrPanic(fabricConfig),
   341  		Type:   mspConfig.Type,
   342  	})
   343  
   344  	// Inject the endpoint
   345  	ordererOrgProtos := &common.OrdererAddresses{
   346  		Addresses: []string{endpoint},
   347  	}
   348  	secondOrdererConfig.Values[channelconfig.EndpointsKey].Value = protoutil.MarshalOrPanic(ordererOrgProtos)
   349  }