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