Skip to content

Commit 389e616

Browse files
author
Srinivasan Muralidharan
committed
[FAB-3948]chaincode shim unit tests and framework
A bit more refactoring and a few more error coverage Cleaned up error processing to be more UT coverage friendly. Added keepalive for a bit more UT coverage. Change-Id: Icf12b6cc1079b2486afb4560d77b3eb8d972589d Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent a6760f7 commit 389e616

File tree

5 files changed

+305
-249
lines changed

5 files changed

+305
-249
lines changed

common/mocks/peer/mockccstream.go

+44
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package peer
1818

1919
import (
2020
"fmt"
21+
"time"
2122

2223
pb "github.com/hyperledger/fabric/protos/peer"
2324
)
@@ -53,11 +54,13 @@ type MockResponse struct {
5354
type MockCCComm struct {
5455
name string
5556
bailOnError bool
57+
keepAlive *pb.ChaincodeMessage
5658
sendOnRecv *pb.ChaincodeMessage
5759
recvStream chan *pb.ChaincodeMessage
5860
sendStream chan *pb.ChaincodeMessage
5961
respIndex int
6062
respSet *MockResponseSet
63+
pong bool
6164
}
6265

6366
func (s *MockCCComm) SetName(newname string) {
@@ -66,6 +69,9 @@ func (s *MockCCComm) SetName(newname string) {
6669

6770
//Send sends a message
6871
func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error {
72+
defer func() {
73+
recover()
74+
}()
6975
s.sendStream <- msg
7076
return nil
7177
}
@@ -109,14 +115,44 @@ func (s *MockCCComm) SetBailOnError(b bool) {
109115
s.bailOnError = b
110116
}
111117

118+
//SetPong pongs received keepalive. This mut be done on the chaincode only
119+
func (s *MockCCComm) SetPong(val bool) {
120+
s.pong = val
121+
}
122+
123+
//SetKeepAlive sets keepalive. This mut be done on the server only
124+
func (s *MockCCComm) SetKeepAlive(ka *pb.ChaincodeMessage) {
125+
s.keepAlive = ka
126+
}
127+
112128
//SetResponses sets responses for an Init or Invoke
113129
func (s *MockCCComm) SetResponses(respSet *MockResponseSet) {
114130
s.respSet = respSet
115131
s.respIndex = 0
116132
}
117133

134+
//keepAlive
135+
func (s *MockCCComm) ka() {
136+
defer recover()
137+
for {
138+
if s.keepAlive == nil {
139+
return
140+
}
141+
s.Send(s.keepAlive)
142+
time.Sleep(10 * time.Millisecond)
143+
}
144+
}
145+
118146
//Run receives and sends indefinitely
119147
func (s *MockCCComm) Run() error {
148+
//start the keepalive
149+
go s.ka()
150+
151+
//if we started keep alive this will kill it
152+
defer func() {
153+
s.keepAlive = nil
154+
}()
155+
120156
for {
121157
msg, err := s.Recv()
122158

@@ -133,6 +169,14 @@ func (s *MockCCComm) Run() error {
133169
}
134170

135171
func (s *MockCCComm) respond(msg *pb.ChaincodeMessage) error {
172+
if msg != nil && msg.Type == pb.ChaincodeMessage_KEEPALIVE {
173+
//if ping should be ponged, pong
174+
if s.pong {
175+
return s.Send(msg)
176+
}
177+
return nil
178+
}
179+
136180
var err error
137181
if s.respIndex < len(s.respSet.Responses) {
138182
mockResp := s.respSet.Responses[s.respIndex]

core/chaincode/chaincode_support_test.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ func setupcc(name string) (*mockpeer.MockCCComm, *mockpeer.MockCCComm) {
199199
recv := make(chan *pb.ChaincodeMessage)
200200
peerSide, _ := mockPeerCCSupport.AddCC(name, recv, send)
201201
peerSide.SetName("peer")
202-
return peerSide, mockPeerCCSupport.GetCCMirror(name)
202+
ccSide := mockPeerCCSupport.GetCCMirror(name)
203+
ccSide.SetPong(true)
204+
return peerSide, ccSide
203205
}
204206

205207
//assign this to done and failNow and keep using them
@@ -208,7 +210,10 @@ func setuperror() chan error {
208210
}
209211

210212
func processDone(t *testing.T, done chan error, expecterr bool) {
211-
err := <-done
213+
var err error
214+
if done != nil {
215+
err = <-done
216+
}
212217
if expecterr != (err != nil) {
213218
if err == nil {
214219
t.Fatalf("Expected error but got success")
@@ -353,7 +358,10 @@ func initializeCC(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCC
353358
resp.RespMsg.(*pb.ChaincodeMessage).Txid = "1"
354359

355360
badcccid := ccprovider.NewCCContext(chainID, ccname, "unknownver", "1", false, sprop, prop)
356-
execCC(t, ctxt, ccSide, badcccid, false, true, done, cis, respSet)
361+
362+
//we are not going to reach the chaincode and so won't get a response from it. processDone will not
363+
//be triggered by the chaincode stream. We just expect an error from fabric. Hence pass nil for done
364+
execCC(t, ctxt, ccSide, badcccid, false, true, nil, cis, respSet)
357365

358366
//---------try a successful init at last-------
359367
//everything lined up

core/chaincode/shim/chaincode.go

+23-25
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,14 @@ const (
434434
HISTORY_QUERY_RESULT
435435
)
436436

437+
func (stub *ChaincodeStub) handleGetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) {
438+
response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID)
439+
if err != nil {
440+
return nil, err
441+
}
442+
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
443+
}
444+
437445
// GetStateByRange function can be invoked by a chaincode to query of a range
438446
// of keys in the state. Assuming the startKey and endKey are in lexical order,
439447
// an iterator will be returned that can be used to iterate over all keys
@@ -448,11 +456,7 @@ func (stub *ChaincodeStub) GetStateByRange(startKey, endKey string) (StateQueryI
448456
if err := validateSimpleKeys(startKey, endKey); err != nil {
449457
return nil, err
450458
}
451-
response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID)
452-
if err != nil {
453-
return nil, err
454-
}
455-
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
459+
return stub.handleGetStateByRange(startKey, endKey)
456460
}
457461

458462
// GetQueryResult function can be invoked by a chaincode to perform a
@@ -547,31 +551,27 @@ func validateSimpleKeys(simpleKeys ...string) error {
547551
//a partial composite key. For a full composite key, an iter with empty response
548552
//would be returned.
549553
func (stub *ChaincodeStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) {
550-
partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes)
551-
if err != nil {
552-
return nil, err
553-
}
554-
response, err := stub.handler.handleGetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue), stub.TxID)
555-
if err != nil {
554+
if partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes); err == nil {
555+
return stub.handleGetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue))
556+
} else {
556557
return nil, err
557558
}
558-
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
559559
}
560560

561561
func (iter *StateQueryIterator) Next() (*queryresult.KV, error) {
562-
result, err := iter.nextResult(STATE_QUERY_RESULT)
563-
if err != nil {
562+
if result, err := iter.nextResult(STATE_QUERY_RESULT); err == nil {
563+
return result.(*queryresult.KV), err
564+
} else {
564565
return nil, err
565566
}
566-
return result.(*queryresult.KV), err
567567
}
568568

569569
func (iter *HistoryQueryIterator) Next() (*queryresult.KeyModification, error) {
570-
result, err := iter.nextResult(HISTORY_QUERY_RESULT)
571-
if err != nil {
570+
if result, err := iter.nextResult(HISTORY_QUERY_RESULT); err == nil {
571+
return result.(*queryresult.KeyModification), err
572+
} else {
572573
return nil, err
573574
}
574-
return result.(*queryresult.KeyModification), err
575575
}
576576

577577
// HasNext returns true if the range query iterator contains additional keys
@@ -608,15 +608,13 @@ func (iter *CommonIterator) getResultFromBytes(queryResultBytes *pb.QueryResultB
608608
}
609609

610610
func (iter *CommonIterator) fetchNextQueryResult() error {
611-
response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid)
612-
613-
if err != nil {
611+
if response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid); err == nil {
612+
iter.currentLoc = 0
613+
iter.response = response
614+
return nil
615+
} else {
614616
return err
615617
}
616-
617-
iter.currentLoc = 0
618-
iter.response = response
619-
return nil
620618
}
621619

622620
// nextResult returns the next QueryResult (i.e., either a KV struct or KeyModification)

0 commit comments

Comments
 (0)