Skip to content

Commit 74ee0ff

Browse files
committed
[FAB-10687] create sd runner for e2e tests
this change set adds discovery service runner in order to perform some e2e tests. it also covers the needed changes in core.yaml, and adds some helper functions that are used in sd test, and will be used also in the e2e tests. Change-Id: Ie558e0de7ee803398fdb46fbabfc0d95da80652e Signed-off-by: nirro <nirro@il.ibm.com>
1 parent ec398ed commit 74ee0ff

File tree

6 files changed

+616
-1
lines changed

6 files changed

+616
-1
lines changed

integration/helpers/discovery.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package helpers
8+
9+
import (
10+
"github.com/hyperledger/fabric/protos/discovery"
11+
)
12+
13+
type DiscoveredPeer struct {
14+
MSPID string
15+
LedgerHeight uint64
16+
Endpoint string
17+
Identity string
18+
Chaincodes []string
19+
}
20+
21+
type EndorsementDescriptor struct {
22+
Chaincode string
23+
EndorsersByGroups map[string][]DiscoveredPeer
24+
Layouts []*discovery.Layout
25+
}
26+
27+
// Verifies that each DiscveredPeer in expectedPeers exist in actualPeers.
28+
// The check is done by comparing peer endpoint and mspid and ignores ledger height, identity and chaincodes.
29+
func CheckPeersContainsExpectedPeers(expectedPeers []DiscoveredPeer, actualPeers []DiscoveredPeer) bool {
30+
if len(actualPeers) != len(expectedPeers) {
31+
return false
32+
}
33+
34+
foundPeersCount := 0
35+
for _, expectedPeer := range expectedPeers {
36+
for _, actualPeer := range actualPeers {
37+
if actualPeer.Endpoint == expectedPeer.Endpoint && actualPeer.MSPID == expectedPeer.MSPID {
38+
foundPeersCount++
39+
break
40+
}
41+
}
42+
}
43+
if foundPeersCount == len(expectedPeers) {
44+
return true
45+
}
46+
return false
47+
}
48+
49+
// Verifies that discovery service expectedConfig can be found in actualConfig.
50+
// The check is done by comparing orderers (name, host and port) and by comparing msps(only name)
51+
func CheckConfigContainsExpectedConfig(expectedConfig discovery.ConfigResult, actualConfig discovery.ConfigResult) bool {
52+
if len(expectedConfig.Orderers) != len(actualConfig.Orderers) || len(expectedConfig.Msps) != len(actualConfig.Msps) {
53+
return false
54+
}
55+
// compare Orderers
56+
for expectedName, expectedOrderer := range expectedConfig.Orderers {
57+
foundOrderer := false
58+
for actualName, actualOrderer := range actualConfig.Orderers {
59+
if expectedName != actualName {
60+
continue
61+
}
62+
if len(expectedOrderer.Endpoint) != len(actualOrderer.Endpoint) {
63+
continue
64+
}
65+
foundEndpoints := 0
66+
for _, expectedEndpoint := range expectedOrderer.Endpoint {
67+
for _, actualEndpoint := range actualOrderer.Endpoint {
68+
if expectedEndpoint.Host == actualEndpoint.Host && expectedEndpoint.Port == actualEndpoint.Port {
69+
foundEndpoints++
70+
}
71+
}
72+
}
73+
if len(expectedOrderer.Endpoint) == foundEndpoints {
74+
foundOrderer = true
75+
}
76+
}
77+
if !foundOrderer {
78+
return false
79+
}
80+
}
81+
// compare msps
82+
for expectedName, expectedMsp := range expectedConfig.Msps {
83+
foundMsp := false
84+
for actualName, actualMsp := range actualConfig.Msps {
85+
if expectedName != actualName {
86+
continue
87+
}
88+
if expectedMsp.Name != actualMsp.Name {
89+
continue
90+
}
91+
foundMsp = true
92+
}
93+
if !foundMsp {
94+
return false
95+
}
96+
}
97+
98+
return true
99+
}
100+
101+
// Verifies that actualEndorsement contains expectedEndorsement.
102+
// The check is done by comparing the following fields:
103+
// - Chaincode - identical in both endorsement descriptors
104+
// - EndorsersByGroups - each group of DiscoveredPeer in expectedEndorsement can be found also in actualEndorsement. different calls to discovery service might generate different groups names
105+
// - Layouts - all layouts that exist in expectedEndorsement can be found also in actualEndorsement. the function takes care of different names also in this check
106+
func CheckEndorsementContainsExpectedEndorsement(expectedEndorsement EndorsementDescriptor, actualEndorsement EndorsementDescriptor) bool {
107+
if expectedEndorsement.Chaincode != actualEndorsement.Chaincode {
108+
return false
109+
}
110+
groupsMapping := map[string]string{} //mapping from dummy names to group names in the output
111+
for dummyGroupName, expectedGroup := range expectedEndorsement.EndorsersByGroups {
112+
foundGroup := false
113+
for actualGroupName, actualGroup := range actualEndorsement.EndorsersByGroups {
114+
if CheckPeersContainsExpectedPeers(expectedGroup, actualGroup) {
115+
foundGroup = true
116+
groupsMapping[actualGroupName] = dummyGroupName
117+
break
118+
}
119+
}
120+
if !foundGroup {
121+
return false
122+
}
123+
}
124+
125+
for _, expectedLayout := range expectedEndorsement.Layouts {
126+
foundLayout := false
127+
for _, actualLayout := range actualEndorsement.Layouts {
128+
if len(expectedLayout.QuantitiesByGroup) != len(actualLayout.QuantitiesByGroup) {
129+
continue
130+
}
131+
foundGroupCount := 0
132+
for expectedGroupName, expectedQuantity := range expectedLayout.QuantitiesByGroup {
133+
for actualGroupName, actualQuantity := range actualLayout.QuantitiesByGroup {
134+
if groupsMapping[actualGroupName] == expectedGroupName && expectedQuantity == actualQuantity {
135+
foundGroupCount++
136+
break
137+
}
138+
}
139+
}
140+
if len(expectedLayout.QuantitiesByGroup) == foundGroupCount {
141+
foundLayout = true
142+
break
143+
}
144+
}
145+
if !foundLayout {
146+
return false
147+
}
148+
}
149+
return true
150+
}

integration/helpers/utils.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package helpers
8+
9+
import (
10+
"time"
11+
12+
. "github.com/onsi/gomega"
13+
"github.com/tedsuo/ifrit"
14+
)
15+
16+
const (
17+
runnerExecutionTimeout = time.Second * 30
18+
)
19+
20+
func Execute(r ifrit.Runner) (err error) {
21+
p := ifrit.Invoke(r)
22+
Eventually(p.Ready()).Should(BeClosed())
23+
Eventually(p.Wait(), runnerExecutionTimeout).Should(Receive(&err))
24+
return err
25+
}
26+
27+
func Contains(list []string, value string) bool {
28+
for _, item := range list {
29+
if item == value {
30+
return true
31+
}
32+
}
33+
return false
34+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package runner
8+
9+
import (
10+
"encoding/json"
11+
"fmt"
12+
"io/ioutil"
13+
"os"
14+
"os/exec"
15+
"path/filepath"
16+
"strings"
17+
18+
"github.com/hyperledger/fabric/integration/helpers"
19+
"github.com/hyperledger/fabric/protos/discovery"
20+
. "github.com/onsi/gomega"
21+
22+
"github.com/tedsuo/ifrit/ginkgomon"
23+
)
24+
25+
// DiscoveryService wraps sd cli and enables discovering peers, config and endorsement descriptors
26+
type DiscoveryService struct {
27+
// The location of the discovery service executable
28+
Path string
29+
// Path to the config file that will be generated in GenerateConfig function and will be used later in all other functions
30+
ConfigFilePath string
31+
// Log level that will be used in discovery service executable
32+
LogLevel string
33+
}
34+
35+
func (sd *DiscoveryService) setupEnvironment(cmd *exec.Cmd) {
36+
for _, env := range os.Environ() {
37+
cmd.Env = append(cmd.Env, env)
38+
}
39+
if sd.LogLevel != "" {
40+
cmd.Env = append(cmd.Env, fmt.Sprintf("CORE_LOGGING_LEVEL=%s", sd.LogLevel))
41+
}
42+
}
43+
44+
func (sd *DiscoveryService) GenerateConfig(userCert string, userKey string, msp string, extraArgs ...string) *ginkgomon.Runner {
45+
cmd := exec.Command(sd.Path, "saveConfig", "--configFile", sd.ConfigFilePath, "--userCert", userCert, "--userKey", userKey, "--MSP", msp)
46+
47+
cmd.Args = append(cmd.Args, extraArgs...)
48+
sd.setupEnvironment(cmd)
49+
return ginkgomon.New(ginkgomon.Config{
50+
Name: "discover saveConfig",
51+
AnsiColorCode: "92m",
52+
Command: cmd,
53+
})
54+
}
55+
56+
func (sd *DiscoveryService) DiscoverPeers(channel string, server string, extraArgs ...string) *ginkgomon.Runner {
57+
cmd := exec.Command(sd.Path, "peers", "--configFile", sd.ConfigFilePath, "--channel", channel, "--server", server)
58+
59+
cmd.Args = append(cmd.Args, extraArgs...)
60+
sd.setupEnvironment(cmd)
61+
return ginkgomon.New(ginkgomon.Config{
62+
Name: "discover peers",
63+
AnsiColorCode: "95m",
64+
Command: cmd,
65+
})
66+
}
67+
68+
func (sd *DiscoveryService) DiscoverConfig(channel string, server string, extraArgs ...string) *ginkgomon.Runner {
69+
cmd := exec.Command(sd.Path, "config", "--configFile", sd.ConfigFilePath, "--channel", channel, "--server", server)
70+
71+
cmd.Args = append(cmd.Args, extraArgs...)
72+
sd.setupEnvironment(cmd)
73+
return ginkgomon.New(ginkgomon.Config{
74+
Name: "discover config",
75+
AnsiColorCode: "96m",
76+
Command: cmd,
77+
})
78+
}
79+
80+
func (sd *DiscoveryService) DiscoverEndorsers(channel string, server string, chaincodeName string, collectionName string, extraArgs ...string) *ginkgomon.Runner {
81+
var args []string
82+
if collectionName == "" {
83+
args = []string{"endorsers", "--configFile", sd.ConfigFilePath, "--channel", channel, "--server", server, "--chaincode", chaincodeName}
84+
} else {
85+
args = []string{"endorsers", "--configFile", sd.ConfigFilePath, "--channel", channel, "--server", server, "--chaincode", chaincodeName, fmt.Sprintf("--collection=%s:%s", chaincodeName, collectionName)}
86+
}
87+
cmd := exec.Command(sd.Path, args...)
88+
cmd.Args = append(cmd.Args, extraArgs...)
89+
sd.setupEnvironment(cmd)
90+
return ginkgomon.New(ginkgomon.Config{
91+
Name: "discover endorsers",
92+
AnsiColorCode: "97m",
93+
Command: cmd,
94+
})
95+
}
96+
97+
func SetupDiscoveryService(sd *DiscoveryService, org int, configFilePath string, userCert string, userKeyDir string) *DiscoveryService {
98+
sd.ConfigFilePath = configFilePath
99+
sd.LogLevel = "debug"
100+
101+
files, err := ioutil.ReadDir(userKeyDir)
102+
Expect(err).NotTo(HaveOccurred())
103+
userKey := ""
104+
Expect(len(files)).To(Equal(1))
105+
for _, f := range files {
106+
userKey = filepath.Join(userKeyDir, f.Name())
107+
}
108+
msp := fmt.Sprintf("Org%dMSP", org)
109+
110+
sdRunner := sd.GenerateConfig(userCert, userKey, msp)
111+
err = helpers.Execute(sdRunner)
112+
Expect(err).NotTo(HaveOccurred())
113+
return sd
114+
}
115+
116+
func VerifyAllPeersDiscovered(sd *DiscoveryService, expectedPeers []helpers.DiscoveredPeer, channel string, server string) ([]helpers.DiscoveredPeer, bool) {
117+
sdRunner := sd.DiscoverPeers(channel, server)
118+
err := helpers.Execute(sdRunner)
119+
Expect(err).NotTo(HaveOccurred())
120+
121+
var discoveredPeers []helpers.DiscoveredPeer
122+
json.Unmarshal(sdRunner.Buffer().Contents(), &discoveredPeers)
123+
124+
if helpers.CheckPeersContainsExpectedPeers(expectedPeers, discoveredPeers) &&
125+
helpers.CheckPeersContainsExpectedPeers(discoveredPeers, expectedPeers) {
126+
return discoveredPeers, true
127+
}
128+
return discoveredPeers, false
129+
}
130+
131+
func VerifyConfigDiscovered(sd *DiscoveryService, expectedConfig discovery.ConfigResult, channel string, server string) bool {
132+
sdRunner := sd.DiscoverConfig(channel, server)
133+
err := helpers.Execute(sdRunner)
134+
Expect(err).NotTo(HaveOccurred())
135+
136+
var config discovery.ConfigResult
137+
json.Unmarshal(sdRunner.Buffer().Contents(), &config)
138+
139+
return helpers.CheckConfigContainsExpectedConfig(expectedConfig, config) &&
140+
helpers.CheckConfigContainsExpectedConfig(config, expectedConfig)
141+
}
142+
143+
func VerifyEndorsersDiscovered(sd *DiscoveryService, expectedEndorsementDescriptor helpers.EndorsementDescriptor, channel string, server string, chaincodeName string, collectionName string) bool {
144+
sdRunner := sd.DiscoverEndorsers(channel, server, chaincodeName, collectionName)
145+
err := helpers.Execute(sdRunner)
146+
Expect(err).NotTo(HaveOccurred())
147+
if strings.Contains(string(sdRunner.Buffer().Contents()[:]), fmt.Sprintf(`failed constructing descriptor for chaincodes:<name:"%s"`, chaincodeName)) {
148+
return false
149+
}
150+
var endorsers []helpers.EndorsementDescriptor
151+
json.Unmarshal(sdRunner.Buffer().Contents(), &endorsers)
152+
153+
return helpers.CheckEndorsementContainsExpectedEndorsement(expectedEndorsementDescriptor, endorsers[0]) &&
154+
helpers.CheckEndorsementContainsExpectedEndorsement(endorsers[0], expectedEndorsementDescriptor)
155+
}

0 commit comments

Comments
 (0)