github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/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 "sync" 22 "time" 23 24 pb "github.com/hyperledger/fabric-protos-go/peer" 25 ) 26 27 //MockResponseSet is used for processing CC to Peer comm 28 //such as GET/PUT/DEL state. The MockResponse contains the 29 //response to be returned for each input received.from the 30 //CC. Every stub call will generate a response 31 type MockResponseSet struct { 32 //DoneFunc is invoked when all I/O is done for this 33 //response set 34 DoneFunc func(int, error) 35 36 //ErrorFunc is invoked at any step when the input does not 37 //match the received message 38 ErrorFunc func(int, error) 39 40 //Responses contained the expected received message (optional) 41 //and response to send (optional) 42 Responses []*MockResponse 43 } 44 45 //MockResponse contains the expected received message (optional) 46 //and response to send (optional) 47 type MockResponse struct { 48 RecvMsg *pb.ChaincodeMessage 49 RespMsg interface{} 50 } 51 52 // MockCCComm implements the mock communication between chaincode and peer 53 // We'd need two MockCCComm for communication. The receiver and sender will 54 // be switched between the two. 55 type MockCCComm struct { 56 name string 57 bailOnError bool 58 keepAlive *pb.ChaincodeMessage 59 recvStream chan *pb.ChaincodeMessage 60 sendStream chan *pb.ChaincodeMessage 61 respIndex int 62 respLock sync.Mutex 63 respSet *MockResponseSet 64 pong bool 65 skipClose bool 66 } 67 68 func (s *MockCCComm) SetName(newname string) { 69 s.name = newname 70 } 71 72 //Send sends a message 73 func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error { 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... 100 func (s *MockCCComm) Quit() { 101 if !s.skipClose { 102 close(s.recvStream) 103 close(s.sendStream) 104 } 105 } 106 107 //SetBailOnError will cause Run to return on any error 108 func (s *MockCCComm) SetBailOnError(b bool) { 109 s.bailOnError = b 110 } 111 112 //SetPong pongs received keepalive. This mut be done on the chaincode only 113 func (s *MockCCComm) SetPong(val bool) { 114 s.pong = val 115 } 116 117 //SetKeepAlive sets keepalive. This mut be done on the server only 118 func (s *MockCCComm) SetKeepAlive(ka *pb.ChaincodeMessage) { 119 s.keepAlive = ka 120 } 121 122 //SetResponses sets responses for an Init or Invoke 123 func (s *MockCCComm) SetResponses(respSet *MockResponseSet) { 124 s.respLock.Lock() 125 s.respSet = respSet 126 s.respIndex = 0 127 s.respLock.Unlock() 128 } 129 130 //keepAlive 131 func (s *MockCCComm) ka(done <-chan struct{}) { 132 for { 133 if s.keepAlive == nil { 134 return 135 } 136 s.Send(s.keepAlive) 137 select { 138 case <-time.After(10 * time.Millisecond): 139 case <-done: 140 return 141 } 142 } 143 } 144 145 //Run receives and sends indefinitely 146 func (s *MockCCComm) Run(done <-chan struct{}) error { 147 //start the keepalive 148 go s.ka(done) 149 defer s.Quit() 150 151 for { 152 msg, err := s.Recv() 153 154 //stream could just be closed 155 if msg == nil { 156 return err 157 } 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 s.respLock.Lock() 181 defer s.respLock.Unlock() 182 183 var err error 184 if s.respIndex < len(s.respSet.Responses) { 185 mockResp := s.respSet.Responses[s.respIndex] 186 if mockResp.RecvMsg != nil { 187 if msg.Type != mockResp.RecvMsg.Type { 188 if s.respSet.ErrorFunc != nil { 189 s.respSet.ErrorFunc(s.respIndex, fmt.Errorf("Invalid message expected %d received %d", int32(mockResp.RecvMsg.Type), int32(msg.Type))) 190 s.respIndex = s.respIndex + 1 191 return nil 192 } 193 } 194 } 195 196 if mockResp.RespMsg != nil { 197 var ccMsg *pb.ChaincodeMessage 198 if ccMsg, _ = mockResp.RespMsg.(*pb.ChaincodeMessage); ccMsg == nil { 199 if ccMsgFunc, ok := mockResp.RespMsg.(func(*pb.ChaincodeMessage) *pb.ChaincodeMessage); ok && ccMsgFunc != nil { 200 ccMsg = ccMsgFunc(msg) 201 } 202 } 203 204 if ccMsg == nil { 205 panic("----no pb.ChaincodeMessage---") 206 } 207 err = s.Send(ccMsg) 208 } 209 210 s.respIndex = s.respIndex + 1 211 212 if s.respIndex == len(s.respSet.Responses) { 213 if s.respSet.DoneFunc != nil { 214 s.respSet.DoneFunc(s.respIndex, nil) 215 } 216 } 217 } 218 return err 219 }