github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/common/mocks/peer/mockccstream.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package peer 18 19 import ( 20 "fmt" 21 "time" 22 23 pb "github.com/hyperledger/fabric/protos/peer" 24 ) 25 26 //MockResponseSet is used for processing CC to Peer comm 27 //such as GET/PUT/DEL state. The MockResponse contains the 28 //response to be returned for each input received.from the 29 //CC. Every stub call will generate a response 30 type MockResponseSet struct { 31 //DoneFunc is invoked when all I/O is done for this 32 //response set 33 DoneFunc func(int, error) 34 35 //ErrorFunc is invoked at any step when the input does not 36 //match the received message 37 ErrorFunc func(int, error) 38 39 //Responses contained the expected received message (optional) 40 //and response to send (optional) 41 Responses []*MockResponse 42 } 43 44 //MockResponse contains the expected received message (optional) 45 //and response to send (optional) 46 type MockResponse struct { 47 RecvMsg *pb.ChaincodeMessage 48 RespMsg interface{} 49 } 50 51 // MockCCComm implements the mock communication between chaincode and peer 52 // We'd need two MockCCComm for communication. The receiver and sender will 53 // be switched between the two. 54 type MockCCComm struct { 55 name string 56 bailOnError bool 57 keepAlive *pb.ChaincodeMessage 58 sendOnRecv *pb.ChaincodeMessage 59 recvStream chan *pb.ChaincodeMessage 60 sendStream chan *pb.ChaincodeMessage 61 respIndex int 62 respSet *MockResponseSet 63 pong bool 64 } 65 66 func (s *MockCCComm) SetName(newname string) { 67 s.name = newname 68 } 69 70 //Send sends a message 71 func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error { 72 defer func() { 73 recover() 74 }() 75 s.sendStream <- msg 76 return nil 77 } 78 79 //Recv receives a message 80 func (s *MockCCComm) Recv() (*pb.ChaincodeMessage, error) { 81 msg := <-s.recvStream 82 return msg, nil 83 } 84 85 //CloseSend closes send 86 func (s *MockCCComm) CloseSend() error { 87 return nil 88 } 89 90 //GetRecvStream returns the recvStream 91 func (s *MockCCComm) GetRecvStream() chan *pb.ChaincodeMessage { 92 return s.recvStream 93 } 94 95 //GetSendStream returns the sendStream 96 func (s *MockCCComm) GetSendStream() chan *pb.ChaincodeMessage { 97 return s.sendStream 98 } 99 100 //Quit closes the channels...this will also close chaincode side 101 func (s *MockCCComm) Quit() { 102 if s.recvStream != nil { 103 close(s.recvStream) 104 s.recvStream = nil 105 } 106 107 if s.sendStream != nil { 108 close(s.sendStream) 109 s.sendStream = nil 110 } 111 } 112 113 //SetBailOnError will cause Run to return on any error 114 func (s *MockCCComm) SetBailOnError(b bool) { 115 s.bailOnError = b 116 } 117 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 128 //SetResponses sets responses for an Init or Invoke 129 func (s *MockCCComm) SetResponses(respSet *MockResponseSet) { 130 s.respSet = respSet 131 s.respIndex = 0 132 } 133 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 146 //Run receives and sends indefinitely 147 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 156 for { 157 msg, err := s.Recv() 158 159 if err != nil { 160 return err 161 } 162 163 if err = s.respond(msg); err != nil { 164 if s.bailOnError { 165 return err 166 } 167 } 168 } 169 } 170 171 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 180 var err error 181 if s.respIndex < len(s.respSet.Responses) { 182 mockResp := s.respSet.Responses[s.respIndex] 183 if mockResp.RecvMsg != nil { 184 if msg.Type != mockResp.RecvMsg.Type { 185 if s.respSet.ErrorFunc != nil { 186 s.respSet.ErrorFunc(s.respIndex, fmt.Errorf("Invalid message expected %d received %d", int32(mockResp.RecvMsg.Type), int32(msg.Type))) 187 s.respIndex = s.respIndex + 1 188 return nil 189 } 190 } 191 } 192 193 if mockResp.RespMsg != nil { 194 var ccMsg *pb.ChaincodeMessage 195 if ccMsg, _ = mockResp.RespMsg.(*pb.ChaincodeMessage); ccMsg == nil { 196 if ccMsgFunc, ok := mockResp.RespMsg.(func(*pb.ChaincodeMessage) *pb.ChaincodeMessage); ok && ccMsgFunc != nil { 197 ccMsg = ccMsgFunc(msg) 198 } 199 } 200 201 if ccMsg == nil { 202 panic("----no pb.ChaincodeMessage---") 203 } 204 err = s.Send(ccMsg) 205 } 206 207 s.respIndex = s.respIndex + 1 208 209 if s.respIndex == len(s.respSet.Responses) { 210 if s.respSet.DoneFunc != nil { 211 s.respSet.DoneFunc(s.respIndex, nil) 212 } 213 } 214 } 215 return err 216 }