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