github.com/anjalikarhana/fabric@v2.1.1+incompatible/internal/configtxgen/encoder/encoder_test.go (about)

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