Skip to content

Commit

Permalink
FAB-12991 kafka2raft e2e tests green path
Browse files Browse the repository at this point in the history
This task focuses on testing the consensus-type migration "green" path,
that was introduced in FAB-13264.

The main contribution is in migration_test.go, which defines 3 test-cases
that test the green path. This is not the complete test suite for migration.
It is introduced in this stage to allow reviewers to get the full picture
of the feature defined in FAB-13264. The tests for the abort path and failure
scenarios will be added in later tasks.

The three test-cases are:

1. A test that executes the migration flow on the Kafka side
   (from START-TX until COMMIT-TX), on the system channel only.
2. A test that executes the migration flow on the Kafka side
   (from START-TX, CONTEXT-TX until COMMIT-TX), on the system
   channel and a single application channel. 
3. A test that executes the migration flow on the Raft side
   (from START-TX, CONTEXT-TX until COMMIT-TX, followed by restart
   of the orderer), on the system channel and a two application channel.

The tests are somewhat overlapping but are verifying different aspects of
the expected behavior. Overall, the tests verify that the flow of:

 - START-TX => CONTEXT-TX (x #std-channels) =>COMMIT-TX => Restart
   => (optional NONE-TX)

results in a functional etcdraft-based ordering service. That is, normal
transactions can be executed, and new channels can be created.
 

The task introduces some minor changes to the nwo test framework in order to
support the testing of the new feature:

 - Add OrdererCapabilites to Config, since kafka-to-raft migration is gates
   by a new V2_0 capability
   - add the following to tests that read the network config from file

     orderercapabilities:
       v20: false

 - Adds method to verify failure to update the OrdererConfig
 - Extends the configtx template to include support for the V2_0 orderer
   capability
 - Extend the network.go to
   - support V2_0 orderer capability
   - verify channel creation is blocked
   - support ConsensusType.Type changes
 - Extend standard_networks.go to
   - Support V2_0 orderer capability
   - define a Kafka2Raft and Kafka2RaftMultiChannel configurations for
     migration tests

Change-Id: I043b133b4c716f3bf53512f1999c7dfbc8aa67bb
Signed-off-by: Yoav Tock <tock@il.ibm.com>
  • Loading branch information
tock-ibm committed Feb 17, 2019
1 parent 0504983 commit 05485b9
Show file tree
Hide file tree
Showing 9 changed files with 633 additions and 36 deletions.
3 changes: 3 additions & 0 deletions integration/discovery/testdata/network.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ orderers:
- name: orderer
organization: orderer-org

orderercapabilities:
v20: false

channels:
- name: testchannel
profile: ThreeOrgsChannel
Expand Down
524 changes: 524 additions & 0 deletions integration/e2e/migration_test.go

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions integration/nwo/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ package nwo
// Config holds the basic information needed to generate
// fabric configuration files.
type Config struct {
Organizations []*Organization `yaml:"organizations,omitempty"`
Consortiums []*Consortium `yaml:"consortiums,omitempty"`
SystemChannel *SystemChannel `yaml:"system_channel,omitempty"`
Channels []*Channel `yaml:"channels,omitempty"`
Consensus *Consensus `yaml:"consensus,omitempty"`
Orderers []*Orderer `yaml:"orderers,omitempty"`
Peers []*Peer `yaml:"peers,omitempty"`
Profiles []*Profile `yaml:"profiles,omitempty"`
Templates *Templates `yaml:"templates,omitempty"`
Organizations []*Organization `yaml:"organizations,omitempty"`
Consortiums []*Consortium `yaml:"consortiums,omitempty"`
SystemChannel *SystemChannel `yaml:"system_channel,omitempty"`
Channels []*Channel `yaml:"channels,omitempty"`
Consensus *Consensus `yaml:"consensus,omitempty"`
OrdererCap *OrdererCapabilities `yaml:"orderercapabilities,omitempty"`
Orderers []*Orderer `yaml:"orderers,omitempty"`
Peers []*Peer `yaml:"peers,omitempty"`
Profiles []*Profile `yaml:"profiles,omitempty"`
Templates *Templates `yaml:"templates,omitempty"`
}

func (c *Config) RemovePeer(orgName, peerName string) {
Expand Down
76 changes: 50 additions & 26 deletions integration/nwo/configblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,35 +127,11 @@ func UpdateConfig(n *Network, orderer *Orderer, channel string, current, updated
func UpdateOrdererConfig(n *Network, orderer *Orderer, channel string, current, updated *common.Config, submitter *Peer, additionalSigners ...*Orderer) {
tempDir, err := ioutil.TempDir("", "updateConfig")
Expect(err).NotTo(HaveOccurred())
defer os.RemoveAll(tempDir)

// compute update
configUpdate, err := update.Compute(current, updated)
Expect(err).NotTo(HaveOccurred())
configUpdate.ChannelId = channel

signedEnvelope, err := utils.CreateSignedEnvelope(
common.HeaderType_CONFIG_UPDATE,
channel,
nil, // local signer
&common.ConfigUpdateEnvelope{ConfigUpdate: utils.MarshalOrPanic(configUpdate)},
0, // message version
0, // epoch
)
Expect(err).NotTo(HaveOccurred())
Expect(signedEnvelope).NotTo(BeNil())

updateFile := filepath.Join(tempDir, "update.pb")
err = ioutil.WriteFile(updateFile, utils.MarshalOrPanic(signedEnvelope), 0600)
Expect(err).NotTo(HaveOccurred())
defer os.RemoveAll(tempDir)

for _, signer := range additionalSigners {
sess, err := n.OrdererAdminSession(signer, submitter, commands.SignConfigTx{File: updateFile})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
}
computeUpdateOrdererConfig(updateFile, n, channel, current, updated, submitter, additionalSigners...)

// get current configuration block number
currentBlockNumber := CurrentConfigBlockNumber(n, submitter, orderer, channel)

Eventually(func() string {
Expand Down Expand Up @@ -207,6 +183,54 @@ func CurrentConfigBlockNumber(n *Network, peer *Peer, orderer *Orderer, channel
return configBlock.Header.Number
}

// UpdateOrdererConfigFail computes, signs, and submits a configuration update which requires orderers signature
// and waits for the update to FAIL.
func UpdateOrdererConfigFail(n *Network, orderer *Orderer, channel string, current, updated *common.Config, submitter *Peer, additionalSigners ...*Orderer) {
tempDir, err := ioutil.TempDir("", "updateConfig")
Expect(err).NotTo(HaveOccurred())
updateFile := filepath.Join(tempDir, "update.pb")
defer os.RemoveAll(tempDir)

computeUpdateOrdererConfig(updateFile, n, channel, current, updated, submitter, additionalSigners...)

//session should not return with a zero exit code nor with a success response
sess, err := n.OrdererAdminSession(orderer, submitter, commands.ChannelUpdate{
ChannelID: channel,
Orderer: n.OrdererAddress(orderer, ListenPort),
File: updateFile,
})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).ShouldNot(gexec.Exit(0))
Expect(sess.Err).NotTo(gbytes.Say("Successfully submitted channel update"))
}

func computeUpdateOrdererConfig(updateFile string, n *Network, channel string, current, updated *common.Config, submitter *Peer, additionalSigners ...*Orderer) {
// compute update
configUpdate, err := update.Compute(current, updated)
Expect(err).NotTo(HaveOccurred())
configUpdate.ChannelId = channel

signedEnvelope, err := utils.CreateSignedEnvelope(
common.HeaderType_CONFIG_UPDATE,
channel,
nil, // local signer
&common.ConfigUpdateEnvelope{ConfigUpdate: utils.MarshalOrPanic(configUpdate)},
0, // message version
0, // epoch
)
Expect(err).NotTo(HaveOccurred())
Expect(signedEnvelope).NotTo(BeNil())

err = ioutil.WriteFile(updateFile, utils.MarshalOrPanic(signedEnvelope), 0600)
Expect(err).NotTo(HaveOccurred())

for _, signer := range additionalSigners {
sess, err := n.OrdererAdminSession(signer, submitter, commands.SignConfigTx{File: updateFile})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, n.EventuallyTimeout).Should(gexec.Exit(0))
}
}

// UnmarshalBlockFromFile unmarshals a proto encoded block from a file.
func UnmarshalBlockFromFile(blockFile string) *common.Block {
blockBytes, err := ioutil.ReadFile(blockFile)
Expand Down
4 changes: 4 additions & 0 deletions integration/nwo/configtx_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ Profiles:{{ range .Profiles }}
PreferredMaxBytes: 512 KB
Capabilities:
V1_1: true
{{- if $w.OrdererCap.V2_0 }}
V2_0: true
{{- end }}
{{- if eq $w.Consensus.Type "kafka" }}
Kafka:
Brokers:{{ range $w.BrokerAddresses "HostPort" }}
Expand Down
34 changes: 33 additions & 1 deletion integration/nwo/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ func (o Orderer) ID() string {
return fmt.Sprintf("%s.%s", o.Organization, o.Name)
}

type OrdererCapabilities struct {
V2_0 bool `yaml:"v20,omitempty"`
}

// Peer defines a peer instance, it's owning organization, and the list of
// channels that the peer shoudl be joined to.
type Peer struct {
Expand Down Expand Up @@ -144,6 +148,7 @@ type Network struct {
SystemChannel *SystemChannel
Channels []*Channel
Consensus *Consensus
OrdererCap *OrdererCapabilities
Orderers []*Orderer
Peers []*Peer
Profiles []*Profile
Expand Down Expand Up @@ -172,6 +177,7 @@ func New(c *Config, rootDir string, client *docker.Client, startPort int, compon

Organizations: c.Organizations,
Consensus: c.Consensus,
OrdererCap: c.OrdererCap,
Orderers: c.Orderers,
Peers: c.Peers,
SystemChannel: c.SystemChannel,
Expand Down Expand Up @@ -732,6 +738,31 @@ func (n *Network) CreateChannel(channelName string, o *Orderer, p *Peer) {
Eventually(createChannel, n.EventuallyTimeout).Should(Equal(0))
}

// CreateChannelFail will submit an existing create channel transaction to the
// specified orderer, but expect to FAIL. The channel transaction must exist
// at the location returned by CreateChannelTxPath.
//
// The orderer must be running when this is called.
func (n *Network) CreateChannelFail(o *Orderer, channelName string) {
peers := n.PeersWithChannel(channelName)
if len(peers) == 0 {
return
}

createChannelFail := func() int {
sess, err := n.PeerAdminSession(peers[0], commands.ChannelCreate{
ChannelID: channelName,
Orderer: n.OrdererAddress(o, ListenPort),
File: n.CreateChannelTxPath(channelName),
OutputBlock: "/dev/null",
})
Expect(err).NotTo(HaveOccurred())
return sess.Wait(n.EventuallyTimeout).ExitCode()
}

Eventually(createChannelFail, n.EventuallyTimeout).ShouldNot(Equal(0))
}

// JoinChannel will join peers to the specified channel. The orderer is used to
// obtain the current configuration block for the channel.
//
Expand Down Expand Up @@ -879,7 +910,8 @@ func (n *Network) OrdererRunner(o *Orderer) *ginkgomon.Runner {
StartCheckTimeout: 15 * time.Second,
}

if n.Consensus.Brokers != 0 {
//After consensus-type migration, the #brokers is >0, but the type is etcdraft
if n.Consensus.Type == "kafka" && n.Consensus.Brokers != 0 {
config.StartCheck = "Start phase completed successfully"
config.StartCheckTimeout = 30 * time.Second
}
Expand Down
3 changes: 3 additions & 0 deletions integration/nwo/solo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ orderers:
- name: orderer0
organization: orderer-org

orderercapabilities:
v20: false

channels:
- name: testchannel
profile: TwoOrgsChannel
Expand Down
3 changes: 3 additions & 0 deletions integration/nwo/standard_networks.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ func BasicSolo() *Config {
Consensus: &Consensus{
Type: "solo",
},
OrdererCap: &OrdererCapabilities{
V2_0: false,
},
SystemChannel: &SystemChannel{
Name: "systemchannel",
Profile: "TwoOrgsOrdererGenesis",
Expand Down
3 changes: 3 additions & 0 deletions integration/pvtdata/testdata/network.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ orderers:
- name: orderer
organization: orderer-org

orderercapabilities:
v20: false

channels:
- name: testchannel
profile: ThreeOrgsChannel
Expand Down

0 comments on commit 05485b9

Please sign in to comment.