github.com/ewagmig/fabric@v2.1.1+incompatible/core/chaincode/mock/mockccstream.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package mock 8 9 import ( 10 "fmt" 11 "sync" 12 "time" 13 14 pb "github.com/hyperledger/fabric-protos-go/peer" 15 ) 16 17 //MockResponseSet is used for processing CC to Peer comm 18 //such as GET/PUT/DEL state. The MockResponse contains the 19 //response to be returned for each input received.from the 20 //CC. Every stub call will generate a response 21 type MockResponseSet struct { 22 //DoneFunc is invoked when all I/O is done for this 23 //response set 24 DoneFunc func(int, error) 25 26 //ErrorFunc is invoked at any step when the input does not 27 //match the received message 28 ErrorFunc func(int, error) 29 30 //Responses contained the expected received message (optional) 31 //and response to send (optional) 32 Responses []*MockResponse 33 } 34 35 //MockResponse contains the expected received message (optional) 36 //and response to send (optional) 37 type MockResponse struct { 38 RecvMsg *pb.ChaincodeMessage 39 RespMsg interface{} 40 } 41 42 // MockCCComm implements the mock communication between chaincode and peer 43 // We'd need two MockCCComm for communication. The receiver and sender will 44 // be switched between the two. 45 type MockCCComm struct { 46 name string 47 bailOnError bool 48 keepAlive *pb.ChaincodeMessage 49 recvStream chan *pb.ChaincodeMessage 50 sendStream chan *pb.ChaincodeMessage 51 respIndex int 52 respLock sync.Mutex 53 respSet *MockResponseSet 54 pong bool 55 skipClose bool 56 } 57 58 func (s *MockCCComm) SetName(newname string) { 59 s.name = newname 60 } 61 62 //Send sends a message 63 func (s *MockCCComm) Send(msg *pb.ChaincodeMessage) error { 64 s.sendStream <- msg 65 return nil 66 } 67 68 //Recv receives a message 69 func (s *MockCCComm) Recv() (*pb.ChaincodeMessage, error) { 70 msg := <-s.recvStream 71 return msg, nil 72 } 73 74 //CloseSend closes send 75 func (s *MockCCComm) CloseSend() error { 76 return nil 77 } 78 79 //GetRecvStream returns the recvStream 80 func (s *MockCCComm) GetRecvStream() chan *pb.ChaincodeMessage { 81 return s.recvStream 82 } 83 84 //GetSendStream returns the sendStream 85 func (s *MockCCComm) GetSendStream() chan *pb.ChaincodeMessage { 86 return s.sendStream 87 } 88 89 //Quit closes the channels... 90 func (s *MockCCComm) Quit() { 91 if !s.skipClose { 92 close(s.recvStream) 93 close(s.sendStream) 94 } 95 } 96 97 //SetBailOnError will cause Run to return on any error 98 func (s *MockCCComm) SetBailOnError(b bool) { 99 s.bailOnError = b 100 } 101 102 //SetPong pongs received keepalive. This mut be done on the chaincode only 103 func (s *MockCCComm) SetPong(val bool) { 104 s.pong = val 105 } 106 107 //SetKeepAlive sets keepalive. This mut be done on the server only 108 func (s *MockCCComm) SetKeepAlive(ka *pb.ChaincodeMessage) { 109 s.keepAlive = ka 110 } 111 112 //SetResponses sets responses for an Init or Invoke 113 func (s *MockCCComm) SetResponses(respSet *MockResponseSet) { 114 s.respLock.Lock() 115 s.respSet = respSet 116 s.respIndex = 0 117 s.respLock.Unlock() 118 } 119 120 //keepAlive 121 func (s *MockCCComm) ka(done <-chan struct{}) { 122 for { 123 if s.keepAlive == nil { 124 return 125 } 126 s.Send(s.keepAlive) 127 select { 128 case <-time.After(10 * time.Millisecond): 129 case <-done: 130 return 131 } 132 } 133 } 134 135 //Run receives and sends indefinitely 136 func (s *MockCCComm) Run(done <-chan struct{}) error { 137 //start the keepalive 138 go s.ka(done) 139 defer s.Quit() 140 141 for { 142 msg, err := s.Recv() 143 144 //stream could just be closed 145 if msg == nil { 146 return err 147 } 148 149 if err != nil { 150 return err 151 } 152 153 if err = s.respond(msg); err != nil { 154 if s.bailOnError { 155 return err 156 } 157 } 158 } 159 } 160 161 func (s *MockCCComm) respond(msg *pb.ChaincodeMessage) error { 162 if msg != nil && msg.Type == pb.ChaincodeMessage_KEEPALIVE { 163 //if ping should be ponged, pong 164 if s.pong { 165 return s.Send(msg) 166 } 167 return nil 168 } 169 170 s.respLock.Lock() 171 defer s.respLock.Unlock() 172 173 var err error 174 if s.respIndex < len(s.respSet.Responses) { 175 mockResp := s.respSet.Responses[s.respIndex] 176 if mockResp.RecvMsg != nil { 177 if msg.Type != mockResp.RecvMsg.Type { 178 if s.respSet.ErrorFunc != nil { 179 s.respSet.ErrorFunc(s.respIndex, fmt.Errorf("Invalid message expected %d received %d", int32(mockResp.RecvMsg.Type), int32(msg.Type))) 180 s.respIndex = s.respIndex + 1 181 return nil 182 } 183 } 184 } 185 186 if mockResp.RespMsg != nil { 187 var ccMsg *pb.ChaincodeMessage 188 if ccMsg, _ = mockResp.RespMsg.(*pb.ChaincodeMessage); ccMsg == nil { 189 if ccMsgFunc, ok := mockResp.RespMsg.(func(*pb.ChaincodeMessage) *pb.ChaincodeMessage); ok && ccMsgFunc != nil { 190 ccMsg = ccMsgFunc(msg) 191 } 192 } 193 194 if ccMsg == nil { 195 panic("----no pb.ChaincodeMessage---") 196 } 197 err = s.Send(ccMsg) 198 } 199 200 s.respIndex = s.respIndex + 1 201 202 if s.respIndex == len(s.respSet.Responses) { 203 if s.respSet.DoneFunc != nil { 204 s.respSet.DoneFunc(s.respIndex, nil) 205 } 206 } 207 } 208 return err 209 }