Skip to content

Commit

Permalink
[FAB-3948]chaincode shim unit tests and framework
Browse files Browse the repository at this point in the history
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 <muralisr@us.ibm.com>
  • Loading branch information
Srinivasan Muralidharan committed Jun 3, 2017
1 parent a6760f7 commit 389e616
Show file tree
Hide file tree
Showing 5 changed files with 305 additions and 249 deletions.
44 changes: 44 additions & 0 deletions common/mocks/peer/mockccstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package peer

import (
"fmt"
"time"

pb "github.com/hyperledger/fabric/protos/peer"
)
Expand Down Expand Up @@ -53,11 +54,13 @@ type MockResponse struct {
type MockCCComm struct {
name string
bailOnError bool
keepAlive *pb.ChaincodeMessage
sendOnRecv *pb.ChaincodeMessage
recvStream chan *pb.ChaincodeMessage
sendStream chan *pb.ChaincodeMessage
respIndex int
respSet *MockResponseSet
pong bool
}

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

//Send sends a message
func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error {
defer func() {
recover()
}()
s.sendStream <- msg
return nil
}
Expand Down Expand Up @@ -109,14 +115,44 @@ func (s *MockCCComm) SetBailOnError(b bool) {
s.bailOnError = b
}

//SetPong pongs received keepalive. This mut be done on the chaincode only
func (s *MockCCComm) SetPong(val bool) {
s.pong = val
}

//SetKeepAlive sets keepalive. This mut be done on the server only
func (s *MockCCComm) SetKeepAlive(ka *pb.ChaincodeMessage) {
s.keepAlive = ka
}

//SetResponses sets responses for an Init or Invoke
func (s *MockCCComm) SetResponses(respSet *MockResponseSet) {
s.respSet = respSet
s.respIndex = 0
}

//keepAlive
func (s *MockCCComm) ka() {
defer recover()
for {
if s.keepAlive == nil {
return
}
s.Send(s.keepAlive)
time.Sleep(10 * time.Millisecond)
}
}

//Run receives and sends indefinitely
func (s *MockCCComm) Run() error {
//start the keepalive
go s.ka()

//if we started keep alive this will kill it
defer func() {
s.keepAlive = nil
}()

for {
msg, err := s.Recv()

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

func (s *MockCCComm) respond(msg *pb.ChaincodeMessage) error {
if msg != nil && msg.Type == pb.ChaincodeMessage_KEEPALIVE {
//if ping should be ponged, pong
if s.pong {
return s.Send(msg)
}
return nil
}

var err error
if s.respIndex < len(s.respSet.Responses) {
mockResp := s.respSet.Responses[s.respIndex]
Expand Down
14 changes: 11 additions & 3 deletions core/chaincode/chaincode_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,9 @@ func setupcc(name string) (*mockpeer.MockCCComm, *mockpeer.MockCCComm) {
recv := make(chan *pb.ChaincodeMessage)
peerSide, _ := mockPeerCCSupport.AddCC(name, recv, send)
peerSide.SetName("peer")
return peerSide, mockPeerCCSupport.GetCCMirror(name)
ccSide := mockPeerCCSupport.GetCCMirror(name)
ccSide.SetPong(true)
return peerSide, ccSide
}

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

func processDone(t *testing.T, done chan error, expecterr bool) {
err := <-done
var err error
if done != nil {
err = <-done
}
if expecterr != (err != nil) {
if err == nil {
t.Fatalf("Expected error but got success")
Expand Down Expand Up @@ -353,7 +358,10 @@ func initializeCC(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCC
resp.RespMsg.(*pb.ChaincodeMessage).Txid = "1"

badcccid := ccprovider.NewCCContext(chainID, ccname, "unknownver", "1", false, sprop, prop)
execCC(t, ctxt, ccSide, badcccid, false, true, done, cis, respSet)

//we are not going to reach the chaincode and so won't get a response from it. processDone will not
//be triggered by the chaincode stream. We just expect an error from fabric. Hence pass nil for done
execCC(t, ctxt, ccSide, badcccid, false, true, nil, cis, respSet)

//---------try a successful init at last-------
//everything lined up
Expand Down
48 changes: 23 additions & 25 deletions core/chaincode/shim/chaincode.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,14 @@ const (
HISTORY_QUERY_RESULT
)

func (stub *ChaincodeStub) handleGetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error) {
response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID)
if err != nil {
return nil, err
}
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
}

// GetStateByRange function can be invoked by a chaincode to query of a range
// of keys in the state. Assuming the startKey and endKey are in lexical order,
// an iterator will be returned that can be used to iterate over all keys
Expand All @@ -448,11 +456,7 @@ func (stub *ChaincodeStub) GetStateByRange(startKey, endKey string) (StateQueryI
if err := validateSimpleKeys(startKey, endKey); err != nil {
return nil, err
}
response, err := stub.handler.handleGetStateByRange(startKey, endKey, stub.TxID)
if err != nil {
return nil, err
}
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
return stub.handleGetStateByRange(startKey, endKey)
}

// GetQueryResult function can be invoked by a chaincode to perform a
Expand Down Expand Up @@ -547,31 +551,27 @@ func validateSimpleKeys(simpleKeys ...string) error {
//a partial composite key. For a full composite key, an iter with empty response
//would be returned.
func (stub *ChaincodeStub) GetStateByPartialCompositeKey(objectType string, attributes []string) (StateQueryIteratorInterface, error) {
partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes)
if err != nil {
return nil, err
}
response, err := stub.handler.handleGetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue), stub.TxID)
if err != nil {
if partialCompositeKey, err := stub.CreateCompositeKey(objectType, attributes); err == nil {
return stub.handleGetStateByRange(partialCompositeKey, partialCompositeKey+string(maxUnicodeRuneValue))
} else {
return nil, err
}
return &StateQueryIterator{CommonIterator: &CommonIterator{stub.handler, stub.TxID, response, 0}}, nil
}

func (iter *StateQueryIterator) Next() (*queryresult.KV, error) {
result, err := iter.nextResult(STATE_QUERY_RESULT)
if err != nil {
if result, err := iter.nextResult(STATE_QUERY_RESULT); err == nil {
return result.(*queryresult.KV), err
} else {
return nil, err
}
return result.(*queryresult.KV), err
}

func (iter *HistoryQueryIterator) Next() (*queryresult.KeyModification, error) {
result, err := iter.nextResult(HISTORY_QUERY_RESULT)
if err != nil {
if result, err := iter.nextResult(HISTORY_QUERY_RESULT); err == nil {
return result.(*queryresult.KeyModification), err
} else {
return nil, err
}
return result.(*queryresult.KeyModification), err
}

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

func (iter *CommonIterator) fetchNextQueryResult() error {
response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid)

if err != nil {
if response, err := iter.handler.handleQueryStateNext(iter.response.Id, iter.uuid); err == nil {
iter.currentLoc = 0
iter.response = response
return nil
} else {
return err
}

iter.currentLoc = 0
iter.response = response
return nil
}

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

0 comments on commit 389e616

Please sign in to comment.