github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/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 recvStream chan *pb.ChaincodeMessage 59 sendStream chan *pb.ChaincodeMessage 60 respIndex int 61 respSet *MockResponseSet 62 pong bool 63 } 64 65 func (s *MockCCComm) SetName(newname string) { 66 s.name = newname 67 } 68 69 //Send sends a message 70 func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error { 71 defer func() { 72 recover() 73 }() 74 s.sendStream <- msg 75 return nil 76 } 77 78 //Recv receives a message 79 func (s *MockCCComm) Recv() (*pb.ChaincodeMessage, error) { 80 msg := <-s.recvStream 81 return msg, nil 82 } 83 84 //CloseSend closes send 85 func (s *MockCCComm) CloseSend() error { 86 return nil 87 } 88 89 //GetRecvStream returns the recvStream 90 func (s *MockCCComm) GetRecvStream() chan *pb.ChaincodeMessage { 91 return s.recvStream 92 } 93 94 //GetSendStream returns the sendStream 95 func (s *MockCCComm) GetSendStream() chan *pb.ChaincodeMessage { 96 return s.sendStream 97 } 98 99 //Quit closes the channels...this will also close chaincode side 100 func (s *MockCCComm) Quit() { 101 if s.recvStream != nil { 102 close(s.recvStream) 103 s.recvStream = nil 104 } 105 106 if s.sendStream != nil { 107 close(s.sendStream) 108 s.sendStream = nil 109 } 110 } 111 112 //SetBailOnError will cause Run to return on any error 113 func (s *MockCCComm) SetBailOnError(b bool) { 114 s.bailOnError = b 115 } 116 117 //SetPong pongs received keepalive. This mut be done on the chaincode only 118 func (s *MockCCComm) SetPong(val bool) { 119 s.pong = val 120 } 121 122 //SetKeepAlive sets keepalive. This mut be done on the server only 123 func (s *MockCCComm) SetKeepAlive(ka *pb.ChaincodeMessage) { 124 s.keepAlive = ka 125 } 126 127 //SetResponses sets responses for an Init or Invoke 128 func (s *MockCCComm) SetResponses(respSet *MockResponseSet) { 129 s.respSet = respSet 130 s.respIndex = 0 131 } 132 133 //keepAlive 134 func (s *MockCCComm) ka() { 135 defer recover() 136 for { 137 if s.keepAlive == nil { 138 return 139 } 140 s.Send(s.keepAlive) 141 time.Sleep(10 * time.Millisecond) 142 } 143 } 144 145 //Run receives and sends indefinitely 146 func (s *MockCCComm) Run() error { 147 //start the keepalive 148 go s.ka() 149 150 //if we started keep alive this will kill it 151 defer func() { 152 s.keepAlive = nil 153 }() 154 155 for { 156 msg, err := s.Recv() 157 158 if err != nil { 159 return err 160 } 161 162 if err = s.respond(msg); err != nil { 163 if s.bailOnError { 164 return err 165 } 166 } 167 } 168 } 169 170 func (s *MockCCComm) respond(msg *pb.ChaincodeMessage) error { 171 if msg != nil && msg.Type == pb.ChaincodeMessage_KEEPALIVE { 172 //if ping should be ponged, pong 173 if s.pong { 174 return s.Send(msg) 175 } 176 return nil 177 } 178 179 var err error 180 if s.respIndex < len(s.respSet.Responses) { 181 mockResp := s.respSet.Responses[s.respIndex] 182 if mockResp.RecvMsg != nil { 183 if msg.Type != mockResp.RecvMsg.Type { 184 if s.respSet.ErrorFunc != nil { 185 s.respSet.ErrorFunc(s.respIndex, fmt.Errorf("Invalid message expected %d received %d", int32(mockResp.RecvMsg.Type), int32(msg.Type))) 186 s.respIndex = s.respIndex + 1 187 return nil 188 } 189 } 190 } 191 192 if mockResp.RespMsg != nil { 193 var ccMsg *pb.ChaincodeMessage 194 if ccMsg, _ = mockResp.RespMsg.(*pb.ChaincodeMessage); ccMsg == nil { 195 if ccMsgFunc, ok := mockResp.RespMsg.(func(*pb.ChaincodeMessage) *pb.ChaincodeMessage); ok && ccMsgFunc != nil { 196 ccMsg = ccMsgFunc(msg) 197 } 198 } 199 200 if ccMsg == nil { 201 panic("----no pb.ChaincodeMessage---") 202 } 203 err = s.Send(ccMsg) 204 } 205 206 s.respIndex = s.respIndex + 1 207 208 if s.respIndex == len(s.respSet.Responses) { 209 if s.respSet.DoneFunc != nil { 210 s.respSet.DoneFunc(s.respIndex, nil) 211 } 212 } 213 } 214 return err 215 }