-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FAB-3948]WIP-chaincode shim unit tests and framework
Adds a mock framework based on channel streams for chaincode to peer connecvity. The unit test then follows the entire shim path driven by an actual chaincode. Init and Invoke are sent from the UT and chaincode sends ChaincoeMessages on the mock stream. The mock stream is primed with responses for each message received. With this setup, with just basic GET/PUT/DEL, we get a coverage jump from 17 to 43% as reported by go test -coverprofile=coverage.out Fixed Copyright year More tests Change-Id: I3ea9ac94abc7f43ee5dd297b8202a360d6800cbf Signed-off-by: Srinivasan Muralidharan <muralisr@us.ibm.com>
- Loading branch information
Srinivasan Muralidharan
committed
May 17, 2017
1 parent
fa98b46
commit fa9c616
Showing
6 changed files
with
1,011 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/* | ||
Copyright IBM Corp. 2017 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package peer | ||
|
||
import ( | ||
"fmt" | ||
|
||
pb "github.com/hyperledger/fabric/protos/peer" | ||
) | ||
|
||
//MockResponseSet is used for processing CC to Peer comm | ||
//such as GET/PUT/DEL state. The MockResponse contains the | ||
//response to be returned for each input received.from the | ||
//CC. Every stub call will generate a response | ||
type MockResponseSet struct { | ||
//DoneFunc is invoked when all I/O is done for this | ||
//response set | ||
DoneFunc func(int, error) | ||
|
||
//ErrorFunc is invoked at any step when the input does not | ||
//match the received message | ||
ErrorFunc func(int, error) | ||
|
||
//Responses contained the expected received message (optional) | ||
//and response to send (optional) | ||
Responses []*MockResponse | ||
} | ||
|
||
//MockResponse contains the expected received message (optional) | ||
//and response to send (optional) | ||
type MockResponse struct { | ||
RecvMsg *pb.ChaincodeMessage | ||
RespMsg *pb.ChaincodeMessage | ||
} | ||
|
||
// MockCCComm implements the mock communication between chaincode and peer | ||
// We'd need two MockCCComm for communication. The receiver and sender will | ||
// be switched between the two. | ||
type MockCCComm struct { | ||
name string | ||
bailOnError bool | ||
sendOnRecv *pb.ChaincodeMessage | ||
recvStream chan *pb.ChaincodeMessage | ||
sendStream chan *pb.ChaincodeMessage | ||
respIndex int | ||
respSet *MockResponseSet | ||
} | ||
|
||
//Send sends a message | ||
func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error { | ||
s.sendStream <- msg | ||
return nil | ||
} | ||
|
||
//Recv receives a message | ||
func (s *MockCCComm) Recv() (*pb.ChaincodeMessage, error) { | ||
msg := <-s.recvStream | ||
return msg, nil | ||
} | ||
|
||
//CloseSend closes send | ||
func (s *MockCCComm) CloseSend() error { | ||
return nil | ||
} | ||
|
||
//GetRecvStream returns the recvStream | ||
func (s *MockCCComm) GetRecvStream() chan *pb.ChaincodeMessage { | ||
return s.recvStream | ||
} | ||
|
||
//GetSendStream returns the sendStream | ||
func (s *MockCCComm) GetSendStream() chan *pb.ChaincodeMessage { | ||
return s.sendStream | ||
} | ||
|
||
//Quit closes the channels...this will also close chaincode side | ||
func (s *MockCCComm) Quit() { | ||
if s.recvStream != nil { | ||
close(s.recvStream) | ||
s.recvStream = nil | ||
} | ||
|
||
if s.sendStream != nil { | ||
close(s.sendStream) | ||
s.sendStream = nil | ||
} | ||
} | ||
|
||
//SetBailOnError will cause Run to return on any error | ||
func (s *MockCCComm) SetBailOnError(b bool) { | ||
s.bailOnError = b | ||
} | ||
|
||
//SetResponses sets responses for an Init or Invoke | ||
func (s *MockCCComm) SetResponses(respSet *MockResponseSet) { | ||
s.respSet = respSet | ||
s.respIndex = 0 | ||
} | ||
|
||
//Run receives and sends indefinitely | ||
func (s *MockCCComm) Run() error { | ||
for { | ||
msg, err := s.Recv() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
if err = s.respond(msg); err != nil { | ||
if s.bailOnError { | ||
return err | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (s *MockCCComm) respond(msg *pb.ChaincodeMessage) error { | ||
var err error | ||
if s.respIndex < len(s.respSet.Responses) { | ||
mockResp := s.respSet.Responses[s.respIndex] | ||
if mockResp.RecvMsg != nil { | ||
if msg.Type != mockResp.RecvMsg.Type { | ||
if s.respSet.ErrorFunc != nil { | ||
s.respSet.ErrorFunc(s.respIndex, fmt.Errorf("Invalid message expected %d received %d", int32(mockResp.RecvMsg.Type), int32(msg.Type))) | ||
s.respIndex = s.respIndex + 1 | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
if mockResp.RespMsg != nil { | ||
err = s.Send(mockResp.RespMsg) | ||
} | ||
|
||
s.respIndex = s.respIndex + 1 | ||
|
||
if s.respIndex == len(s.respSet.Responses) { | ||
if s.respSet.DoneFunc != nil { | ||
s.respSet.DoneFunc(s.respIndex, nil) | ||
} | ||
} | ||
} | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
Copyright IBM Corp. 2017 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package peer | ||
|
||
import ( | ||
"fmt" | ||
|
||
pb "github.com/hyperledger/fabric/protos/peer" | ||
) | ||
|
||
//MockPeerCCSupport provides CC support for peer interfaces. | ||
type MockPeerCCSupport struct { | ||
ccStream map[string]*MockCCComm | ||
} | ||
|
||
//NewMockPeerSupport getsa mock peer support | ||
func NewMockPeerSupport() *MockPeerCCSupport { | ||
return &MockPeerCCSupport{ccStream: make(map[string]*MockCCComm)} | ||
} | ||
|
||
//AddCC adds a cc to the MockPeerCCSupport | ||
func (mp *MockPeerCCSupport) AddCC(name string, recv chan *pb.ChaincodeMessage, send chan *pb.ChaincodeMessage) (*MockCCComm, error) { | ||
if mp.ccStream[name] != nil { | ||
return nil, fmt.Errorf("CC %s already added", name) | ||
} | ||
mcc := &MockCCComm{name: name, recvStream: recv, sendStream: send} | ||
mp.ccStream[name] = mcc | ||
return mcc, nil | ||
} | ||
|
||
//GetCC gets a cc from the MockPeerCCSupport | ||
func (mp *MockPeerCCSupport) GetCC(name string) (*MockCCComm, error) { | ||
s := mp.ccStream[name] | ||
if s == nil { | ||
return nil, fmt.Errorf("CC %s not added", name) | ||
} | ||
return s, nil | ||
} | ||
|
||
//GetCCMirror creates a MockCCStream with streans switched | ||
func (mp *MockPeerCCSupport) GetCCMirror(name string) *MockCCComm { | ||
s := mp.ccStream[name] | ||
if s == nil { | ||
return nil | ||
} | ||
|
||
return &MockCCComm{name: name, recvStream: s.sendStream, sendStream: s.recvStream} | ||
} | ||
|
||
//RemoveCC removes a cc | ||
func (mp *MockPeerCCSupport) RemoveCC(name string) error { | ||
if mp.ccStream[name] == nil { | ||
return fmt.Errorf("CC %s not added", name) | ||
} | ||
delete(mp.ccStream, name) | ||
return nil | ||
} | ||
|
||
//RemoveAll removes all ccs | ||
func (mp *MockPeerCCSupport) RemoveAll() error { | ||
mp.ccStream = make(map[string]*MockCCComm) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.