github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/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  }