github.com/kaituanwang/hyperledger@v2.0.1+incompatible/discovery/cmd/endorsers_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package discovery_test 8 9 import ( 10 "bytes" 11 "testing" 12 13 discprotos "github.com/hyperledger/fabric-protos-go/discovery" 14 "github.com/hyperledger/fabric-protos-go/msp" 15 "github.com/hyperledger/fabric/cmd/common" 16 . "github.com/hyperledger/fabric/discovery/client" 17 discovery "github.com/hyperledger/fabric/discovery/cmd" 18 "github.com/hyperledger/fabric/discovery/cmd/mocks" 19 "github.com/hyperledger/fabric/protoutil" 20 "github.com/pkg/errors" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/mock" 23 ) 24 25 func TestEndorserCmd(t *testing.T) { 26 server := "peer0" 27 channel := "mychannel" 28 stub := &mocks.Stub{} 29 parser := &mocks.ResponseParser{} 30 31 t.Run("no server supplied", func(t *testing.T) { 32 cmd := discovery.NewEndorsersCmd(stub, parser) 33 cmd.SetChannel(&channel) 34 35 err := cmd.Execute(common.Config{}) 36 assert.Equal(t, err.Error(), "no server specified") 37 }) 38 39 t.Run("no channel supplied", func(t *testing.T) { 40 cmd := discovery.NewEndorsersCmd(stub, parser) 41 cmd.SetServer(&server) 42 43 err := cmd.Execute(common.Config{}) 44 assert.Equal(t, err.Error(), "no channel specified") 45 }) 46 47 t.Run("Endorsement query with no chaincodes", func(t *testing.T) { 48 cmd := discovery.NewEndorsersCmd(stub, parser) 49 cmd.SetServer(&server) 50 cmd.SetChannel(&channel) 51 52 err := cmd.Execute(common.Config{}) 53 assert.Contains(t, err.Error(), "invocation chain should not be empty") 54 }) 55 56 t.Run("Server return error", func(t *testing.T) { 57 chaincodes := []string{"mycc"} 58 cmd := discovery.NewEndorsersCmd(stub, parser) 59 cmd.SetChannel(&channel) 60 cmd.SetServer(&server) 61 cmd.SetChaincodes(&chaincodes) 62 stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, errors.New("deadline exceeded")).Once() 63 64 err := cmd.Execute(common.Config{}) 65 assert.Contains(t, err.Error(), "deadline exceeded") 66 }) 67 68 t.Run("Endorsement query with no collections succeeds", func(t *testing.T) { 69 chaincodes := []string{"mycc"} 70 cmd := discovery.NewEndorsersCmd(stub, parser) 71 cmd.SetChannel(&channel) 72 cmd.SetServer(&server) 73 cmd.SetChaincodes(&chaincodes) 74 parser.On("ParseResponse", channel, mock.Anything).Return(nil).Once() 75 stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once() 76 77 err := cmd.Execute(common.Config{}) 78 assert.NoError(t, err) 79 }) 80 81 t.Run("Endorsement query with collections succeeds", func(t *testing.T) { 82 chaincodes := []string{"mycc", "yourcc"} 83 collections := map[string]string{ 84 "mycc": "col1,col2", 85 } 86 87 stub := &mocks.Stub{} 88 cmd := discovery.NewEndorsersCmd(stub, parser) 89 cmd.SetChannel(&channel) 90 cmd.SetServer(&server) 91 cmd.SetChaincodes(&chaincodes) 92 cmd.SetCollections(&collections) 93 parser.On("ParseResponse", channel, mock.Anything).Return(nil).Once() 94 stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once().Run(func(arg mock.Arguments) { 95 // Ensure the stub got the request that corresponds to what the CLI passed in 96 req := arg.Get(2).(*Request) 97 // Ensure chaincode names in the invocation chain match 98 assert.Equal(t, "mycc", req.Queries[0].GetCcQuery().Interests[0].Chaincodes[0].Name) 99 // Ensure collection names in the invocation chain match 100 assert.Equal(t, []string{"col1", "col2"}, req.Queries[0].GetCcQuery().Interests[0].Chaincodes[0].CollectionNames) 101 }) 102 103 err := cmd.Execute(common.Config{}) 104 assert.NoError(t, err) 105 stub.AssertNumberOfCalls(t, "Send", 1) 106 }) 107 108 t.Run("Endorsement query with collections that aren't mapped to any chaincode(s)", func(t *testing.T) { 109 chaincodes := []string{"mycc", "yourcc"} 110 collections := map[string]string{ 111 "mycc": "col1,col2", 112 "ourcc": "col3", 113 } 114 115 stub := &mocks.Stub{} 116 cmd := discovery.NewEndorsersCmd(stub, parser) 117 cmd.SetChannel(&channel) 118 cmd.SetServer(&server) 119 cmd.SetChaincodes(&chaincodes) 120 cmd.SetCollections(&collections) 121 stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once() 122 123 err := cmd.Execute(common.Config{}) 124 assert.Contains(t, err.Error(), "a collection specified chaincode ourcc but it wasn't specified with a chaincode flag") 125 }) 126 127 t.Run("Endorsement query with collections that aren't mapped to any chaincode(s)", func(t *testing.T) { 128 chaincodes := []string{"mycc", "yourcc"} 129 collections := map[string]string{ 130 "mycc": "col1,col2", 131 "ourcc": "col3", 132 } 133 134 stub := &mocks.Stub{} 135 cmd := discovery.NewEndorsersCmd(stub, parser) 136 cmd.SetChannel(&channel) 137 cmd.SetServer(&server) 138 cmd.SetChaincodes(&chaincodes) 139 cmd.SetCollections(&collections) 140 stub.On("Send", server, mock.Anything, mock.Anything).Return(nil, nil).Once() 141 142 err := cmd.Execute(common.Config{}) 143 assert.Contains(t, err.Error(), "a collection specified chaincode ourcc but it wasn't specified with a chaincode flag") 144 }) 145 } 146 147 func TestParseEndorsementResponse(t *testing.T) { 148 buff := &bytes.Buffer{} 149 parser := &discovery.EndorserResponseParser{Writer: buff} 150 res := &mocks.ServiceResponse{} 151 152 t.Run("Server returns empty response", func(t *testing.T) { 153 defer buff.Reset() 154 res.On("Raw").Return(&discprotos.Response{}).Once() 155 err := parser.ParseResponse("mychannel", res) 156 assert.Contains(t, err.Error(), "empty results") 157 }) 158 159 t.Run("Server returns an error", func(t *testing.T) { 160 defer buff.Reset() 161 res.On("Raw").Return(&discprotos.Response{ 162 Results: []*discprotos.QueryResult{ 163 { 164 Result: &discprotos.QueryResult_Error{ 165 Error: &discprotos.Error{ 166 Content: "internal error", 167 }, 168 }, 169 }, 170 }, 171 }).Once() 172 err := parser.ParseResponse("mychannel", res) 173 assert.Contains(t, err.Error(), "internal error") 174 }) 175 176 t.Run("Server returns a response with the wrong type", func(t *testing.T) { 177 defer buff.Reset() 178 res.On("Raw").Return(&discprotos.Response{ 179 Results: []*discprotos.QueryResult{ 180 { 181 Result: &discprotos.QueryResult_Members{ 182 Members: &discprotos.PeerMembershipResult{PeersByOrg: map[string]*discprotos.Peers{ 183 "Org1MSP": {}, 184 }}, 185 }, 186 }, 187 }, 188 }).Once() 189 err := parser.ParseResponse("mychannel", res) 190 assert.Contains(t, err.Error(), "server returned response of unexpected type: *discovery.QueryResult") 191 }) 192 193 t.Run("Server returns a proper response", func(t *testing.T) { 194 defer buff.Reset() 195 res.On("Raw").Return(&discprotos.Response{ 196 Results: []*discprotos.QueryResult{ 197 { 198 Result: endorsersResponse, 199 }, 200 }, 201 }).Once() 202 err := parser.ParseResponse("mychannel", res) 203 assert.NoError(t, err) 204 assert.Equal(t, expectedEndorsersOutput, buff.String()) 205 }) 206 } 207 208 var endorsersResponse = &discprotos.QueryResult_CcQueryRes{ 209 CcQueryRes: &discprotos.ChaincodeQueryResult{ 210 Content: []*discprotos.EndorsementDescriptor{ 211 { 212 Chaincode: "mycc", 213 EndorsersByGroups: map[string]*discprotos.Peers{ 214 "Org1MSP": { 215 Peers: []*discprotos.Peer{ 216 { 217 Identity: protoutil.MarshalOrPanic(&msp.SerializedIdentity{ 218 Mspid: "Org1MSP", 219 IdBytes: []byte("identity"), 220 }), 221 StateInfo: stateInfoMessage(100).Envelope, 222 MembershipInfo: aliveMessage(0).Envelope, 223 }, 224 }, 225 }, 226 }, 227 Layouts: []*discprotos.Layout{ 228 { 229 QuantitiesByGroup: map[string]uint32{ 230 "Org1MSP": 2, 231 }, 232 }, 233 }, 234 }, 235 }, 236 }, 237 } 238 239 const expectedEndorsersOutput = `[ 240 { 241 "Chaincode": "mycc", 242 "EndorsersByGroups": { 243 "Org1MSP": [ 244 { 245 "MSPID": "Org1MSP", 246 "LedgerHeight": 100, 247 "Endpoint": "p0", 248 "Identity": "identity" 249 } 250 ] 251 }, 252 "Layouts": [ 253 { 254 "quantities_by_group": { 255 "Org1MSP": 2 256 } 257 } 258 ] 259 } 260 ] 261 `