Skip to content

Commit

Permalink
Updates to external chaincode integration tests (hyperledger#1561)
Browse files Browse the repository at this point in the history
- Remove TestChaincodeAsExternalService function as the test is not a
  standalone suite
- Reduce number of files by using a single JSON document for chaincode
  configuration
- Exercise queries and invokes in the chaincode
- Reuse the 'binary' builder for client and server chaincode
- Rename chaincode from 'extcc' to 'server'

Signed-off-by: Matthew Sykes <[email protected]>
  • Loading branch information
sykesm committed Jul 9, 2020
1 parent 9ac4e5b commit 8f882a3
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 329 deletions.
53 changes: 0 additions & 53 deletions integration/chaincode/extcc/main.go

This file was deleted.

61 changes: 61 additions & 0 deletions integration/chaincode/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"

"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric/integration/chaincode/simple"
)

type config struct {
ListenAddress string `json:"listen_address,omitempty"`
Key string `json:"key,omitempty"` // PEM encoded key
Cert string `json:"cert,omitempty"` // PEM encoded certificate
CA string `json:"ca,omitempty"` // PEM encode CA certificate
}

func main() {
if len(os.Args) < 2 {
fmt.Println("usage: <package-id>")
os.Exit(1)
}

configData, err := ioutil.ReadFile("config.json")
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot read config file: %s", err)
os.Exit(2)
}

var config config
if err := json.Unmarshal(configData, &config); err != nil {
fmt.Fprintf(os.Stderr, "Cannot read config file: %s", err)
os.Exit(2)
}

server := &shim.ChaincodeServer{
CCID: os.Args[1],
Address: config.ListenAddress,
CC: new(simple.SimpleChaincode),
TLSProps: shim.TLSProperties{
Key: []byte(config.Key),
Cert: []byte(config.Cert),
ClientCACerts: []byte(config.CA),
},
}

// do not modify - needed for integration test
fmt.Printf("Starting chaincode %s at %s\n", server.CCID, server.Address)
err = server.Start()
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
183 changes: 183 additions & 0 deletions integration/e2e/chaincode_server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package e2e

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"

"github.com/hyperledger/fabric/common/crypto/tlsgen"
"github.com/hyperledger/fabric/core/container/externalbuilder"
"github.com/hyperledger/fabric/integration/nwo"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/tedsuo/ifrit"
"github.com/tedsuo/ifrit/ginkgomon"
)

var _ = Describe("ChaincodeAsExternalServer", func() {
var (
testDir string
network *nwo.Network
chaincode nwo.Chaincode
chaincodeServerAddress string
assetDir string
process ifrit.Process
ccserver ifrit.Process
)

BeforeEach(func() {
var err error
testDir, err = ioutil.TempDir("", "external-chaincode-server")
Expect(err).NotTo(HaveOccurred())

network = nwo.New(nwo.BasicSolo(), testDir, nil, StartPort(), components)
network.GenerateConfigTree()
network.Bootstrap()

// Create the configuration
chaincodeServerAddress = fmt.Sprintf("127.0.0.1:%d", network.ReservePort())
connData, serverKeyPair := generateChaincodeConfig(chaincodeServerAddress)

// Create directory for configuration files
assetDir, err = ioutil.TempDir(testDir, "assets")
Expect(err).NotTo(HaveOccurred())

// Write the config files
connJSON, err := json.Marshal(connData)
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(assetDir, "connection.json"), connJSON, 0644)
Expect(err).NotTo(HaveOccurred())

configJSON, err := json.Marshal(serverKeyPair)
Expect(err).NotTo(HaveOccurred())
err = ioutil.WriteFile(filepath.Join(assetDir, "config.json"), configJSON, 0644)
Expect(err).NotTo(HaveOccurred())

// Setup the network
networkRunner := network.NetworkGroupRunner()
process = ifrit.Invoke(networkRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())

network.CreateAndJoinChannel(network.Orderer("orderer"), "testchannel")
nwo.EnableCapabilities(
network,
"testchannel",
"Application", "V2_0",
network.Orderer("orderer"),
network.Peer("Org1", "peer0"), network.Peer("Org2", "peer0"),
)

chaincode = nwo.Chaincode{
Name: "mycc",
Version: "0.0",
Path: components.Build("github.com/hyperledger/fabric/integration/chaincode/server"),
Lang: "binary",
PackageFile: filepath.Join(testDir, "server.tar.gz"),
Ctor: `{"Args":["init","a","100","b","200"]}`,
InitRequired: true,
SignaturePolicy: `AND ('Org1MSP.member','Org2MSP.member')`,
Sequence: "1",
Label: "my_server_chaincode",
CodeFiles: map[string]string{
filepath.Join(assetDir, "connection.json"): "connection.json",
filepath.Join(assetDir, "config.json"): "config.json",
},
}
})

AfterEach(func() {
if ccserver != nil {
ccserver.Signal(syscall.SIGTERM)
Eventually(ccserver.Wait(), network.EventuallyTimeout).Should(Receive())
}

if process != nil {
process.Signal(syscall.SIGTERM)
Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
}
if network != nil {
network.Cleanup()
}
os.RemoveAll(testDir)
})

It("executes a basic solo network with 2 orgs and external chaincode server", func() {
orderer := network.Orderer("orderer")
peer := network.Peer("Org1", "peer0")
peers := network.PeersWithChannel("testchannel")

By("packaging and installing the chaincode")
nwo.PackageAndInstallChaincode(network, chaincode, peers...)
chaincode.SetPackageIDFromPackageFile()

By("approving and committing the chaincode")
nwo.ApproveChaincodeForMyOrg(network, "testchannel", orderer, chaincode, peers...)
nwo.CheckCommitReadinessUntilReady(network, "testchannel", chaincode, network.PeerOrgs(), peers...)
nwo.CommitChaincode(network, "testchannel", orderer, chaincode, peer, peers...)

By("starting the chaincode server")
ccserver = ifrit.Invoke(ginkgomon.New(ginkgomon.Config{
Name: chaincode.PackageID,
Command: &exec.Cmd{
Path: chaincode.Path,
Args: []string{chaincode.Path, chaincode.PackageID, chaincodeServerAddress},
Dir: assetDir,
},
StartCheck: `Starting chaincode ` + chaincode.PackageID + ` at ` + chaincodeServerAddress,
StartCheckTimeout: 15 * time.Second,
}))
Eventually(ccserver.Ready(), network.EventuallyTimeout).Should(BeClosed())

By("exercising the chaincode")
nwo.InitChaincode(network, "testchannel", orderer, chaincode, network.PeersWithChannel("testchannel")...)
RunQueryInvokeQuery(network, orderer, peer, "testchannel")
RunRespondWith(network, orderer, peer, "testchannel")
})
})

type chaincodeConfig struct {
ListenAddress string `json:"listen_address,omitempty"`
Key string `json:"key,omitempty"` // PEM encoded key
Cert string `json:"cert,omitempty"` // PEM encoded certificate
CA string `json:"ca,omitempty"` // PEM encode CA certificate
}

func generateChaincodeConfig(chaincodeAddress string) (externalbuilder.ChaincodeServerUserData, chaincodeConfig) {
tlsCA, err := tlsgen.NewCA()
Expect(err).NotTo(HaveOccurred())

serverPair, err := tlsCA.NewServerCertKeyPair("127.0.0.1")
Expect(err).NotTo(HaveOccurred())
clientPair, err := tlsCA.NewClientCertKeyPair()
Expect(err).NotTo(HaveOccurred())

config := chaincodeConfig{
ListenAddress: chaincodeAddress,
Key: string(serverPair.Key),
Cert: string(serverPair.Cert),
CA: string(tlsCA.CertBytes()),
}

connData := externalbuilder.ChaincodeServerUserData{
Address: chaincodeAddress,
DialTimeout: externalbuilder.Duration{Duration: 10 * time.Second},
TLSRequired: true,
ClientAuthRequired: true,
ClientKey: string(clientPair.Key),
ClientCert: string(clientPair.Cert),
RootCert: string(tlsCA.CertBytes()),
}

return connData, config
}
Loading

0 comments on commit 8f882a3

Please sign in to comment.