github.com/kaituanwang/hyperledger@v2.0.1+incompatible/integration/lifecycle/lifecycle_test.go (about) 1 /* 2 Copyright IBM Corp All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package lifecycle 8 9 import ( 10 "bytes" 11 "io/ioutil" 12 "os" 13 "path/filepath" 14 "syscall" 15 16 docker "github.com/fsouza/go-dockerclient" 17 "github.com/golang/protobuf/proto" 18 "github.com/hyperledger/fabric-protos-go/common" 19 "github.com/hyperledger/fabric/common/tools/protolator" 20 "github.com/hyperledger/fabric/common/tools/protolator/protoext/ordererext" 21 "github.com/hyperledger/fabric/integration/nwo" 22 "github.com/hyperledger/fabric/integration/nwo/commands" 23 "github.com/hyperledger/fabric/integration/nwo/fabricconfig" 24 "github.com/hyperledger/fabric/integration/runner" 25 "github.com/onsi/gomega/gbytes" 26 "github.com/onsi/gomega/gexec" 27 "github.com/tedsuo/ifrit" 28 29 . "github.com/onsi/ginkgo" 30 . "github.com/onsi/gomega" 31 . "github.com/onsi/gomega/gstruct" 32 ) 33 34 var _ = Describe("Lifecycle", func() { 35 var ( 36 client *docker.Client 37 testDir string 38 network *nwo.Network 39 processes = map[string]ifrit.Process{} 40 termFiles []string 41 ) 42 43 BeforeEach(func() { 44 var err error 45 testDir, err = ioutil.TempDir("", "lifecycle") 46 Expect(err).NotTo(HaveOccurred()) 47 48 client, err = docker.NewClientFromEnv() 49 Expect(err).NotTo(HaveOccurred()) 50 51 network = nwo.New(nwo.BasicSolo(), testDir, client, StartPort(), components) 52 53 // Generate config 54 network.GenerateConfigTree() 55 56 // configure only one of four peers (Org1, peer0) to use couchdb. 57 // Note that we do not support a channel with mixed DBs. 58 // However, for testing, it would be fine to use couchdb for one 59 // peer. We're using couchdb here to ensure all supported character 60 // classes in chaincode names/versions work on the supported db types. 61 couchDB := &runner.CouchDB{} 62 couchProcess := ifrit.Invoke(couchDB) 63 Eventually(couchProcess.Ready(), runner.DefaultStartTimeout).Should(BeClosed()) 64 Consistently(couchProcess.Wait()).ShouldNot(Receive()) 65 couchAddr := couchDB.Address() 66 peer := network.Peer("Org1", "peer0") 67 core := network.ReadPeerConfig(peer) 68 core.Ledger.State.StateDatabase = "CouchDB" 69 core.Ledger.State.CouchDBConfig.CouchDBAddress = couchAddr 70 processes[couchDB.Name] = couchProcess 71 setTermFileEnvForBinaryExternalBuilder := func(envKey, termFile string, externalBuilders []*fabricconfig.ExternalBuilder) { 72 os.Setenv(envKey, termFile) 73 for _, e := range externalBuilders { 74 if e.Name == "binary" { 75 e.EnvironmentWhitelist = append(e.EnvironmentWhitelist, envKey) 76 } 77 } 78 } 79 org1TermFile := filepath.Join(testDir, "org1-term-file") 80 setTermFileEnvForBinaryExternalBuilder("ORG1_TERM_FILE", org1TermFile, core.Chaincode.ExternalBuilders) 81 network.WritePeerConfig(peer, core) 82 83 peer = network.Peer("Org2", "peer0") 84 core = network.ReadPeerConfig(peer) 85 org2TermFile := filepath.Join(testDir, "org2-term-file") 86 setTermFileEnvForBinaryExternalBuilder("ORG2_TERM_FILE", org2TermFile, core.Chaincode.ExternalBuilders) 87 network.WritePeerConfig(peer, core) 88 89 termFiles = []string{org1TermFile, org2TermFile} 90 91 // bootstrap the network 92 network.Bootstrap() 93 94 for _, o := range network.Orderers { 95 or := network.OrdererRunner(o) 96 p := ifrit.Invoke(or) 97 processes[o.ID()] = p 98 Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed()) 99 } 100 101 for _, peer := range network.Peers { 102 pr := network.PeerRunner(peer) 103 p := ifrit.Invoke(pr) 104 processes[peer.ID()] = p 105 Eventually(p.Ready(), network.EventuallyTimeout).Should(BeClosed()) 106 } 107 }) 108 109 AfterEach(func() { 110 // Shutdown processes and cleanup 111 for _, p := range processes { 112 p.Signal(syscall.SIGTERM) 113 Eventually(p.Wait(), network.EventuallyTimeout).Should(Receive()) 114 } 115 network.Cleanup() 116 117 os.RemoveAll(testDir) 118 }) 119 120 It("deploys and executes chaincode using _lifecycle and upgrades it", func() { 121 orderer := network.Orderer("orderer") 122 testPeers := network.PeersWithChannel("testchannel") 123 org1peer0 := network.Peer("Org1", "peer0") 124 125 chaincodePath := components.Build("github.com/hyperledger/fabric/integration/chaincode/module") 126 chaincode := nwo.Chaincode{ 127 Name: "My_1st-Chaincode", 128 Version: "Version-0.0", 129 Path: chaincodePath, 130 Lang: "binary", 131 PackageFile: filepath.Join(testDir, "modulecc.tar.gz"), 132 Ctor: `{"Args":["init","a","100","b","200"]}`, 133 ChannelConfigPolicy: "/Channel/Application/Endorsement", 134 Sequence: "1", 135 InitRequired: true, 136 Label: "my_simple_chaincode", 137 } 138 139 By("setting up the channel") 140 network.CreateAndJoinChannels(orderer) 141 network.UpdateChannelAnchors(orderer, "testchannel") 142 network.VerifyMembership(network.PeersWithChannel("testchannel"), "testchannel") 143 nwo.EnableCapabilities(network, "testchannel", "Application", "V2_0", orderer, network.Peer("Org1", "peer0"), network.Peer("Org2", "peer0")) 144 145 By("deploying the chaincode") 146 nwo.PackageChaincodeBinary(chaincode) 147 chaincode.SetPackageIDFromPackageFile() 148 149 nwo.InstallChaincode(network, chaincode, testPeers...) 150 151 By("verifying the installed chaincode package matches the one that was submitted") 152 sess, err := network.PeerAdminSession(testPeers[0], commands.ChaincodeGetInstalledPackage{ 153 PackageID: chaincode.PackageID, 154 OutputDirectory: testDir, 155 }) 156 Expect(err).NotTo(HaveOccurred()) 157 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 158 fileBytes, err := ioutil.ReadFile(chaincode.PackageFile) 159 Expect(err).NotTo(HaveOccurred()) 160 fileBytesFromPeer, err := ioutil.ReadFile(filepath.Join(network.RootDir, chaincode.PackageID+".tar.gz")) 161 Expect(err).NotTo(HaveOccurred()) 162 Expect(fileBytesFromPeer).To(Equal(fileBytes)) 163 164 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...) 165 166 nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...) 167 nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...) 168 nwo.InitChaincode(network, "testchannel", orderer, chaincode, testPeers...) 169 170 By("ensuring the chaincode can be invoked and queried") 171 endorsers := []*nwo.Peer{ 172 network.Peer("Org1", "peer0"), 173 network.Peer("Org2", "peer0"), 174 } 175 RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 100, endorsers...) 176 177 By("setting a bad package ID to temporarily disable endorsements on org1") 178 savedPackageID := chaincode.PackageID 179 // note that in theory it should be sufficient to set it to an 180 // empty string, but the ApproveChaincodeForMyOrg 181 // function fills the packageID field if empty 182 chaincode.PackageID = "bad" 183 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer0) 184 185 By("querying the chaincode and expecting the invocation to fail") 186 sess, err = network.PeerUserSession(org1peer0, "User1", commands.ChaincodeQuery{ 187 ChannelID: "testchannel", 188 Name: "My_1st-Chaincode", 189 Ctor: `{"Args":["query","a"]}`, 190 }) 191 Expect(err).NotTo(HaveOccurred()) 192 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1)) 193 Expect(sess.Err).To(gbytes.Say("Error: endorsement failure during query. response: status:500 " + 194 "message:\"make sure the chaincode My_1st-Chaincode has been successfully defined on channel testchannel and try " + 195 "again: chaincode definition for 'My_1st-Chaincode' exists, but chaincode is not installed\"")) 196 197 By("setting the correct package ID to restore the chaincode") 198 chaincode.PackageID = savedPackageID 199 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, org1peer0) 200 201 By("querying the chaincode and expecting the invocation to succeed") 202 sess, err = network.PeerUserSession(org1peer0, "User1", commands.ChaincodeQuery{ 203 ChannelID: "testchannel", 204 Name: "My_1st-Chaincode", 205 Ctor: `{"Args":["query","a"]}`, 206 }) 207 Expect(err).NotTo(HaveOccurred()) 208 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 209 Expect(sess).To(gbytes.Say("90")) 210 211 By("upgrading the chaincode to sequence 2 using a new chaincode package") 212 previousLabel := chaincode.Label 213 previousPackageID := chaincode.PackageID 214 chaincode.Label = "my_simple_chaincode_updated" 215 chaincode.PackageFile = filepath.Join(testDir, "modulecc-updated.tar.gz") 216 chaincode.Sequence = "2" 217 nwo.PackageChaincodeBinary(chaincode) 218 chaincode.SetPackageIDFromPackageFile() 219 nwo.InstallChaincode(network, chaincode, testPeers...) 220 221 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, testPeers...) 222 223 nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), testPeers...) 224 nwo.CommitChaincode(network, "testchannel", orderer, chaincode, testPeers[0], testPeers...) 225 226 By("listing the installed chaincodes and verifying the channel/chaincode definitions that are using the chaincode package") 227 nwo.QueryInstalledReferences(network, "testchannel", chaincode.Label, chaincode.PackageID, network.Peer("Org2", "peer0"), []string{"My_1st-Chaincode", "Version-0.0"}) 228 229 By("checking for term files that are written when the chaincode is stopped via SIGTERM") 230 for _, termFile := range termFiles { 231 Expect(termFile).To(BeARegularFile()) 232 } 233 234 By("ensuring the previous chaincode package is no longer referenced by a chaincode definition on the channel") 235 Expect(nwo.QueryInstalled(network, network.Peer("Org2", "peer0"))()).To( 236 ContainElement(MatchFields(IgnoreExtras, 237 Fields{ 238 "Label": Equal(previousLabel), 239 "PackageId": Equal(previousPackageID), 240 "References": Not(HaveKey("testchannel")), 241 }, 242 )), 243 ) 244 245 By("ensuring the chaincode can still be invoked and queried") 246 RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 90, endorsers...) 247 248 By("deploying another chaincode using the same chaincode package") 249 anotherChaincode := nwo.Chaincode{ 250 Name: "Your_Chaincode", 251 Version: "Version+0_0", 252 Path: chaincodePath, 253 Lang: "binary", 254 PackageFile: filepath.Join(testDir, "modulecc.tar.gz"), 255 Ctor: `{"Args":["init","a","100","b","200"]}`, 256 ChannelConfigPolicy: "/Channel/Application/Endorsement", 257 Sequence: "1", 258 InitRequired: true, 259 Label: "my_simple_chaincode", 260 } 261 nwo.DeployChaincode(network, "testchannel", orderer, anotherChaincode) 262 263 By("listing the installed chaincodes and verifying the channel/chaincode definitions that are using the chaincode package") 264 anotherChaincode.SetPackageIDFromPackageFile() 265 nwo.QueryInstalledReferences(network, "testchannel", anotherChaincode.Label, anotherChaincode.PackageID, network.Peer("Org2", "peer0"), []string{"Your_Chaincode", "Version+0_0"}) 266 267 By("adding a new org") 268 org3 := &nwo.Organization{ 269 MSPID: "Org3MSP", 270 Name: "Org3", 271 Domain: "org3.example.com", 272 EnableNodeOUs: true, 273 Users: 2, 274 CA: &nwo.CA{ 275 Hostname: "ca", 276 }, 277 } 278 279 org3peer0 := &nwo.Peer{ 280 Name: "peer0", 281 Organization: "Org3", 282 Channels: testPeers[0].Channels, 283 } 284 285 network.AddOrg(org3, org3peer0) 286 GenerateOrgUpdateMaterials(network, org3peer0) 287 288 By("starting the org3 peer") 289 pr := network.PeerRunner(org3peer0) 290 org3Process := ifrit.Invoke(pr) 291 processes[org3peer0.ID()] = org3Process 292 Eventually(org3Process.Ready(), network.EventuallyTimeout).Should(BeClosed()) 293 294 By("updating the channel config to include org3") 295 // get the current channel config 296 currentConfig := nwo.GetConfig(network, testPeers[0], orderer, "testchannel") 297 updatedConfig := proto.Clone(currentConfig).(*common.Config) 298 299 // get the configtx info for org3 300 sess, err = network.ConfigTxGen(commands.PrintOrg{ 301 ConfigPath: network.RootDir, 302 PrintOrg: "Org3", 303 }) 304 Expect(err).NotTo(HaveOccurred()) 305 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 306 org3Group := &ordererext.DynamicOrdererOrgGroup{ConfigGroup: &common.ConfigGroup{}} 307 err = protolator.DeepUnmarshalJSON(bytes.NewBuffer(sess.Out.Contents()), org3Group) 308 Expect(err).NotTo(HaveOccurred()) 309 310 // update the channel config to include org3 311 updatedConfig.ChannelGroup.Groups["Application"].Groups["Org3"] = org3Group.ConfigGroup 312 nwo.UpdateConfig(network, orderer, "testchannel", currentConfig, updatedConfig, true, testPeers[0], testPeers...) 313 314 By("joining the org3 peers to the channel") 315 network.JoinChannel("testchannel", orderer, org3peer0) 316 317 // update testPeers now that org3 has joined 318 testPeers = network.PeersWithChannel("testchannel") 319 320 // wait until all peers, particularly those in org3, have received the block 321 // containing the updated config 322 maxLedgerHeight := nwo.GetMaxLedgerHeight(network, "testchannel", testPeers...) 323 nwo.WaitUntilEqualLedgerHeight(network, "testchannel", maxLedgerHeight, testPeers...) 324 325 By("querying definitions by org3 before performing any chaincode actions") 326 sess, err = network.PeerAdminSession(network.Peer("Org2", "peer0"), commands.ChaincodeListCommitted{ 327 ChannelID: "testchannel", 328 }) 329 Expect(err).NotTo(HaveOccurred()) 330 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 331 332 By("installing the chaincode to the org3 peers") 333 nwo.InstallChaincode(network, chaincode, org3peer0) 334 335 By("ensuring org3 peers do not execute the chaincode before approving the definition") 336 org3AndOrg1PeerAddresses := []string{ 337 network.PeerAddress(org3peer0, nwo.ListenPort), 338 network.PeerAddress(org1peer0, nwo.ListenPort), 339 } 340 341 sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{ 342 ChannelID: "testchannel", 343 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 344 Name: "My_1st-Chaincode", 345 Ctor: `{"Args":["invoke","a","b","10"]}`, 346 PeerAddresses: org3AndOrg1PeerAddresses, 347 WaitForEvent: true, 348 }) 349 Expect(err).NotTo(HaveOccurred()) 350 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1)) 351 Expect(sess.Err).To(gbytes.Say("chaincode definition for 'My_1st-Chaincode' at sequence 2 on channel 'testchannel' has not yet been approved by this org")) 352 353 By("org3 approving the chaincode definition") 354 nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, network.PeersInOrg("Org3")...) 355 nwo.EnsureChaincodeCommitted(network, "testchannel", chaincode.Name, chaincode.Version, chaincode.Sequence, []*nwo.Organization{network.Organization("Org1"), network.Organization("Org2"), network.Organization("Org3")}, org3peer0) 356 357 By("ensuring chaincode can be invoked and queried by org3") 358 org3andOrg1Endorsers := []*nwo.Peer{ 359 network.Peer("Org3", "peer0"), 360 network.Peer("Org1", "peer0"), 361 } 362 RunQueryInvokeQuery(network, orderer, "My_1st-Chaincode", 80, org3andOrg1Endorsers...) 363 364 By("deploying a chaincode without an endorsement policy specified") 365 chaincode = nwo.Chaincode{ 366 Name: "defaultpolicycc", 367 Version: "0.0", 368 Path: chaincodePath, 369 Lang: "binary", 370 PackageFile: filepath.Join(testDir, "modulecc.tar.gz"), 371 Ctor: `{"Args":["init","a","100","b","200"]}`, 372 Sequence: "1", 373 InitRequired: true, 374 Label: "my_simple_chaincode", 375 } 376 377 nwo.DeployChaincode(network, "testchannel", orderer, chaincode) 378 379 By("attempting to invoke the chaincode without a majority") 380 sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{ 381 ChannelID: "testchannel", 382 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 383 Name: "defaultpolicycc", 384 Ctor: `{"Args":["invoke","a","b","10"]}`, 385 WaitForEvent: true, 386 }) 387 Expect(err).ToNot(HaveOccurred()) 388 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(1)) 389 Expect(sess.Err).To(gbytes.Say(`\QError: transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)\E`)) 390 391 By("attempting to invoke the chaincode with a majority") 392 sess, err = network.PeerUserSession(org3peer0, "User1", commands.ChaincodeInvoke{ 393 ChannelID: "testchannel", 394 Orderer: network.OrdererAddress(orderer, nwo.ListenPort), 395 Name: "defaultpolicycc", 396 Ctor: `{"Args":["invoke","a","b","10"]}`, 397 PeerAddresses: org3AndOrg1PeerAddresses, 398 WaitForEvent: true, 399 }) 400 Expect(err).NotTo(HaveOccurred()) 401 Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0)) 402 Expect(sess.Err).To(gbytes.Say(`\Qcommitted with status (VALID)\E`)) 403 Expect(sess.Err).To(gbytes.Say(`Chaincode invoke successful. result: status:200`)) 404 }) 405 })