github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/bddtests/steps/orderer_util.py (about)

     1  
     2  # Copyright IBM Corp. 2016 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  import os
    18  import re
    19  import time
    20  import datetime
    21  import Queue
    22  import subprocess
    23  import devops_pb2
    24  import fabric_pb2
    25  import chaincode_pb2
    26  from orderer import ab_pb2
    27  from common import common_pb2
    28  
    29  import bdd_test_util
    30  import bdd_grpc_util
    31  
    32  from grpc.beta import implementations
    33  from grpc.framework.interfaces.face.face import NetworkError
    34  from grpc.framework.interfaces.face.face import AbortionError
    35  from grpc.beta.interfaces import StatusCode
    36  from common.common_pb2 import Payload
    37  
    38  # The default chain ID when the system is statically bootstrapped for testing
    39  TEST_CHAIN_ID = "testchainid"
    40  
    41  def _defaultDataFunction(index):
    42      payload = common_pb2.Payload(
    43          header = common_pb2.Header(
    44              chainHeader = common_pb2.ChainHeader(
    45                  chainID = TEST_CHAIN_ID,
    46                  type = common_pb2.ENDORSER_TRANSACTION,
    47              ),
    48              signatureHeader = common_pb2.SignatureHeader(),
    49          ),
    50          data = str("BDD test: {0}".format(datetime.datetime.utcnow())),
    51      )
    52      envelope = common_pb2.Envelope(
    53          payload = payload.SerializeToString()
    54      )
    55      return envelope
    56  
    57  
    58  class StreamHelper:
    59  
    60      def __init__(self):
    61          self.streamClosed = False
    62          self.sendQueue = Queue.Queue()
    63          self.receivedMessages = []
    64          self.replyGenerator = None
    65  
    66      def setReplyGenerator(self, replyGenerator):
    67          assert self.replyGenerator == None, "reply generator already set!!"
    68          self.replyGenerator = replyGenerator
    69  
    70      def createSendGenerator(self, timeout = 2):
    71        while True:
    72          try:
    73              nextMsg = self.sendQueue.get(True, timeout)
    74              if nextMsg:
    75                yield nextMsg
    76              else:
    77                #None indicates desire to close send
    78                return
    79          except Queue.Empty:
    80              return
    81  
    82      def readMessage(self):
    83          for reply in self.readMessages(1):
    84              return reply
    85          assert False, "Received no messages"
    86  
    87      def readMessages(self, expectedCount):
    88          msgsReceived = []
    89          counter = 0
    90          try:
    91              for reply in self.replyGenerator:
    92                  counter += 1
    93                  #print("received reply: {0}, counter = {1}".format(reply, counter))
    94                  msgsReceived.append(reply)
    95                  if counter == int(expectedCount):
    96                      break
    97          except AbortionError as networkError:
    98              self.handleNetworkError(networkError)
    99          return msgsReceived
   100  
   101      def handleNetworkError(self, networkError):
   102          if networkError.code == StatusCode.OUT_OF_RANGE and networkError.details == "EOF":
   103              print("Error received and ignored: {0}".format(networkError))
   104              print()
   105              self.streamClosed = True
   106          else:
   107              raise Exception("Unexpected NetworkError: {0}".format(networkError))
   108  
   109  
   110  class DeliverStreamHelper(StreamHelper):
   111  
   112      def __init__(self, ordererStub, timeout = 1):
   113          StreamHelper.__init__(self)
   114          # Set the UpdateMessage and start the stream
   115          sendGenerator = self.createSendGenerator(timeout)
   116          self.replyGenerator = ordererStub.Deliver(sendGenerator, timeout + 1)
   117  
   118      def seekToRange(self, chainID = TEST_CHAIN_ID, start = 'Oldest', end = 'Newest'):
   119          self.sendQueue.put(createSeekInfo(start = start, chainID = chainID))
   120  
   121      def getBlocks(self):
   122          blocks = []
   123          try:
   124              while True:
   125                  reply = self.readMessage()
   126                  if reply.HasField("block"):
   127                      blocks.append(reply.block)
   128                      #print("received reply: {0}, len(blocks) = {1}".format(reply, len(blocks)))
   129                  else:
   130                      if reply.status != common_pb2.SUCCESS:
   131                          print("Got error: {0}".format(reply.status))
   132                      print("Done receiving blocks")
   133                      break
   134          except Exception as e:
   135              print("getBlocks got error: {0}".format(e) )
   136          return blocks
   137  
   138  
   139  class UserRegistration:
   140  
   141      def __init__(self, userName):
   142          self.userName= userName
   143          self.tags = {}
   144          # Dictionary of composeService->atomic broadcast grpc Stub
   145          self.atomicBroadcastStubsDict = {}
   146          # composeService->StreamHelper
   147          self.abDeliversStreamHelperDict = {}
   148  
   149      def getUserName(self):
   150          return self.userName
   151  
   152      def connectToDeliverFunction(self, context, composeService, timeout=1):
   153          'Connect to the deliver function and drain messages to associated orderer queue'
   154          assert not composeService in self.abDeliversStreamHelperDict, "Already connected to deliver stream on {0}".format(composeService)
   155          streamHelper = DeliverStreamHelper(self.getABStubForComposeService(context, composeService))
   156          self.abDeliversStreamHelperDict[composeService] = streamHelper
   157          return streamHelper
   158  
   159      def getDelivererStreamHelper(self, context, composeService):
   160          assert composeService in self.abDeliversStreamHelperDict, "NOT connected to deliver stream on {0}".format(composeService)
   161          return self.abDeliversStreamHelperDict[composeService]
   162  
   163      def broadcastMessages(self, context, numMsgsToBroadcast, composeService, chainID=TEST_CHAIN_ID, dataFunc=_defaultDataFunction):
   164          abStub = self.getABStubForComposeService(context, composeService)
   165          replyGenerator = abStub.Broadcast(generateBroadcastMessages(chainID=chainID, numToGenerate = int(numMsgsToBroadcast), dataFunc=dataFunc), 2)
   166          counter = 0
   167          try:
   168              for reply in replyGenerator:
   169                  counter += 1
   170                  print("{0} received reply: {1}, counter = {2}".format(self.getUserName(), reply, counter))
   171                  if counter == int(numMsgsToBroadcast):
   172                      break
   173          except Exception as e:
   174              print("Got error: {0}".format(e) )
   175              print("Got error")
   176          print("Done")
   177          assert counter == int(numMsgsToBroadcast), "counter = {0}, expected {1}".format(counter, numMsgsToBroadcast)
   178  
   179      def getABStubForComposeService(self, context, composeService):
   180          'Return a Stub for the supplied composeService, will cache'
   181          if composeService in self.atomicBroadcastStubsDict:
   182              return self.atomicBroadcastStubsDict[composeService]
   183          # Get the IP address of the server that the user registered on
   184          channel = getGRPCChannel(*bdd_test_util.getPortHostMapping(context.compose_containers, composeService, 7050))
   185          newABStub = ab_pb2.beta_create_AtomicBroadcast_stub(channel)
   186          self.atomicBroadcastStubsDict[composeService] = newABStub
   187          return newABStub
   188  
   189  
   190  # Registerses a user on a specific composeService
   191  def registerUser(context, secretMsg, composeService):
   192      userName = secretMsg['enrollId']
   193      if 'ordererUsers' in context:
   194          pass
   195      else:
   196          context.ordererUsers = {}
   197      if userName in context.ordererUsers:
   198          raise Exception("Orderer user already registered: {0}".format(userName))
   199      userRegistration = UserRegistration(secretMsg)
   200      context.ordererUsers[userName] = userRegistration
   201      return userRegistration
   202  
   203  def getUserRegistration(context, enrollId):
   204      userRegistration = None
   205      if 'ordererUsers' in context:
   206          pass
   207      else:
   208          ordererContext.ordererUsers = {}
   209      if enrollId in context.ordererUsers:
   210          userRegistration = context.ordererUsers[enrollId]
   211      else:
   212          raise Exception("Orderer user has not been registered: {0}".format(enrollId))
   213      return userRegistration
   214  
   215  def seekPosition(position):
   216      if position == 'Oldest':
   217          return ab_pb2.SeekPosition(oldest = ab_pb2.SeekOldest())
   218      elif  position == 'Newest':
   219          return ab_pb2.SeekPosition(newest = ab_pb2.SeekNewest())
   220      else:
   221          return ab_pb2.SeekPosition(specified = ab_pb2.SeekSpecified(number = position))
   222  
   223  def convertSeek(utfString):
   224      try:
   225          return int(utfString)
   226      except ValueError:
   227          return str(utfString)
   228  
   229  def createSeekInfo(chainID = TEST_CHAIN_ID, start = 'Oldest', end = 'Newest',  behavior = 'FAIL_IF_NOT_READY'):
   230      return common_pb2.Envelope(
   231          payload = common_pb2.Payload(
   232              header = common_pb2.Header(
   233                  channel_header = common_pb2.ChannelHeader( channel_id = chainID ),
   234                  signature_header = common_pb2.SignatureHeader(),
   235              ),
   236              data = ab_pb2.SeekInfo(
   237                  start = seekPosition(start),
   238                  stop = seekPosition(end),
   239                  behavior = ab_pb2.SeekInfo.SeekBehavior.Value(behavior),
   240              ).SerializeToString(),
   241          ).SerializeToString(),
   242      )
   243  
   244  
   245  def generateBroadcastMessages(chainID = TEST_CHAIN_ID, numToGenerate = 3, timeToHoldOpen = 1, dataFunc =_defaultDataFunction):
   246      messages = []
   247      for i in range(0, numToGenerate):
   248          messages.append(dataFunc(i))
   249      for msg in messages:
   250          yield msg
   251      time.sleep(timeToHoldOpen)
   252  
   253  
   254  def getGRPCChannel(host='localhost', port=7050):
   255      channel = implementations.insecure_channel(host, port)
   256      print("Returning GRPC for address: {0}:{1}".format(host,port))
   257      return channel