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  }