github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/configtxgen/encoder/encoder_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package encoder_test
     8  
     9  import (
    10  	"fmt"
    11  
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hechain20/hechain/common/util"
    17  	"github.com/hechain20/hechain/internal/configtxgen/encoder"
    18  	"github.com/hechain20/hechain/internal/configtxgen/encoder/fakes"
    19  	"github.com/hechain20/hechain/internal/configtxgen/genesisconfig"
    20  	"github.com/hechain20/hechain/internal/pkg/identity"
    21  	"github.com/hechain20/hechain/protoutil"
    22  	cb "github.com/hyperledger/fabric-protos-go/common"
    23  	ab "github.com/hyperledger/fabric-protos-go/orderer"
    24  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    25  )
    26  
    27  //go:generate counterfeiter -o fakes/signer_serializer.go --fake-name SignerSerializer . signerSerializer
    28  type signerSerializer interface {
    29  	identity.SignerSerializer
    30  }
    31  
    32  func CreateStandardPolicies() map[string]*genesisconfig.Policy {
    33  	return map[string]*genesisconfig.Policy{
    34  		"Admins": {
    35  			Type: "ImplicitMeta",
    36  			Rule: "ANY Admins",
    37  		},
    38  		"Readers": {
    39  			Type: "ImplicitMeta",
    40  			Rule: "ANY Readers",
    41  		},
    42  		"Writers": {
    43  			Type: "ImplicitMeta",
    44  			Rule: "ANY Writers",
    45  		},
    46  	}
    47  }
    48  
    49  func CreateStandardOrdererPolicies() map[string]*genesisconfig.Policy {
    50  	policies := CreateStandardPolicies()
    51  
    52  	policies["BlockValidation"] = &genesisconfig.Policy{
    53  		Type: "ImplicitMeta",
    54  		Rule: "ANY Admins",
    55  	}
    56  
    57  	return policies
    58  }
    59  
    60  var _ = Describe("Encoder", func() {
    61  	Describe("AddOrdererPolicies", func() {
    62  		var (
    63  			cg       *cb.ConfigGroup
    64  			policies map[string]*genesisconfig.Policy
    65  		)
    66  
    67  		BeforeEach(func() {
    68  			cg = protoutil.NewConfigGroup()
    69  			policies = CreateStandardOrdererPolicies()
    70  		})
    71  
    72  		It("adds the block validation policy to the group", func() {
    73  			err := encoder.AddOrdererPolicies(cg, policies, "Admins")
    74  			Expect(err).NotTo(HaveOccurred())
    75  			Expect(len(cg.Policies)).To(Equal(4))
    76  
    77  			Expect(cg.Policies["BlockValidation"].Policy).To(Equal(&cb.Policy{
    78  				Type: int32(cb.Policy_IMPLICIT_META),
    79  				Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
    80  					SubPolicy: "Admins",
    81  					Rule:      cb.ImplicitMetaPolicy_ANY,
    82  				}),
    83  			}))
    84  		})
    85  
    86  		Context("when the policy map is nil", func() {
    87  			BeforeEach(func() {
    88  				policies = nil
    89  			})
    90  
    91  			It("returns an error", func() {
    92  				err := encoder.AddOrdererPolicies(cg, policies, "Admins")
    93  				Expect(err).To(MatchError("no policies defined"))
    94  			})
    95  		})
    96  
    97  		Context("when the policy map is missing 'BlockValidation'", func() {
    98  			BeforeEach(func() {
    99  				delete(policies, "BlockValidation")
   100  			})
   101  
   102  			It("returns an error", func() {
   103  				err := encoder.AddOrdererPolicies(cg, policies, "Admins")
   104  				Expect(err).To(MatchError("no BlockValidation policy defined"))
   105  			})
   106  		})
   107  	})
   108  
   109  	Describe("AddPolicies", func() {
   110  		var (
   111  			cg       *cb.ConfigGroup
   112  			policies map[string]*genesisconfig.Policy
   113  		)
   114  
   115  		BeforeEach(func() {
   116  			cg = protoutil.NewConfigGroup()
   117  			policies = CreateStandardPolicies()
   118  		})
   119  
   120  		It("adds the standard policies to the group", func() {
   121  			err := encoder.AddPolicies(cg, policies, "Admins")
   122  			Expect(err).NotTo(HaveOccurred())
   123  			Expect(len(cg.Policies)).To(Equal(3))
   124  
   125  			Expect(cg.Policies["Admins"].Policy).To(Equal(&cb.Policy{
   126  				Type: int32(cb.Policy_IMPLICIT_META),
   127  				Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   128  					SubPolicy: "Admins",
   129  					Rule:      cb.ImplicitMetaPolicy_ANY,
   130  				}),
   131  			}))
   132  
   133  			Expect(cg.Policies["Readers"].Policy).To(Equal(&cb.Policy{
   134  				Type: int32(cb.Policy_IMPLICIT_META),
   135  				Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   136  					SubPolicy: "Readers",
   137  					Rule:      cb.ImplicitMetaPolicy_ANY,
   138  				}),
   139  			}))
   140  
   141  			Expect(cg.Policies["Writers"].Policy).To(Equal(&cb.Policy{
   142  				Type: int32(cb.Policy_IMPLICIT_META),
   143  				Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   144  					SubPolicy: "Writers",
   145  					Rule:      cb.ImplicitMetaPolicy_ANY,
   146  				}),
   147  			}))
   148  		})
   149  
   150  		Context("when the policy map is nil", func() {
   151  			BeforeEach(func() {
   152  				policies = nil
   153  			})
   154  
   155  			It("returns an error", func() {
   156  				err := encoder.AddPolicies(cg, policies, "Admins")
   157  				Expect(err).To(MatchError("no policies defined"))
   158  			})
   159  		})
   160  
   161  		Context("when the policy map is missing 'Admins'", func() {
   162  			BeforeEach(func() {
   163  				delete(policies, "Admins")
   164  			})
   165  
   166  			It("returns an error", func() {
   167  				err := encoder.AddPolicies(cg, policies, "Admins")
   168  				Expect(err).To(MatchError("no Admins policy defined"))
   169  			})
   170  		})
   171  
   172  		Context("when the policy map is missing 'Readers'", func() {
   173  			BeforeEach(func() {
   174  				delete(policies, "Readers")
   175  			})
   176  
   177  			It("returns an error", func() {
   178  				err := encoder.AddPolicies(cg, policies, "Readers")
   179  				Expect(err).To(MatchError("no Readers policy defined"))
   180  			})
   181  		})
   182  
   183  		Context("when the policy map is missing 'Writers'", func() {
   184  			BeforeEach(func() {
   185  				delete(policies, "Writers")
   186  			})
   187  
   188  			It("returns an error", func() {
   189  				err := encoder.AddPolicies(cg, policies, "Writers")
   190  				Expect(err).To(MatchError("no Writers policy defined"))
   191  			})
   192  		})
   193  
   194  		Context("when the signature policy definition is bad", func() {
   195  			BeforeEach(func() {
   196  				policies["Readers"].Type = "Signature"
   197  				policies["Readers"].Rule = "garbage"
   198  			})
   199  
   200  			It("wraps and returns the error", func() {
   201  				err := encoder.AddPolicies(cg, policies, "Readers")
   202  				Expect(err).To(MatchError("invalid signature policy rule 'garbage': unrecognized token 'garbage' in policy string"))
   203  			})
   204  		})
   205  
   206  		Context("when the implicit policy definition is bad", func() {
   207  			BeforeEach(func() {
   208  				policies["Readers"].Type = "ImplicitMeta"
   209  				policies["Readers"].Rule = "garbage"
   210  			})
   211  
   212  			It("wraps and returns the error", func() {
   213  				err := encoder.AddPolicies(cg, policies, "Readers")
   214  				Expect(err).To(MatchError("invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   215  			})
   216  		})
   217  
   218  		Context("when the policy type is unknown", func() {
   219  			BeforeEach(func() {
   220  				policies["Readers"].Type = "garbage"
   221  			})
   222  
   223  			It("returns an error", func() {
   224  				err := encoder.AddPolicies(cg, policies, "Readers")
   225  				Expect(err).To(MatchError("unknown policy type: garbage"))
   226  			})
   227  		})
   228  	})
   229  
   230  	Describe("NewChannelGroup", func() {
   231  		var conf *genesisconfig.Profile
   232  
   233  		BeforeEach(func() {
   234  			conf = &genesisconfig.Profile{
   235  				Consortium: "MyConsortium",
   236  				Policies:   CreateStandardPolicies(),
   237  				Application: &genesisconfig.Application{
   238  					Policies: CreateStandardPolicies(),
   239  				},
   240  				Orderer: &genesisconfig.Orderer{
   241  					OrdererType: "solo",
   242  					Policies:    CreateStandardOrdererPolicies(),
   243  					Addresses:   []string{"foo.com:7050", "bar.com:8050"},
   244  				},
   245  				Consortiums: map[string]*genesisconfig.Consortium{
   246  					"SampleConsortium": {},
   247  				},
   248  				Capabilities: map[string]bool{
   249  					"FakeCapability": true,
   250  				},
   251  			}
   252  		})
   253  
   254  		It("translates the config into a config group", func() {
   255  			cg, err := encoder.NewChannelGroup(conf)
   256  			Expect(err).NotTo(HaveOccurred())
   257  			Expect(len(cg.Values)).To(Equal(5))
   258  			Expect(cg.Values["BlockDataHashingStructure"]).NotTo(BeNil())
   259  			Expect(cg.Values["Consortium"]).NotTo(BeNil())
   260  			Expect(cg.Values["Capabilities"]).NotTo(BeNil())
   261  			Expect(cg.Values["HashingAlgorithm"]).NotTo(BeNil())
   262  			Expect(cg.Values["OrdererAddresses"]).NotTo(BeNil())
   263  		})
   264  
   265  		Context("when the policy definition is bad", func() {
   266  			BeforeEach(func() {
   267  				conf.Policies["Admins"].Rule = "garbage"
   268  			})
   269  
   270  			It("wraps and returns the error", func() {
   271  				_, err := encoder.NewChannelGroup(conf)
   272  				Expect(err).To(MatchError("error adding policies to channel group: invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   273  			})
   274  		})
   275  
   276  		Context("when the orderer addresses are omitted", func() {
   277  			BeforeEach(func() {
   278  				conf.Orderer.Addresses = []string{}
   279  			})
   280  
   281  			It("does not create the config value", func() {
   282  				cg, err := encoder.NewChannelGroup(conf)
   283  				Expect(err).NotTo(HaveOccurred())
   284  				Expect(cg.Values["OrdererAddresses"]).To(BeNil())
   285  			})
   286  		})
   287  
   288  		Context("when the orderer config is bad", func() {
   289  			BeforeEach(func() {
   290  				conf.Orderer.OrdererType = "bad-type"
   291  			})
   292  
   293  			It("wraps and returns the error", func() {
   294  				_, err := encoder.NewChannelGroup(conf)
   295  				Expect(err).To(MatchError("could not create orderer group: unknown orderer type: bad-type"))
   296  			})
   297  
   298  			Context("when the orderer config is missing", func() {
   299  				BeforeEach(func() {
   300  					conf.Orderer = nil
   301  				})
   302  
   303  				It("handles it gracefully", func() {
   304  					_, err := encoder.NewChannelGroup(conf)
   305  					Expect(err).NotTo(HaveOccurred())
   306  				})
   307  			})
   308  		})
   309  
   310  		Context("when the application config is bad", func() {
   311  			BeforeEach(func() {
   312  				conf.Application.Policies["Admins"] = &genesisconfig.Policy{
   313  					Type: "garbage",
   314  				}
   315  			})
   316  
   317  			It("wraps and returns the error", func() {
   318  				_, err := encoder.NewChannelGroup(conf)
   319  				Expect(err).To(MatchError("could not create application group: error adding policies to application group: unknown policy type: garbage"))
   320  			})
   321  		})
   322  
   323  		Context("when the consortium config is bad", func() {
   324  			BeforeEach(func() {
   325  				conf.Consortiums["SampleConsortium"].Organizations = []*genesisconfig.Organization{
   326  					{
   327  						Policies: map[string]*genesisconfig.Policy{
   328  							"garbage-policy": {
   329  								Type: "garbage",
   330  							},
   331  						},
   332  					},
   333  				}
   334  			})
   335  
   336  			It("wraps and returns the error", func() {
   337  				_, err := encoder.NewChannelGroup(conf)
   338  				Expect(err).To(MatchError("could not create consortiums group: failed to create consortium SampleConsortium: failed to create consortium org: 1 - Error loading MSP configuration for org: : unknown MSP type ''"))
   339  			})
   340  		})
   341  	})
   342  
   343  	Describe("NewOrdererGroup", func() {
   344  		var conf *genesisconfig.Orderer
   345  
   346  		BeforeEach(func() {
   347  			conf = &genesisconfig.Orderer{
   348  				OrdererType: "solo",
   349  				Organizations: []*genesisconfig.Organization{
   350  					{
   351  						MSPDir:   "../../../sampleconfig/msp",
   352  						ID:       "SampleMSP",
   353  						MSPType:  "bccsp",
   354  						Name:     "SampleOrg",
   355  						Policies: CreateStandardPolicies(),
   356  					},
   357  				},
   358  				Policies: CreateStandardOrdererPolicies(),
   359  				Capabilities: map[string]bool{
   360  					"FakeCapability": true,
   361  				},
   362  			}
   363  		})
   364  
   365  		It("translates the config into a config group", func() {
   366  			cg, err := encoder.NewOrdererGroup(conf)
   367  			Expect(err).NotTo(HaveOccurred())
   368  			Expect(len(cg.Policies)).To(Equal(4)) // BlockValidation automatically added
   369  			Expect(cg.Policies["Admins"]).NotTo(BeNil())
   370  			Expect(cg.Policies["Readers"]).NotTo(BeNil())
   371  			Expect(cg.Policies["Writers"]).NotTo(BeNil())
   372  			Expect(cg.Policies["BlockValidation"]).NotTo(BeNil())
   373  			Expect(len(cg.Groups)).To(Equal(1))
   374  			Expect(cg.Groups["SampleOrg"]).NotTo(BeNil())
   375  			Expect(len(cg.Values)).To(Equal(5))
   376  			Expect(cg.Values["BatchSize"]).NotTo(BeNil())
   377  			Expect(cg.Values["BatchTimeout"]).NotTo(BeNil())
   378  			Expect(cg.Values["ChannelRestrictions"]).NotTo(BeNil())
   379  			Expect(cg.Values["Capabilities"]).NotTo(BeNil())
   380  		})
   381  
   382  		Context("when the policy definition is bad", func() {
   383  			BeforeEach(func() {
   384  				conf.Policies["Admins"].Rule = "garbage"
   385  			})
   386  
   387  			It("wraps and returns the error", func() {
   388  				_, err := encoder.NewOrdererGroup(conf)
   389  				Expect(err).To(MatchError("error adding policies to orderer group: invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   390  			})
   391  		})
   392  
   393  		Context("when the consensus type is Kafka", func() {
   394  			BeforeEach(func() {
   395  				conf.OrdererType = "kafka"
   396  			})
   397  
   398  			It("adds the kafka brokers key", func() {
   399  				cg, err := encoder.NewOrdererGroup(conf)
   400  				Expect(err).NotTo(HaveOccurred())
   401  				Expect(len(cg.Values)).To(Equal(6))
   402  				Expect(cg.Values["KafkaBrokers"]).NotTo(BeNil())
   403  			})
   404  		})
   405  
   406  		Context("when the consensus type is etcd/raft", func() {
   407  			BeforeEach(func() {
   408  				conf.OrdererType = "etcdraft"
   409  				conf.EtcdRaft = &etcdraft.ConfigMetadata{
   410  					Options: &etcdraft.Options{
   411  						TickInterval: "500ms",
   412  					},
   413  				}
   414  			})
   415  
   416  			It("adds the raft metadata", func() {
   417  				cg, err := encoder.NewOrdererGroup(conf)
   418  				Expect(err).NotTo(HaveOccurred())
   419  				Expect(len(cg.Values)).To(Equal(5))
   420  				consensusType := &ab.ConsensusType{}
   421  				err = proto.Unmarshal(cg.Values["ConsensusType"].Value, consensusType)
   422  				Expect(err).NotTo(HaveOccurred())
   423  				Expect(consensusType.Type).To(Equal("etcdraft"))
   424  				metadata := &etcdraft.ConfigMetadata{}
   425  				err = proto.Unmarshal(consensusType.Metadata, metadata)
   426  				Expect(err).NotTo(HaveOccurred())
   427  				Expect(metadata.Options.TickInterval).To(Equal("500ms"))
   428  			})
   429  
   430  			Context("when the raft configuration is bad", func() {
   431  				BeforeEach(func() {
   432  					conf.EtcdRaft = &etcdraft.ConfigMetadata{
   433  						Consenters: []*etcdraft.Consenter{
   434  							{},
   435  						},
   436  					}
   437  				})
   438  
   439  				It("wraps and returns the error", func() {
   440  					_, err := encoder.NewOrdererGroup(conf)
   441  					Expect(err).To(MatchError("cannot marshal metadata for orderer type etcdraft: cannot load client cert for consenter :0: open : no such file or directory"))
   442  				})
   443  			})
   444  		})
   445  
   446  		Context("when the consensus type is unknown", func() {
   447  			BeforeEach(func() {
   448  				conf.OrdererType = "bad-type"
   449  			})
   450  
   451  			It("returns an error", func() {
   452  				_, err := encoder.NewOrdererGroup(conf)
   453  				Expect(err).To(MatchError("unknown orderer type: bad-type"))
   454  			})
   455  		})
   456  
   457  		Context("when the org definition is bad", func() {
   458  			BeforeEach(func() {
   459  				conf.Organizations[0].MSPType = "garbage"
   460  			})
   461  
   462  			It("wraps and returns the error", func() {
   463  				_, err := encoder.NewOrdererGroup(conf)
   464  				Expect(err).To(MatchError("failed to create orderer org: 1 - Error loading MSP configuration for org: SampleOrg: unknown MSP type 'garbage'"))
   465  			})
   466  		})
   467  	})
   468  
   469  	Describe("NewApplicationGroup", func() {
   470  		var conf *genesisconfig.Application
   471  
   472  		BeforeEach(func() {
   473  			conf = &genesisconfig.Application{
   474  				Organizations: []*genesisconfig.Organization{
   475  					{
   476  						MSPDir:   "../../../sampleconfig/msp",
   477  						ID:       "SampleMSP",
   478  						MSPType:  "bccsp",
   479  						Name:     "SampleOrg",
   480  						Policies: CreateStandardPolicies(),
   481  					},
   482  				},
   483  				ACLs: map[string]string{
   484  					"SomeACL": "SomePolicy",
   485  				},
   486  				Policies: CreateStandardPolicies(),
   487  				Capabilities: map[string]bool{
   488  					"FakeCapability": true,
   489  				},
   490  			}
   491  		})
   492  
   493  		It("translates the config into a config group", func() {
   494  			cg, err := encoder.NewApplicationGroup(conf)
   495  			Expect(err).NotTo(HaveOccurred())
   496  			Expect(len(cg.Policies)).To(Equal(3))
   497  			Expect(cg.Policies["Admins"]).NotTo(BeNil())
   498  			Expect(cg.Policies["Readers"]).NotTo(BeNil())
   499  			Expect(cg.Policies["Writers"]).NotTo(BeNil())
   500  			Expect(len(cg.Groups)).To(Equal(1))
   501  			Expect(cg.Groups["SampleOrg"]).NotTo(BeNil())
   502  			Expect(len(cg.Values)).To(Equal(2))
   503  			Expect(cg.Values["ACLs"]).NotTo(BeNil())
   504  			Expect(cg.Values["Capabilities"]).NotTo(BeNil())
   505  		})
   506  
   507  		Context("when the policy definition is bad", func() {
   508  			BeforeEach(func() {
   509  				conf.Policies["Admins"].Rule = "garbage"
   510  			})
   511  
   512  			It("wraps and returns the error", func() {
   513  				_, err := encoder.NewApplicationGroup(conf)
   514  				Expect(err).To(MatchError("error adding policies to application group: invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   515  			})
   516  		})
   517  
   518  		Context("when the org definition is bad", func() {
   519  			BeforeEach(func() {
   520  				conf.Organizations[0].MSPType = "garbage"
   521  			})
   522  
   523  			It("wraps and returns the error", func() {
   524  				_, err := encoder.NewApplicationGroup(conf)
   525  				Expect(err).To(MatchError("failed to create application org: 1 - Error loading MSP configuration for org SampleOrg: unknown MSP type 'garbage'"))
   526  			})
   527  		})
   528  	})
   529  
   530  	Describe("NewConsortiumOrgGroup", func() {
   531  		var conf *genesisconfig.Organization
   532  
   533  		BeforeEach(func() {
   534  			conf = &genesisconfig.Organization{
   535  				MSPDir:   "../../../sampleconfig/msp",
   536  				ID:       "SampleMSP",
   537  				MSPType:  "bccsp",
   538  				Name:     "SampleOrg",
   539  				Policies: CreateStandardPolicies(),
   540  			}
   541  		})
   542  
   543  		It("translates the config into a config group", func() {
   544  			cg, err := encoder.NewConsortiumOrgGroup(conf)
   545  			Expect(err).NotTo(HaveOccurred())
   546  			Expect(len(cg.Values)).To(Equal(1))
   547  			Expect(cg.Values["MSP"]).NotTo(BeNil())
   548  			Expect(len(cg.Policies)).To(Equal(3))
   549  			Expect(cg.Policies["Admins"]).NotTo(BeNil())
   550  			Expect(cg.Policies["Readers"]).NotTo(BeNil())
   551  			Expect(cg.Policies["Writers"]).NotTo(BeNil())
   552  		})
   553  
   554  		Context("when the org is marked to be skipped as foreign", func() {
   555  			BeforeEach(func() {
   556  				conf.SkipAsForeign = true
   557  			})
   558  
   559  			It("returns an empty org group with mod policy set", func() {
   560  				cg, err := encoder.NewConsortiumOrgGroup(conf)
   561  				Expect(err).NotTo(HaveOccurred())
   562  				Expect(len(cg.Values)).To(Equal(0))
   563  				Expect(len(cg.Policies)).To(Equal(0))
   564  			})
   565  
   566  			Context("even when the MSP dir is invalid/corrupt", func() {
   567  				BeforeEach(func() {
   568  					conf.MSPDir = "garbage"
   569  				})
   570  
   571  				It("returns without error", func() {
   572  					_, err := encoder.NewConsortiumOrgGroup(conf)
   573  					Expect(err).NotTo(HaveOccurred())
   574  				})
   575  			})
   576  		})
   577  
   578  		Context("when dev mode is enabled", func() {
   579  			BeforeEach(func() {
   580  				conf.AdminPrincipal = "Member"
   581  			})
   582  
   583  			It("does not produce an error", func() {
   584  				_, err := encoder.NewConsortiumOrgGroup(conf)
   585  				Expect(err).NotTo(HaveOccurred())
   586  			})
   587  		})
   588  
   589  		Context("when the policy definition is bad", func() {
   590  			BeforeEach(func() {
   591  				conf.Policies["Admins"].Rule = "garbage"
   592  			})
   593  
   594  			It("wraps and returns the error", func() {
   595  				_, err := encoder.NewConsortiumOrgGroup(conf)
   596  				Expect(err).To(MatchError("error adding policies to consortiums org group 'SampleOrg': invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   597  			})
   598  		})
   599  	})
   600  
   601  	Describe("NewOrdererOrgGroup", func() {
   602  		var conf *genesisconfig.Organization
   603  
   604  		BeforeEach(func() {
   605  			conf = &genesisconfig.Organization{
   606  				MSPDir:   "../../../sampleconfig/msp",
   607  				ID:       "SampleMSP",
   608  				MSPType:  "bccsp",
   609  				Name:     "SampleOrg",
   610  				Policies: CreateStandardPolicies(),
   611  				OrdererEndpoints: []string{
   612  					"foo:7050",
   613  					"bar:8050",
   614  				},
   615  			}
   616  		})
   617  
   618  		It("translates the config into a config group", func() {
   619  			cg, err := encoder.NewOrdererOrgGroup(conf)
   620  			Expect(err).NotTo(HaveOccurred())
   621  			Expect(len(cg.Values)).To(Equal(2))
   622  			Expect(cg.Values["MSP"]).NotTo(BeNil())
   623  			Expect(len(cg.Policies)).To(Equal(3))
   624  			Expect(cg.Values["Endpoints"]).NotTo(BeNil())
   625  			Expect(cg.Policies["Admins"]).NotTo(BeNil())
   626  			Expect(cg.Policies["Readers"]).NotTo(BeNil())
   627  			Expect(cg.Policies["Writers"]).NotTo(BeNil())
   628  		})
   629  
   630  		Context("when the org is marked to be skipped as foreign", func() {
   631  			BeforeEach(func() {
   632  				conf.SkipAsForeign = true
   633  			})
   634  
   635  			It("returns an empty org group with mod policy set", func() {
   636  				cg, err := encoder.NewOrdererOrgGroup(conf)
   637  				Expect(err).NotTo(HaveOccurred())
   638  				Expect(len(cg.Values)).To(Equal(0))
   639  				Expect(len(cg.Policies)).To(Equal(0))
   640  			})
   641  
   642  			Context("even when the MSP dir is invalid/corrupt", func() {
   643  				BeforeEach(func() {
   644  					conf.MSPDir = "garbage"
   645  				})
   646  
   647  				It("returns without error", func() {
   648  					_, err := encoder.NewOrdererOrgGroup(conf)
   649  					Expect(err).NotTo(HaveOccurred())
   650  				})
   651  			})
   652  		})
   653  
   654  		Context("when there are no ordering endpoints", func() {
   655  			BeforeEach(func() {
   656  				conf.OrdererEndpoints = []string{}
   657  			})
   658  
   659  			It("does not include the endpoints in the config group", func() {
   660  				cg, err := encoder.NewOrdererOrgGroup(conf)
   661  				Expect(err).NotTo(HaveOccurred())
   662  				Expect(cg.Values["Endpoints"]).To(BeNil())
   663  			})
   664  		})
   665  
   666  		Context("when dev mode is enabled", func() {
   667  			BeforeEach(func() {
   668  				conf.AdminPrincipal = "Member"
   669  			})
   670  
   671  			It("does not produce an error", func() {
   672  				_, err := encoder.NewOrdererOrgGroup(conf)
   673  				Expect(err).NotTo(HaveOccurred())
   674  			})
   675  		})
   676  
   677  		Context("when the policy definition is bad", func() {
   678  			BeforeEach(func() {
   679  				conf.Policies["Admins"].Rule = "garbage"
   680  			})
   681  
   682  			It("wraps and returns the error", func() {
   683  				_, err := encoder.NewOrdererOrgGroup(conf)
   684  				Expect(err).To(MatchError("error adding policies to orderer org group 'SampleOrg': invalid implicit meta policy rule 'garbage': expected two space separated tokens, but got 1"))
   685  			})
   686  		})
   687  	})
   688  
   689  	Describe("NewApplicationOrgGroup", func() {
   690  		var conf *genesisconfig.Organization
   691  
   692  		BeforeEach(func() {
   693  			conf = &genesisconfig.Organization{
   694  				MSPDir:   "../../../sampleconfig/msp",
   695  				ID:       "SampleMSP",
   696  				MSPType:  "bccsp",
   697  				Name:     "SampleOrg",
   698  				Policies: CreateStandardPolicies(),
   699  				AnchorPeers: []*genesisconfig.AnchorPeer{
   700  					{
   701  						Host: "hostname",
   702  						Port: 5555,
   703  					},
   704  				},
   705  			}
   706  		})
   707  
   708  		It("translates the config into a config group", func() {
   709  			cg, err := encoder.NewApplicationOrgGroup(conf)
   710  			Expect(err).NotTo(HaveOccurred())
   711  			Expect(len(cg.Values)).To(Equal(2))
   712  			Expect(cg.Values["MSP"]).NotTo(BeNil())
   713  			Expect(cg.Values["AnchorPeers"]).NotTo(BeNil())
   714  			Expect(len(cg.Policies)).To(Equal(3))
   715  			Expect(cg.Policies["Admins"]).NotTo(BeNil())
   716  			Expect(cg.Policies["Readers"]).NotTo(BeNil())
   717  			Expect(cg.Policies["Writers"]).NotTo(BeNil())
   718  			Expect(len(cg.Values)).To(Equal(2))
   719  			Expect(cg.Values["MSP"]).NotTo(BeNil())
   720  			Expect(cg.Values["AnchorPeers"]).NotTo(BeNil())
   721  		})
   722  
   723  		Context("when the org is marked to be skipped as foreign", func() {
   724  			BeforeEach(func() {
   725  				conf.SkipAsForeign = true
   726  			})
   727  
   728  			It("returns an empty org group with mod policy set", func() {
   729  				cg, err := encoder.NewApplicationOrgGroup(conf)
   730  				Expect(err).NotTo(HaveOccurred())
   731  				Expect(len(cg.Values)).To(Equal(0))
   732  				Expect(len(cg.Policies)).To(Equal(0))
   733  			})
   734  
   735  			Context("even when the MSP dir is invalid/corrupt", func() {
   736  				BeforeEach(func() {
   737  					conf.MSPDir = "garbage"
   738  				})
   739  
   740  				It("returns without error", func() {
   741  					_, err := encoder.NewApplicationOrgGroup(conf)
   742  					Expect(err).NotTo(HaveOccurred())
   743  				})
   744  			})
   745  		})
   746  
   747  		Context("when the policy definition is bad", func() {
   748  			BeforeEach(func() {
   749  				conf.Policies["Admins"].Type = "garbage"
   750  			})
   751  
   752  			It("wraps and returns the error", func() {
   753  				_, err := encoder.NewApplicationOrgGroup(conf)
   754  				Expect(err).To(MatchError("error adding policies to application org group SampleOrg: unknown policy type: garbage"))
   755  			})
   756  		})
   757  
   758  		Context("when the MSP definition is bad", func() {
   759  			BeforeEach(func() {
   760  				conf.MSPDir = "garbage"
   761  			})
   762  
   763  			It("wraps and returns the error", func() {
   764  				_, err := encoder.NewApplicationOrgGroup(conf)
   765  				Expect(err).To(MatchError("1 - Error loading MSP configuration for org SampleOrg: could not load a valid ca certificate from directory garbage/cacerts: stat garbage/cacerts: no such file or directory"))
   766  			})
   767  		})
   768  
   769  		Context("when there are no anchor peers defined", func() {
   770  			BeforeEach(func() {
   771  				conf.AnchorPeers = nil
   772  			})
   773  
   774  			It("does not encode the anchor peers", func() {
   775  				cg, err := encoder.NewApplicationOrgGroup(conf)
   776  				Expect(err).NotTo(HaveOccurred())
   777  				Expect(len(cg.Values)).To(Equal(1))
   778  				Expect(cg.Values["AnchorPeers"]).To(BeNil())
   779  			})
   780  		})
   781  	})
   782  
   783  	Describe("ChannelCreationOperations", func() {
   784  		var (
   785  			conf     *genesisconfig.Profile
   786  			template *cb.ConfigGroup
   787  		)
   788  
   789  		BeforeEach(func() {
   790  			conf = &genesisconfig.Profile{
   791  				Consortium: "MyConsortium",
   792  				Policies:   CreateStandardPolicies(),
   793  				Application: &genesisconfig.Application{
   794  					Organizations: []*genesisconfig.Organization{
   795  						{
   796  							Name:     "SampleOrg",
   797  							MSPDir:   "../../../sampleconfig/msp",
   798  							ID:       "SampleMSP",
   799  							MSPType:  "bccsp",
   800  							Policies: CreateStandardPolicies(),
   801  							AnchorPeers: []*genesisconfig.AnchorPeer{
   802  								{
   803  									Host: "hostname",
   804  									Port: 4444,
   805  								},
   806  							},
   807  						},
   808  					},
   809  					Policies: CreateStandardPolicies(),
   810  				},
   811  			}
   812  
   813  			var err error
   814  			template, err = encoder.DefaultConfigTemplate(conf)
   815  			Expect(err).NotTo(HaveOccurred())
   816  		})
   817  
   818  		Describe("NewChannelCreateConfigUpdate", func() {
   819  			It("translates the config into a config group", func() {
   820  				cg, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
   821  				Expect(err).NotTo(HaveOccurred())
   822  				expected := &cb.ConfigUpdate{
   823  					ChannelId: "channel-id",
   824  					ReadSet: &cb.ConfigGroup{
   825  						Groups: map[string]*cb.ConfigGroup{
   826  							"Application": {
   827  								Groups: map[string]*cb.ConfigGroup{
   828  									"SampleOrg": {},
   829  								},
   830  							},
   831  						},
   832  						Values: map[string]*cb.ConfigValue{
   833  							"Consortium": {},
   834  						},
   835  					},
   836  					WriteSet: &cb.ConfigGroup{
   837  						Groups: map[string]*cb.ConfigGroup{
   838  							"Application": {
   839  								Version:   1,
   840  								ModPolicy: "Admins",
   841  								Groups: map[string]*cb.ConfigGroup{
   842  									"SampleOrg": {},
   843  								},
   844  								Policies: map[string]*cb.ConfigPolicy{
   845  									"Admins": {
   846  										Policy: &cb.Policy{
   847  											Type: int32(cb.Policy_IMPLICIT_META),
   848  											Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   849  												SubPolicy: "Admins",
   850  												Rule:      cb.ImplicitMetaPolicy_ANY,
   851  											}),
   852  										},
   853  										ModPolicy: "Admins",
   854  									},
   855  									"Readers": {
   856  										Policy: &cb.Policy{
   857  											Type: int32(cb.Policy_IMPLICIT_META),
   858  											Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   859  												SubPolicy: "Readers",
   860  												Rule:      cb.ImplicitMetaPolicy_ANY,
   861  											}),
   862  										},
   863  										ModPolicy: "Admins",
   864  									},
   865  									"Writers": {
   866  										Policy: &cb.Policy{
   867  											Type: int32(cb.Policy_IMPLICIT_META),
   868  											Value: protoutil.MarshalOrPanic(&cb.ImplicitMetaPolicy{
   869  												SubPolicy: "Writers",
   870  												Rule:      cb.ImplicitMetaPolicy_ANY,
   871  											}),
   872  										},
   873  										ModPolicy: "Admins",
   874  									},
   875  								},
   876  							},
   877  						},
   878  						Values: map[string]*cb.ConfigValue{
   879  							"Consortium": {
   880  								Value: protoutil.MarshalOrPanic(&cb.Consortium{
   881  									Name: "MyConsortium",
   882  								}),
   883  							},
   884  						},
   885  					},
   886  				}
   887  				Expect(proto.Equal(expected, cg)).To(BeTrue())
   888  			})
   889  
   890  			Context("when the template configuration is not the default", func() {
   891  				BeforeEach(func() {
   892  					differentConf := &genesisconfig.Profile{
   893  						Consortium: "MyConsortium",
   894  						Policies:   CreateStandardPolicies(),
   895  						Application: &genesisconfig.Application{
   896  							Organizations: []*genesisconfig.Organization{
   897  								{
   898  									MSPDir:  "../../../sampleconfig/msp",
   899  									ID:      "SampleMSP",
   900  									MSPType: "bccsp",
   901  									Name:    "SampleOrg",
   902  									AnchorPeers: []*genesisconfig.AnchorPeer{
   903  										{
   904  											Host: "hostname",
   905  											Port: 5555,
   906  										},
   907  									},
   908  									Policies: CreateStandardPolicies(),
   909  								},
   910  							},
   911  							Policies: CreateStandardPolicies(),
   912  						},
   913  					}
   914  
   915  					var err error
   916  					template, err = encoder.DefaultConfigTemplate(differentConf)
   917  					Expect(err).NotTo(HaveOccurred())
   918  				})
   919  
   920  				It("reflects the additional modifications designated by the channel creation profile", func() {
   921  					cg, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
   922  					Expect(err).NotTo(HaveOccurred())
   923  					Expect(cg.WriteSet.Groups["Application"].Groups["SampleOrg"].Values["AnchorPeers"].Version).To(Equal(uint64(1)))
   924  				})
   925  			})
   926  
   927  			Context("when the application config is bad", func() {
   928  				BeforeEach(func() {
   929  					conf.Application.Policies["Admins"].Type = "bad-type"
   930  				})
   931  
   932  				It("returns an error", func() {
   933  					_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
   934  					Expect(err).To(MatchError("could not turn parse profile into channel group: could not create application group: error adding policies to application group: unknown policy type: bad-type"))
   935  				})
   936  
   937  				Context("when the application config is missing", func() {
   938  					BeforeEach(func() {
   939  						conf.Application = nil
   940  					})
   941  
   942  					It("returns an error", func() {
   943  						_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
   944  						Expect(err).To(MatchError("cannot define a new channel with no Application section"))
   945  					})
   946  				})
   947  			})
   948  
   949  			Context("when the consortium is empty", func() {
   950  				BeforeEach(func() {
   951  					conf.Consortium = ""
   952  				})
   953  
   954  				It("returns an error", func() {
   955  					_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
   956  					Expect(err).To(MatchError("cannot define a new channel with no Consortium value"))
   957  				})
   958  			})
   959  
   960  			Context("when an update cannot be computed", func() {
   961  				It("returns an error", func() {
   962  					_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, nil)
   963  					Expect(err).To(MatchError("could not compute update: no channel group included for original config"))
   964  				})
   965  			})
   966  		})
   967  
   968  		Describe("MakeChannelCreationTransaction", func() {
   969  			var fakeSigner *fakes.SignerSerializer
   970  
   971  			BeforeEach(func() {
   972  				fakeSigner = &fakes.SignerSerializer{}
   973  				fakeSigner.SerializeReturns([]byte("fake-creator"), nil)
   974  			})
   975  
   976  			It("returns an encoded and signed tx", func() {
   977  				env, err := encoder.MakeChannelCreationTransaction("channel-id", fakeSigner, conf)
   978  				Expect(err).NotTo(HaveOccurred())
   979  				payload := &cb.Payload{}
   980  				err = proto.Unmarshal(env.Payload, payload)
   981  				Expect(err).NotTo(HaveOccurred())
   982  				configUpdateEnv := &cb.ConfigUpdateEnvelope{}
   983  				err = proto.Unmarshal(payload.Data, configUpdateEnv)
   984  				Expect(err).NotTo(HaveOccurred())
   985  				Expect(len(configUpdateEnv.Signatures)).To(Equal(1))
   986  				Expect(fakeSigner.SerializeCallCount()).To(Equal(2))
   987  				Expect(fakeSigner.SignCallCount()).To(Equal(2))
   988  				Expect(fakeSigner.SignArgsForCall(0)).To(Equal(util.ConcatenateBytes(configUpdateEnv.Signatures[0].SignatureHeader, configUpdateEnv.ConfigUpdate)))
   989  			})
   990  
   991  			Context("when a default config cannot be generated", func() {
   992  				BeforeEach(func() {
   993  					conf.Application = nil
   994  				})
   995  
   996  				It("wraps and returns the error", func() {
   997  					_, err := encoder.MakeChannelCreationTransaction("channel-id", fakeSigner, conf)
   998  					Expect(err).To(MatchError("could not generate default config template: channel template configs must contain an application section"))
   999  				})
  1000  			})
  1001  
  1002  			Context("when the signer cannot create the signature header", func() {
  1003  				BeforeEach(func() {
  1004  					fakeSigner.SerializeReturns(nil, fmt.Errorf("serialize-error"))
  1005  				})
  1006  
  1007  				It("wraps and returns the error", func() {
  1008  					_, err := encoder.MakeChannelCreationTransaction("channel-id", fakeSigner, conf)
  1009  					Expect(err).To(MatchError("creating signature header failed: serialize-error"))
  1010  				})
  1011  			})
  1012  
  1013  			Context("when the signer cannot sign", func() {
  1014  				BeforeEach(func() {
  1015  					fakeSigner.SignReturns(nil, fmt.Errorf("sign-error"))
  1016  				})
  1017  
  1018  				It("wraps and returns the error", func() {
  1019  					_, err := encoder.MakeChannelCreationTransaction("channel-id", fakeSigner, conf)
  1020  					Expect(err).To(MatchError("signature failure over config update: sign-error"))
  1021  				})
  1022  			})
  1023  
  1024  			Context("when no signer is provided", func() {
  1025  				It("returns an encoded tx with no signature", func() {
  1026  					_, err := encoder.MakeChannelCreationTransaction("channel-id", nil, conf)
  1027  					Expect(err).NotTo(HaveOccurred())
  1028  				})
  1029  			})
  1030  
  1031  			Context("when the config is bad", func() {
  1032  				BeforeEach(func() {
  1033  					conf.Consortium = ""
  1034  				})
  1035  
  1036  				It("wraps and returns the error", func() {
  1037  					_, err := encoder.MakeChannelCreationTransaction("channel-id", nil, conf)
  1038  					Expect(err).To(MatchError("config update generation failure: cannot define a new channel with no Consortium value"))
  1039  				})
  1040  			})
  1041  		})
  1042  
  1043  		Describe("MakeChannelCreationTransactionWithSystemChannelContext", func() {
  1044  			var (
  1045  				applicationConf *genesisconfig.Profile
  1046  				sysChannelConf  *genesisconfig.Profile
  1047  			)
  1048  
  1049  			BeforeEach(func() {
  1050  				applicationConf = &genesisconfig.Profile{
  1051  					Consortium: "SampleConsortium",
  1052  					Policies:   CreateStandardPolicies(),
  1053  					Orderer: &genesisconfig.Orderer{
  1054  						OrdererType: "solo",
  1055  						Policies:    CreateStandardOrdererPolicies(),
  1056  					},
  1057  					Application: &genesisconfig.Application{
  1058  						Organizations: []*genesisconfig.Organization{
  1059  							{
  1060  								MSPDir:  "../../../sampleconfig/msp",
  1061  								ID:      "Org1MSP",
  1062  								MSPType: "bccsp",
  1063  								Name:    "Org1",
  1064  								AnchorPeers: []*genesisconfig.AnchorPeer{
  1065  									{
  1066  										Host: "my-peer",
  1067  										Port: 5555,
  1068  									},
  1069  								},
  1070  								Policies: CreateStandardPolicies(),
  1071  							},
  1072  							{
  1073  								MSPDir:   "../../../sampleconfig/msp",
  1074  								ID:       "Org2MSP",
  1075  								MSPType:  "bccsp",
  1076  								Name:     "Org2",
  1077  								Policies: CreateStandardPolicies(),
  1078  							},
  1079  						},
  1080  						Policies: CreateStandardPolicies(),
  1081  					},
  1082  				}
  1083  
  1084  				sysChannelConf = &genesisconfig.Profile{
  1085  					Policies: CreateStandardPolicies(),
  1086  					Orderer: &genesisconfig.Orderer{
  1087  						OrdererType: "kafka",
  1088  						Policies:    CreateStandardOrdererPolicies(),
  1089  					},
  1090  					Consortiums: map[string]*genesisconfig.Consortium{
  1091  						"SampleConsortium": {
  1092  							Organizations: []*genesisconfig.Organization{
  1093  								{
  1094  									MSPDir:   "../../../sampleconfig/msp",
  1095  									ID:       "Org1MSP",
  1096  									MSPType:  "bccsp",
  1097  									Name:     "Org1",
  1098  									Policies: CreateStandardPolicies(),
  1099  								},
  1100  								{
  1101  									MSPDir:   "../../../sampleconfig/msp",
  1102  									ID:       "Org2MSP",
  1103  									MSPType:  "bccsp",
  1104  									Name:     "Org2",
  1105  									Policies: CreateStandardPolicies(),
  1106  								},
  1107  							},
  1108  						},
  1109  					},
  1110  				}
  1111  			})
  1112  
  1113  			It("returns an encoded and signed tx including differences from the system channel", func() {
  1114  				env, err := encoder.MakeChannelCreationTransactionWithSystemChannelContext("channel-id", nil, applicationConf, sysChannelConf)
  1115  				Expect(err).NotTo(HaveOccurred())
  1116  				payload := &cb.Payload{}
  1117  				err = proto.Unmarshal(env.Payload, payload)
  1118  				Expect(err).NotTo(HaveOccurred())
  1119  				configUpdateEnv := &cb.ConfigUpdateEnvelope{}
  1120  				err = proto.Unmarshal(payload.Data, configUpdateEnv)
  1121  				Expect(err).NotTo(HaveOccurred())
  1122  				configUpdate := &cb.ConfigUpdate{}
  1123  				err = proto.Unmarshal(configUpdateEnv.ConfigUpdate, configUpdate)
  1124  				Expect(err).NotTo(HaveOccurred())
  1125  				Expect(configUpdate.WriteSet.Version).To(Equal(uint64(0)))
  1126  				Expect(configUpdate.WriteSet.Groups["Application"].Policies["Admins"].Version).To(Equal(uint64(1)))
  1127  				Expect(configUpdate.WriteSet.Groups["Application"].Groups["Org1"].Version).To(Equal(uint64(1)))
  1128  				Expect(configUpdate.WriteSet.Groups["Application"].Groups["Org1"].Values["AnchorPeers"]).NotTo(BeNil())
  1129  				Expect(configUpdate.WriteSet.Groups["Application"].Groups["Org2"].Version).To(Equal(uint64(0)))
  1130  				Expect(configUpdate.WriteSet.Groups["Orderer"].Values["ConsensusType"].Version).To(Equal(uint64(1)))
  1131  			})
  1132  
  1133  			Context("when the system channel config is bad", func() {
  1134  				BeforeEach(func() {
  1135  					sysChannelConf.Orderer.OrdererType = "garbage"
  1136  				})
  1137  
  1138  				It("wraps and returns the error", func() {
  1139  					_, err := encoder.MakeChannelCreationTransactionWithSystemChannelContext("channel-id", nil, applicationConf, sysChannelConf)
  1140  					Expect(err).To(MatchError("could not parse system channel config: could not create orderer group: unknown orderer type: garbage"))
  1141  				})
  1142  			})
  1143  
  1144  			Context("when the template cannot be computed", func() {
  1145  				BeforeEach(func() {
  1146  					applicationConf.Application = nil
  1147  				})
  1148  
  1149  				It("wraps and returns the error", func() {
  1150  					_, err := encoder.MakeChannelCreationTransactionWithSystemChannelContext("channel-id", nil, applicationConf, sysChannelConf)
  1151  					Expect(err).To(MatchError("could not create config template: supplied channel creation profile does not contain an application section"))
  1152  				})
  1153  			})
  1154  		})
  1155  
  1156  		Describe("DefaultConfigTemplate", func() {
  1157  			var conf *genesisconfig.Profile
  1158  
  1159  			BeforeEach(func() {
  1160  				conf = &genesisconfig.Profile{
  1161  					Policies: CreateStandardPolicies(),
  1162  					Orderer: &genesisconfig.Orderer{
  1163  						OrdererType: "solo",
  1164  						Policies:    CreateStandardOrdererPolicies(),
  1165  					},
  1166  					Application: &genesisconfig.Application{
  1167  						Policies: CreateStandardPolicies(),
  1168  						Organizations: []*genesisconfig.Organization{
  1169  							{
  1170  								Name:          "Org1",
  1171  								SkipAsForeign: true,
  1172  							},
  1173  							{
  1174  								Name:          "Org2",
  1175  								SkipAsForeign: true,
  1176  							},
  1177  						},
  1178  					},
  1179  				}
  1180  			})
  1181  
  1182  			It("returns the default config template", func() {
  1183  				cg, err := encoder.DefaultConfigTemplate(conf)
  1184  				Expect(err).NotTo(HaveOccurred())
  1185  				Expect(len(cg.Groups)).To(Equal(2))
  1186  				Expect(cg.Groups["Orderer"]).NotTo(BeNil())
  1187  				Expect(cg.Groups["Application"]).NotTo(BeNil())
  1188  				Expect(cg.Groups["Application"].Policies).To(BeEmpty())
  1189  				Expect(cg.Groups["Application"].Values).To(BeEmpty())
  1190  				Expect(len(cg.Groups["Application"].Groups)).To(Equal(2))
  1191  			})
  1192  
  1193  			Context("when the config cannot be turned into a channel group", func() {
  1194  				BeforeEach(func() {
  1195  					conf.Orderer.OrdererType = "garbage"
  1196  				})
  1197  
  1198  				It("wraps and returns the error", func() {
  1199  					_, err := encoder.DefaultConfigTemplate(conf)
  1200  					Expect(err).To(MatchError("error parsing configuration: could not create orderer group: unknown orderer type: garbage"))
  1201  				})
  1202  			})
  1203  
  1204  			Context("when the application config is nil", func() {
  1205  				BeforeEach(func() {
  1206  					conf.Application = nil
  1207  				})
  1208  
  1209  				It("returns an error", func() {
  1210  					_, err := encoder.DefaultConfigTemplate(conf)
  1211  					Expect(err).To(MatchError("channel template configs must contain an application section"))
  1212  				})
  1213  			})
  1214  		})
  1215  
  1216  		Describe("ConfigTemplateFromGroup", func() {
  1217  			var (
  1218  				applicationConf *genesisconfig.Profile
  1219  				sysChannelGroup *cb.ConfigGroup
  1220  			)
  1221  
  1222  			BeforeEach(func() {
  1223  				applicationConf = &genesisconfig.Profile{
  1224  					Policies:   CreateStandardPolicies(),
  1225  					Consortium: "SampleConsortium",
  1226  					Orderer: &genesisconfig.Orderer{
  1227  						OrdererType: "solo",
  1228  						Policies:    CreateStandardOrdererPolicies(),
  1229  					},
  1230  					Application: &genesisconfig.Application{
  1231  						Organizations: []*genesisconfig.Organization{
  1232  							{
  1233  								Name:          "Org1",
  1234  								SkipAsForeign: true,
  1235  							},
  1236  							{
  1237  								Name:          "Org2",
  1238  								SkipAsForeign: true,
  1239  							},
  1240  						},
  1241  					},
  1242  				}
  1243  
  1244  				var err error
  1245  				sysChannelGroup, err = encoder.NewChannelGroup(&genesisconfig.Profile{
  1246  					Policies: CreateStandardPolicies(),
  1247  					Orderer: &genesisconfig.Orderer{
  1248  						OrdererType: "kafka",
  1249  						Policies:    CreateStandardOrdererPolicies(),
  1250  					},
  1251  					Consortiums: map[string]*genesisconfig.Consortium{
  1252  						"SampleConsortium": {
  1253  							Organizations: []*genesisconfig.Organization{
  1254  								{
  1255  									Name:          "Org1",
  1256  									SkipAsForeign: true,
  1257  								},
  1258  								{
  1259  									Name:          "Org2",
  1260  									SkipAsForeign: true,
  1261  								},
  1262  							},
  1263  						},
  1264  					},
  1265  				})
  1266  				Expect(err).NotTo(HaveOccurred())
  1267  			})
  1268  
  1269  			It("returns a config template", func() {
  1270  				cg, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1271  				Expect(err).NotTo(HaveOccurred())
  1272  				Expect(len(cg.Groups)).To(Equal(2))
  1273  				Expect(cg.Groups["Orderer"]).NotTo(BeNil())
  1274  				Expect(proto.Equal(cg.Groups["Orderer"], sysChannelGroup.Groups["Orderer"])).To(BeTrue())
  1275  				Expect(cg.Groups["Application"]).NotTo(BeNil())
  1276  				Expect(len(cg.Groups["Application"].Policies)).To(Equal(1))
  1277  				Expect(cg.Groups["Application"].Policies["Admins"]).NotTo(BeNil())
  1278  				Expect(cg.Groups["Application"].Values).To(BeEmpty())
  1279  				Expect(len(cg.Groups["Application"].Groups)).To(Equal(2))
  1280  			})
  1281  
  1282  			Context("when the orderer system channel group has no sub-groups", func() {
  1283  				BeforeEach(func() {
  1284  					sysChannelGroup.Groups = nil
  1285  				})
  1286  
  1287  				It("returns an error", func() {
  1288  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1289  					Expect(err).To(MatchError("supplied system channel group has no sub-groups"))
  1290  				})
  1291  			})
  1292  
  1293  			Context("when the orderer system channel group has no consortiums group", func() {
  1294  				BeforeEach(func() {
  1295  					delete(sysChannelGroup.Groups, "Consortiums")
  1296  				})
  1297  
  1298  				It("returns an error", func() {
  1299  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1300  					Expect(err).To(MatchError("supplied system channel group does not appear to be system channel (missing consortiums group)"))
  1301  				})
  1302  			})
  1303  
  1304  			Context("when the orderer system channel group has no consortiums in the consortiums group", func() {
  1305  				BeforeEach(func() {
  1306  					sysChannelGroup.Groups["Consortiums"].Groups = nil
  1307  				})
  1308  
  1309  				It("returns an error", func() {
  1310  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1311  					Expect(err).To(MatchError("system channel consortiums group appears to have no consortiums defined"))
  1312  				})
  1313  			})
  1314  
  1315  			Context("when the orderer system channel group does not have the requested consortium", func() {
  1316  				BeforeEach(func() {
  1317  					applicationConf.Consortium = "bad-consortium"
  1318  				})
  1319  
  1320  				It("returns an error", func() {
  1321  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1322  					Expect(err).To(MatchError("supplied system channel group is missing 'bad-consortium' consortium"))
  1323  				})
  1324  			})
  1325  
  1326  			Context("when the channel creation profile has no application section", func() {
  1327  				BeforeEach(func() {
  1328  					applicationConf.Application = nil
  1329  				})
  1330  
  1331  				It("returns an error", func() {
  1332  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1333  					Expect(err).To(MatchError("supplied channel creation profile does not contain an application section"))
  1334  				})
  1335  			})
  1336  
  1337  			Context("when the orderer system channel group does not have all the channel creation orgs", func() {
  1338  				BeforeEach(func() {
  1339  					delete(sysChannelGroup.Groups["Consortiums"].Groups["SampleConsortium"].Groups, "Org1")
  1340  				})
  1341  
  1342  				It("returns an error", func() {
  1343  					_, err := encoder.ConfigTemplateFromGroup(applicationConf, sysChannelGroup)
  1344  					Expect(err).To(MatchError("consortium SampleConsortium does not contain member org Org1"))
  1345  				})
  1346  			})
  1347  		})
  1348  
  1349  		Describe("HasSkippedForeignOrgs", func() {
  1350  			var conf *genesisconfig.Profile
  1351  
  1352  			BeforeEach(func() {
  1353  				conf = &genesisconfig.Profile{
  1354  					Orderer: &genesisconfig.Orderer{
  1355  						Organizations: []*genesisconfig.Organization{
  1356  							{
  1357  								Name: "OrdererOrg1",
  1358  							},
  1359  							{
  1360  								Name: "OrdererOrg2",
  1361  							},
  1362  						},
  1363  					},
  1364  					Application: &genesisconfig.Application{
  1365  						Organizations: []*genesisconfig.Organization{
  1366  							{
  1367  								Name: "ApplicationOrg1",
  1368  							},
  1369  							{
  1370  								Name: "ApplicationOrg2",
  1371  							},
  1372  						},
  1373  					},
  1374  					Consortiums: map[string]*genesisconfig.Consortium{
  1375  						"SomeConsortium": {
  1376  							Organizations: []*genesisconfig.Organization{
  1377  								{
  1378  									Name: "ConsortiumOrg1",
  1379  								},
  1380  								{
  1381  									Name: "ConsortiumOrg2",
  1382  								},
  1383  							},
  1384  						},
  1385  					},
  1386  				}
  1387  			})
  1388  
  1389  			It("returns no error if all orgs are not skipped as foreign", func() {
  1390  				err := encoder.HasSkippedForeignOrgs(conf)
  1391  				Expect(err).NotTo(HaveOccurred())
  1392  			})
  1393  
  1394  			Context("when the orderer group has foreign orgs", func() {
  1395  				BeforeEach(func() {
  1396  					conf.Orderer.Organizations[1].SkipAsForeign = true
  1397  				})
  1398  
  1399  				It("returns an error indicating the offending org", func() {
  1400  					err := encoder.HasSkippedForeignOrgs(conf)
  1401  					Expect(err).To(MatchError("organization 'OrdererOrg2' is marked to be skipped as foreign"))
  1402  				})
  1403  			})
  1404  
  1405  			Context("when the application group has foreign orgs", func() {
  1406  				BeforeEach(func() {
  1407  					conf.Application.Organizations[1].SkipAsForeign = true
  1408  				})
  1409  
  1410  				It("returns an error indicating the offending org", func() {
  1411  					err := encoder.HasSkippedForeignOrgs(conf)
  1412  					Expect(err).To(MatchError("organization 'ApplicationOrg2' is marked to be skipped as foreign"))
  1413  				})
  1414  			})
  1415  
  1416  			Context("when the consortium group has foreign orgs", func() {
  1417  				BeforeEach(func() {
  1418  					conf.Consortiums["SomeConsortium"].Organizations[1].SkipAsForeign = true
  1419  				})
  1420  
  1421  				It("returns an error indicating the offending org", func() {
  1422  					err := encoder.HasSkippedForeignOrgs(conf)
  1423  					Expect(err).To(MatchError("organization 'ConsortiumOrg2' is marked to be skipped as foreign"))
  1424  				})
  1425  			})
  1426  		})
  1427  	})
  1428  
  1429  	Describe("Bootstrapper", func() {
  1430  		Describe("NewBootstrapper", func() {
  1431  			var conf *genesisconfig.Profile
  1432  
  1433  			BeforeEach(func() {
  1434  				conf = &genesisconfig.Profile{
  1435  					Policies: CreateStandardPolicies(),
  1436  					Orderer: &genesisconfig.Orderer{
  1437  						OrdererType: "solo",
  1438  						Policies:    CreateStandardOrdererPolicies(),
  1439  					},
  1440  				}
  1441  			})
  1442  
  1443  			It("creates a new bootstrapper for the given config", func() {
  1444  				bs, err := encoder.NewBootstrapper(conf)
  1445  				Expect(err).NotTo(HaveOccurred())
  1446  				Expect(bs).NotTo(BeNil())
  1447  			})
  1448  
  1449  			Context("when the channel config is bad", func() {
  1450  				BeforeEach(func() {
  1451  					conf.Orderer.OrdererType = "bad-type"
  1452  				})
  1453  
  1454  				It("wraps and returns the error", func() {
  1455  					_, err := encoder.NewBootstrapper(conf)
  1456  					Expect(err).To(MatchError("could not create channel group: could not create orderer group: unknown orderer type: bad-type"))
  1457  				})
  1458  			})
  1459  
  1460  			Context("when the channel config contains a foreign org", func() {
  1461  				BeforeEach(func() {
  1462  					conf.Orderer.Organizations = []*genesisconfig.Organization{
  1463  						{
  1464  							Name:          "MyOrg",
  1465  							SkipAsForeign: true,
  1466  						},
  1467  					}
  1468  				})
  1469  
  1470  				It("wraps and returns the error", func() {
  1471  					_, err := encoder.NewBootstrapper(conf)
  1472  					Expect(err).To(MatchError("all org definitions must be local during bootstrapping: organization 'MyOrg' is marked to be skipped as foreign"))
  1473  				})
  1474  			})
  1475  		})
  1476  
  1477  		Describe("New", func() {
  1478  			var conf *genesisconfig.Profile
  1479  
  1480  			BeforeEach(func() {
  1481  				conf = &genesisconfig.Profile{
  1482  					Policies: CreateStandardPolicies(),
  1483  					Orderer: &genesisconfig.Orderer{
  1484  						OrdererType: "solo",
  1485  						Policies:    CreateStandardOrdererPolicies(),
  1486  					},
  1487  				}
  1488  			})
  1489  
  1490  			It("creates a new bootstrapper for the given config", func() {
  1491  				bs := encoder.New(conf)
  1492  				Expect(bs).NotTo(BeNil())
  1493  			})
  1494  
  1495  			Context("when the channel config is bad", func() {
  1496  				BeforeEach(func() {
  1497  					conf.Orderer.OrdererType = "bad-type"
  1498  				})
  1499  
  1500  				It("panics", func() {
  1501  					Expect(func() { encoder.New(conf) }).To(Panic())
  1502  				})
  1503  			})
  1504  		})
  1505  
  1506  		Describe("Functions", func() {
  1507  			var bs *encoder.Bootstrapper
  1508  
  1509  			BeforeEach(func() {
  1510  				bs = encoder.New(&genesisconfig.Profile{
  1511  					Policies: CreateStandardPolicies(),
  1512  					Orderer: &genesisconfig.Orderer{
  1513  						Policies:    CreateStandardOrdererPolicies(),
  1514  						OrdererType: "solo",
  1515  					},
  1516  				})
  1517  			})
  1518  
  1519  			Describe("GenesisBlock", func() {
  1520  				It("produces a new genesis block with a default channel ID", func() {
  1521  					block := bs.GenesisBlock()
  1522  					Expect(block).NotTo(BeNil())
  1523  				})
  1524  			})
  1525  
  1526  			Describe("GenesisBlockForChannel", func() {
  1527  				It("produces a new genesis block with a default channel ID", func() {
  1528  					block := bs.GenesisBlockForChannel("channel-id")
  1529  					Expect(block).NotTo(BeNil())
  1530  				})
  1531  			})
  1532  		})
  1533  	})
  1534  })