github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/bddtests/steps/peer_basic_impl.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 os.path 19 import re 20 import time 21 import copy 22 from behave import * 23 from datetime import datetime, timedelta 24 import base64 25 import uuid 26 27 import sys, requests, json 28 29 import bdd_test_util 30 import compose 31 import bootstrap_util 32 33 CORE_REST_PORT = 7050 34 JSONRPC_VERSION = "2.0" 35 36 class ContainerData: 37 def __init__(self, containerName, ipAddress, envFromInspect, composeService, ports): 38 self.containerName = containerName 39 self.ipAddress = ipAddress 40 self.envFromInspect = envFromInspect 41 self.composeService = composeService 42 self.ports = ports 43 44 def getEnv(self, key): 45 envValue = None 46 for val in self.envFromInspect: 47 if val.startswith(key): 48 envValue = val[len(key):] 49 break 50 if envValue == None: 51 raise Exception("ENV key not found ({0}) for container ({1})".format(key, self.containerName)) 52 return envValue 53 54 def buildUrl(context, ipAddress, path): 55 schema = "http" 56 if 'TLS' in context.tags: 57 schema = "https" 58 return "{0}://{1}:{2}{3}".format(schema, ipAddress, CORE_REST_PORT, path) 59 60 def currentTime(): 61 return time.strftime("%H:%M:%S") 62 63 def getDockerComposeFileArgsFromYamlFile(compose_yaml): 64 parts = compose_yaml.split() 65 args = [] 66 for part in parts: 67 args = args + ["-f"] + [part] 68 return args 69 70 @given(u'we compose "{composeYamlFile}"') 71 def step_impl(context, composeYamlFile): 72 # time.sleep(10) # Should be replaced with a definitive interlock guaranteeing that all peers/membersrvc are ready 73 composition = compose.Composition(context, composeYamlFile) 74 context.compose_containers = composition.containerDataList 75 context.composition = composition 76 77 @when(u'requesting "{path}" from "{containerName}"') 78 def step_impl(context, path, containerName): 79 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 80 request_url = buildUrl(context, ipAddress, path) 81 print("Requesting path = {0}".format(request_url)) 82 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 83 assert resp.status_code == 200, "Failed to GET url %s: %s" % (request_url,resp.text) 84 context.response = resp 85 print("") 86 87 @then(u'I should get a JSON response containing "{attribute}" attribute') 88 def step_impl(context, attribute): 89 getAttributeFromJSON(attribute, context.response.json(), "Attribute not found in response (%s)" %(attribute)) 90 91 @then(u'I should get a JSON response containing no "{attribute}" attribute') 92 def step_impl(context, attribute): 93 try: 94 getAttributeFromJSON(attribute, context.response.json(), "") 95 assert None, "Attribute found in response (%s)" %(attribute) 96 except AssertionError: 97 print("Attribute not found as was expected.") 98 99 def getAttributeFromJSON(attribute, jsonObject, msg): 100 return getHierarchyAttributesFromJSON(attribute.split("."), jsonObject, msg) 101 102 def getHierarchyAttributesFromJSON(attributes, jsonObject, msg): 103 if len(attributes) > 0: 104 assert attributes[0] in jsonObject, msg 105 return getHierarchyAttributesFromJSON(attributes[1:], jsonObject[attributes[0]], msg) 106 return jsonObject 107 108 def formatStringToCompare(value): 109 # double quotes are replaced by simple quotes because is not possible escape double quotes in the attribute parameters. 110 return str(value).replace("\"", "'") 111 112 @then(u'I should get a JSON response with "{attribute}" = "{expectedValue}"') 113 def step_impl(context, attribute, expectedValue): 114 foundValue = getAttributeFromJSON(attribute, context.response.json(), "Attribute not found in response (%s)" %(attribute)) 115 assert (formatStringToCompare(foundValue) == expectedValue), "For attribute %s, expected (%s), instead found (%s)" % (attribute, expectedValue, foundValue) 116 117 @then(u'I should get a JSON response with array "{attribute}" contains "{expectedValue}" elements') 118 def step_impl(context, attribute, expectedValue): 119 foundValue = getAttributeFromJSON(attribute, context.response.json(), "Attribute not found in response (%s)" %(attribute)) 120 assert (len(foundValue) == int(expectedValue)), "For attribute %s, expected array of size (%s), instead found (%s)" % (attribute, expectedValue, len(foundValue)) 121 122 @given(u'I wait "{seconds}" seconds') 123 def step_impl(context, seconds): 124 time.sleep(float(seconds)) 125 126 @when(u'I wait "{seconds}" seconds') 127 def step_impl(context, seconds): 128 time.sleep(float(seconds)) 129 130 @then(u'I wait "{seconds}" seconds') 131 def step_impl(context, seconds): 132 time.sleep(float(seconds)) 133 134 @when(u'I deploy lang chaincode "{chaincodePath}" of "{chainLang}" with ctor "{ctor}" to "{containerName}"') 135 def step_impl(context, chaincodePath, chainLang, ctor, containerName): 136 print("Printing chaincode language " + chainLang) 137 138 chaincode = { 139 "path": chaincodePath, 140 "language": chainLang, 141 "constructor": ctor, 142 "args": getArgsFromContext(context), 143 } 144 145 deployChainCodeToContainer(context, chaincode, containerName) 146 147 def getArgsFromContext(context): 148 args = [] 149 if 'table' in context: 150 # There is ctor arguments 151 args = context.table[0].cells 152 return args 153 154 @when(u'I deploy chaincode "{chaincodePath}" with ctor "{ctor}" to "{containerName}"') 155 def step_impl(context, chaincodePath, ctor, containerName): 156 chaincode = { 157 "path": chaincodePath, 158 "language": "GOLANG", 159 "constructor": ctor, 160 "args": getArgsFromContext(context), 161 } 162 163 deployChainCodeToContainer(context, chaincode, containerName) 164 165 @when(u'I deploy chaincode with name "{chaincodeName}" and with ctor "{ctor}" to "{containerName}"') 166 def step_impl(context, chaincodeName, ctor, containerName): 167 chaincode = { 168 "name": chaincodeName, 169 "language": "GOLANG", 170 "constructor": ctor, 171 "args": getArgsFromContext(context), 172 } 173 174 deployChainCodeToContainer(context, chaincode, containerName) 175 time.sleep(2.0) # After #2068 implemented change this to only apply after a successful ping 176 177 def deployChainCodeToContainer(context, chaincode, containerName): 178 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 179 request_url = buildUrl(context, ipAddress, "/chaincode") 180 print("Requesting path = {0}".format(request_url)) 181 182 chaincodeSpec = createChaincodeSpec(context, chaincode) 183 chaincodeOpPayload = createChaincodeOpPayload("deploy", chaincodeSpec) 184 185 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeOpPayload), verify=False) 186 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 187 context.response = resp 188 chaincodeName = resp.json()['result']['message'] 189 chaincodeSpec['chaincodeID']['name'] = chaincodeName 190 context.chaincodeSpec = chaincodeSpec 191 print(json.dumps(chaincodeSpec, indent=4)) 192 print("") 193 194 def createChaincodeSpec(context, chaincode): 195 chaincode = validateChaincodeDictionary(chaincode) 196 args = prepend(chaincode["constructor"], chaincode["args"]) 197 # Create a ChaincodeSpec structure 198 chaincodeSpec = { 199 "type": getChaincodeTypeValue(chaincode["language"]), 200 "chaincodeID": { 201 "path" : chaincode["path"], 202 "name" : chaincode["name"] 203 }, 204 "ctorMsg": { 205 "args" : args 206 }, 207 } 208 209 if 'userName' in context: 210 chaincodeSpec["secureContext"] = context.userName 211 if 'metadata' in context: 212 chaincodeSpec["metadata"] = context.metadata 213 214 return chaincodeSpec 215 216 def validateChaincodeDictionary(chaincode): 217 chaincodeFields = ["path", "name", "language", "constructor", "args"] 218 219 for field in chaincodeFields: 220 if field not in chaincode: 221 chaincode[field] = "" 222 223 return chaincode 224 225 def getChaincodeTypeValue(chainLang): 226 if chainLang == "GOLANG": 227 return 1 228 elif chainLang =="JAVA": 229 return 4 230 elif chainLang == "NODE": 231 return 2 232 elif chainLang == "CAR": 233 return 3 234 elif chainLang == "UNDEFINED": 235 return 0 236 return 1 237 238 @when(u'I mock deploy chaincode with name "{chaincodeName}"') 239 def step_impl(context, chaincodeName): 240 chaincode = { 241 "name": chaincodeName, 242 "language": "GOLANG" 243 } 244 245 context.chaincodeSpec = createChaincodeSpec(context, chaincode) 246 247 @then(u'I should have received a chaincode name') 248 def step_impl(context): 249 if 'chaincodeSpec' in context: 250 assert context.chaincodeSpec['chaincodeID']['name'] != "" 251 # Set the current transactionID to the name passed back 252 context.transactionID = context.chaincodeSpec['chaincodeID']['name'] 253 elif 'grpcChaincodeSpec' in context: 254 assert context.grpcChaincodeSpec.chaincodeID.name != "" 255 # Set the current transactionID to the name passed back 256 context.transactionID = context.grpcChaincodeSpec.chaincodeID.name 257 else: 258 fail('chaincodeSpec not in context') 259 260 @when(u'I invoke chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}" with "{idGenAlg}"') 261 def step_impl(context, chaincodeName, functionName, containerName, idGenAlg): 262 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 263 invokeChaincode(context, "invoke", functionName, containerName, idGenAlg) 264 265 @when(u'I invoke chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}" "{times}" times') 266 def step_impl(context, chaincodeName, functionName, containerName, times): 267 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 268 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 269 request_url = buildUrl(context, ipAddress, "/chain") 270 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 271 assert resp.status_code == 200, "Failed to get chain height %s: %s" % (request_url,resp.text) 272 context.chainheight = getAttributeFromJSON("height", resp.json(), "Height not found in response.") 273 context.txcount = times 274 for i in range(int(times)): 275 invokeChaincode(context, "invoke", functionName, containerName) 276 277 @when(u'I invoke chaincode "{chaincodeName}" function name "{functionName}" with attributes "{attrs}" on "{containerName}"') 278 def step_impl(context, chaincodeName, functionName, attrs, containerName): 279 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 280 assert attrs, "attrs were not specified" 281 invokeChaincode(context, "invoke", functionName, containerName, None, attrs.split(",")) 282 283 @when(u'I invoke chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}"') 284 def step_impl(context, chaincodeName, functionName, containerName): 285 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 286 invokeChaincode(context, "invoke", functionName, containerName) 287 288 @when(u'I invoke master chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}"') 289 def step_impl(context, chaincodeName, functionName, containerName): 290 invokeMasterChaincode(context, "invoke", chaincodeName, functionName, containerName) 291 292 @then(u'I should have received a transactionID') 293 def step_impl(context): 294 assert 'transactionID' in context, 'transactionID not found in context' 295 assert context.transactionID != "" 296 pass 297 298 @when(u'I unconditionally query chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}"') 299 def step_impl(context, chaincodeName, functionName, containerName): 300 invokeChaincode(context, "query", functionName, containerName) 301 302 @when(u'I query chaincode "{chaincodeName}" function name "{functionName}" on "{containerName}"') 303 def step_impl(context, chaincodeName, functionName, containerName): 304 invokeChaincode(context, "query", functionName, containerName) 305 306 def createChaincodeOpPayload(method, chaincodeSpec): 307 chaincodeOpPayload = { 308 "jsonrpc": JSONRPC_VERSION, 309 "method" : method, 310 "params" : chaincodeSpec, 311 "id" : 1 312 } 313 return chaincodeOpPayload 314 315 def invokeChaincode(context, devopsFunc, functionName, containerName, idGenAlg=None, attributes=[]): 316 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 317 # Update the chaincodeSpec ctorMsg for invoke 318 args = [] 319 if 'table' in context: 320 # There is ctor arguments 321 args = context.table[0].cells 322 args = prepend(functionName, args) 323 for idx, attr in enumerate(attributes): 324 attributes[idx] = attr.strip() 325 326 context.chaincodeSpec['attributes'] = attributes 327 328 #If idGenAlg is passed then, we still using the deprecated devops API because this parameter can't be passed in the new API. 329 if idGenAlg != None: 330 context.chaincodeSpec['ctorMsg']['args'] = to_bytes(args) 331 invokeUsingDevopsService(context, devopsFunc, functionName, containerName, idGenAlg) 332 else: 333 context.chaincodeSpec['ctorMsg']['args'] = args 334 invokeUsingChaincodeService(context, devopsFunc, functionName, containerName) 335 336 def invokeUsingChaincodeService(context, devopsFunc, functionName, containerName): 337 # Invoke the POST 338 chaincodeOpPayload = createChaincodeOpPayload(devopsFunc, context.chaincodeSpec) 339 340 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 341 342 request_url = buildUrl(context, ipAddress, "/chaincode") 343 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 344 print("Using attributes {0}".format(context.chaincodeSpec['attributes'])) 345 346 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeOpPayload), verify=False) 347 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 348 context.response = resp 349 print("RESULT from {0} of chaincode from peer {1}".format(functionName, containerName)) 350 print(json.dumps(context.response.json(), indent = 4)) 351 if 'result' in resp.json(): 352 result = resp.json()['result'] 353 if 'message' in result: 354 transactionID = result['message'] 355 context.transactionID = transactionID 356 357 def invokeUsingDevopsService(context, devopsFunc, functionName, containerName, idGenAlg): 358 # Invoke the POST 359 chaincodeInvocationSpec = { 360 "chaincodeSpec" : context.chaincodeSpec 361 } 362 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 363 if idGenAlg is not None: 364 chaincodeInvocationSpec['idGenerationAlg'] = idGenAlg 365 request_url = buildUrl(context, ipAddress, "/devops/{0}".format(devopsFunc)) 366 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 367 368 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeInvocationSpec), verify=False) 369 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 370 context.response = resp 371 print("RESULT from {0} of chaincode from peer {1}".format(functionName, containerName)) 372 print(json.dumps(context.response.json(), indent = 4)) 373 if 'message' in resp.json(): 374 transactionID = context.response.json()['message'] 375 context.transactionID = transactionID 376 377 def invokeMasterChaincode(context, devopsFunc, chaincodeName, functionName, containerName): 378 args = [] 379 if 'table' in context: 380 args = context.table[0].cells 381 args = prepend(functionName, args) 382 typeGolang = 1 383 chaincodeSpec = { 384 "type": typeGolang, 385 "chaincodeID": { 386 "name" : chaincodeName 387 }, 388 "ctorMsg": { 389 "args" : args 390 } 391 } 392 if 'userName' in context: 393 chaincodeSpec["secureContext"] = context.userName 394 395 chaincodeOpPayload = createChaincodeOpPayload(devopsFunc, chaincodeSpec) 396 397 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 398 request_url = buildUrl(context, ipAddress, "/chaincode") 399 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 400 401 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeOpPayload), verify=False) 402 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 403 context.response = resp 404 print("RESULT from {0} of chaincode from peer {1}".format(functionName, containerName)) 405 print(json.dumps(context.response.json(), indent = 4)) 406 if 'result' in resp.json(): 407 result = resp.json()['result'] 408 if 'message' in result: 409 transactionID = result['message'] 410 context.transactionID = transactionID 411 412 @then(u'I wait "{seconds}" seconds for chaincode to build') 413 def step_impl(context, seconds): 414 """ This step takes into account the chaincodeImagesUpToDate tag, in which case the wait is reduce to some default seconds""" 415 reducedWaitTime = 4 416 if 'chaincodeImagesUpToDate' in context.tags: 417 print("Assuming images are up to date, sleeping for {0} seconds instead of {1} in scenario {2}".format(reducedWaitTime, seconds, context.scenario.name)) 418 time.sleep(float(reducedWaitTime)) 419 else: 420 time.sleep(float(seconds)) 421 422 @then(u'I wait "{seconds}" seconds for transaction to be committed to block on "{containerName}"') 423 def step_impl(context, seconds, containerName): 424 assert 'transactionID' in context, "transactionID not found in context" 425 ipAddress = bdd_test_util.ipFromContainerNamePart(containerName, context.compose_containers) 426 request_url = buildUrl(context, ipAddress, "/transactions/{0}".format(context.transactionID)) 427 print("{0} GETing path = {1}".format(currentTime(), request_url)) 428 429 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 430 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 431 context.response = resp 432 433 def multiRequest(context, seconds, containerDataList, pathBuilderFunc): 434 """Perform a multi request against the system""" 435 # Build map of "containerName" : response 436 respMap = {container.containerName:None for container in containerDataList} 437 # Set the max time before stopping attempts 438 maxTime = datetime.now() + timedelta(seconds = int(seconds)) 439 for container in containerDataList: 440 ipAddress = container.ipAddress 441 request_url = buildUrl(context, ipAddress, pathBuilderFunc(context, container)) 442 443 # Loop unless failure or time exceeded 444 while (datetime.now() < maxTime): 445 print("{0} GETing path = {1}".format(currentTime(), request_url)) 446 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 447 respMap[container.containerName] = resp 448 else: 449 raise Exception("Max time exceeded waiting for multiRequest with current response map = {0}".format(respMap)) 450 451 @then(u'I wait up to "{seconds}" seconds for transaction to be committed to all peers') 452 def step_impl(context, seconds): 453 assert 'transactionID' in context, "transactionID not found in context" 454 assert 'compose_containers' in context, "compose_containers not found in context" 455 456 # Build map of "containerName" : resp.statusCode 457 respMap = {container.containerName:0 for container in context.compose_containers} 458 459 # Set the max time before stopping attempts 460 maxTime = datetime.now() + timedelta(seconds = int(seconds)) 461 for container in context.compose_containers: 462 ipAddress = container.ipAddress 463 request_url = buildUrl(context, ipAddress, "/transactions/{0}".format(context.transactionID)) 464 465 # Loop unless failure or time exceeded 466 while (datetime.now() < maxTime): 467 print("{0} GETing path = {1}".format(currentTime(), request_url)) 468 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 469 if resp.status_code == 404: 470 # Pause then try again 471 respMap[container.containerName] = 404 472 time.sleep(1) 473 continue 474 elif resp.status_code == 200: 475 # Success, continue 476 respMap[container.containerName] = 200 477 break 478 else: 479 raise Exception("Error requesting {0}, returned result code = {1}".format(request_url, resp.status_code)) 480 else: 481 raise Exception("Max time exceeded waiting for transactions with current response map = {0}".format(respMap)) 482 print("Result of request to all peers = {0}".format(respMap)) 483 print("") 484 485 @then(u'I check the transaction ID if it is "{tUUID}"') 486 def step_impl(context, tUUID): 487 assert 'transactionID' in context, "transactionID not found in context" 488 assert context.transactionID == tUUID, "transactionID is not tUUID" 489 490 @then(u'I wait up to "{seconds}" seconds for transaction to be committed to peers') 491 def step_impl(context, seconds): 492 assert 'transactionID' in context, "transactionID not found in context" 493 assert 'compose_containers' in context, "compose_containers not found in context" 494 assert 'table' in context, "table (of peers) not found in context" 495 496 aliases = context.table.headings 497 containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData) 498 499 # Build map of "containerName" : resp.statusCode 500 respMap = {container.containerName:0 for container in containerDataList} 501 502 # Set the max time before stopping attempts 503 maxTime = datetime.now() + timedelta(seconds = int(seconds)) 504 for container in containerDataList: 505 ipAddress = container.ipAddress 506 request_url = buildUrl(context, ipAddress, "/transactions/{0}".format(context.transactionID)) 507 508 # Loop unless failure or time exceeded 509 while (datetime.now() < maxTime): 510 print("{0} GETing path = {1}".format(currentTime(), request_url)) 511 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 512 if resp.status_code == 404: 513 # Pause then try again 514 respMap[container.containerName] = 404 515 time.sleep(1) 516 continue 517 elif resp.status_code == 200: 518 # Success, continue 519 respMap[container.containerName] = 200 520 break 521 else: 522 raise Exception("Error requesting {0}, returned result code = {1}".format(request_url, resp.status_code)) 523 else: 524 raise Exception("Max time exceeded waiting for transactions with current response map = {0}".format(respMap)) 525 print("Result of request to all peers = {0}".format(respMap)) 526 print("") 527 528 @then(u'I wait up to "{seconds}" seconds for transactions to be committed to peers') 529 def step_impl(context, seconds): 530 assert 'chainheight' in context, "chainheight not found in context" 531 assert 'txcount' in context, "txcount not found in context" 532 assert 'compose_containers' in context, "compose_containers not found in context" 533 assert 'table' in context, "table (of peers) not found in context" 534 535 aliases = context.table.headings 536 containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData) 537 538 # Build map of "containerName" : resp.statusCode 539 respMap = {container.containerName:0 for container in containerDataList} 540 541 # Set the max time before stopping attempts 542 maxTime = datetime.now() + timedelta(seconds = int(seconds)) 543 for container in containerDataList: 544 ipAddress = container.ipAddress 545 request_url = buildUrl(context, ipAddress, "/chain") 546 547 # Loop unless failure or time exceeded 548 while (datetime.now() < maxTime): 549 print("{0} GETing path = {1}".format(currentTime(), request_url)) 550 resp = requests.get(request_url, headers={'Accept': 'application/json'}, verify=False) 551 if resp.status_code == 404: 552 # Pause then try again 553 respMap[container.containerName] = 404 554 time.sleep(1) 555 continue 556 elif resp.status_code == 200: 557 height = getAttributeFromJSON("height", resp.json(), "Height not found in response.") 558 if height >= int(context.chainheight) + int(context.txcount): 559 # Success, continue 560 respMap[container.containerName] = 200 561 break 562 else: 563 continue 564 else: 565 raise Exception("Error requesting {0}, returned result code = {1}".format(request_url, resp.status_code)) 566 else: 567 raise Exception("Max time exceeded waiting for transactions with current response map = {0}".format(respMap)) 568 print("Result of request to all peers = {0}".format(respMap)) 569 print("") 570 571 572 @then(u'I should get a rejection message in the listener after stopping it') 573 def step_impl(context): 574 assert "eventlistener" in context, "no eventlistener is started" 575 context.eventlistener.terminate() 576 output = context.eventlistener.stdout.read() 577 rejection = "Received rejected transaction" 578 assert rejection in output, "no rejection message was found" 579 assert output.count(rejection) == 1, "only one rejection message should be found" 580 581 582 @when(u'I query chaincode "{chaincodeName}" function name "{functionName}" on all peers') 583 def step_impl(context, chaincodeName, functionName): 584 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 585 assert 'compose_containers' in context, "compose_containers not found in context" 586 # Update the chaincodeSpec ctorMsg for invoke 587 args = [] 588 if 'table' in context: 589 # There is ctor arguments 590 args = context.table[0].cells 591 args = prepend(functionName, args) 592 context.chaincodeSpec['ctorMsg']['args'] = args #context.table[0].cells if ('table' in context) else [] 593 # Invoke the POST 594 chaincodeOpPayload = createChaincodeOpPayload("query", context.chaincodeSpec) 595 596 responses = [] 597 for container in context.compose_containers: 598 request_url = buildUrl(context, container.ipAddress, "/chaincode") 599 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 600 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeOpPayload), verify=False) 601 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 602 responses.append(resp) 603 context.responses = responses 604 605 @when(u'I unconditionally query chaincode "{chaincodeName}" function name "{functionName}" with value "{value}" on peers') 606 def step_impl(context, chaincodeName, functionName, value): 607 query_common(context, chaincodeName, functionName, value, False) 608 609 @when(u'I query chaincode "{chaincodeName}" function name "{functionName}" with value "{value}" on peers') 610 def step_impl(context, chaincodeName, functionName, value): 611 query_common(context, chaincodeName, functionName, value, True) 612 613 def query_common(context, chaincodeName, functionName, value, failOnError): 614 assert 'chaincodeSpec' in context, "chaincodeSpec not found in context" 615 assert 'compose_containers' in context, "compose_containers not found in context" 616 assert 'table' in context, "table (of peers) not found in context" 617 assert 'peerToSecretMessage' in context, "peerToSecretMessage map not found in context" 618 619 aliases = context.table.headings 620 containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData) 621 622 # Update the chaincodeSpec ctorMsg for invoke 623 context.chaincodeSpec['ctorMsg']['args'] = [functionName, value] 624 # Invoke the POST 625 # Make deep copy of chaincodeSpec as we will be changing the SecurityContext per call. 626 chaincodeOpPayload = createChaincodeOpPayload("query", copy.deepcopy(context.chaincodeSpec)) 627 628 responses = [] 629 for container in containerDataList: 630 # Change the SecurityContext per call 631 chaincodeOpPayload['params']["secureContext"] = context.peerToSecretMessage[container.composeService]['enrollId'] 632 print("Container {0} enrollID = {1}".format(container.containerName, container.getEnv("CORE_SECURITY_ENROLLID"))) 633 request_url = buildUrl(context, container.ipAddress, "/chaincode") 634 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 635 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(chaincodeOpPayload), timeout=30, verify=False) 636 if failOnError: 637 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 638 print("RESULT from {0} of chaincode from peer {1}".format(functionName, container.containerName)) 639 print(json.dumps(resp.json(), indent = 4)) 640 responses.append(resp) 641 context.responses = responses 642 643 @then(u'I should get a JSON response from all peers with "{attribute}" = "{expectedValue}"') 644 def step_impl(context, attribute, expectedValue): 645 assert 'responses' in context, "responses not found in context" 646 for resp in context.responses: 647 foundValue = getAttributeFromJSON(attribute, resp.json(), "Attribute not found in response (%s)" %(attribute)) 648 assert (formatStringToCompare(foundValue) == expectedValue), "For attribute %s, expected (%s), instead found (%s)" % (attribute, expectedValue, foundValue) 649 650 @then(u'I should get a JSON response from peers with "{attribute}" = "{expectedValue}"') 651 def step_impl(context, attribute, expectedValue): 652 assert 'responses' in context, "responses not found in context" 653 assert 'compose_containers' in context, "compose_containers not found in context" 654 assert 'table' in context, "table (of peers) not found in context" 655 656 for resp in context.responses: 657 foundValue = getAttributeFromJSON(attribute, resp.json(), "Attribute not found in response (%s)" %(attribute)) 658 assert (formatStringToCompare(foundValue) == expectedValue), "For attribute %s, expected (%s), instead found (%s)" % (attribute, expectedValue, foundValue) 659 660 @given(u'I register with CA supplying username "{userName}" and secret "{secret}" on peers') 661 def step_impl(context, userName, secret): 662 assert 'compose_containers' in context, "compose_containers not found in context" 663 assert 'table' in context, "table (of peers) not found in context" 664 665 # Get list of IPs to login to 666 aliases = context.table.headings 667 containerDataList = bdd_test_util.getContainerDataValuesFromContext(context, aliases, lambda containerData: containerData) 668 669 secretMsg = { 670 "enrollId": userName, 671 "enrollSecret" : secret 672 } 673 674 # Login to each container specified 675 for containerData in containerDataList: 676 request_url = buildUrl(context, containerData.ipAddress, "/registrar") 677 print("{0} POSTing path = {1}".format(currentTime(), request_url)) 678 679 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(secretMsg), verify=False) 680 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 681 context.response = resp 682 print("message = {0}".format(resp.json())) 683 684 # Create new User entry 685 bdd_test_util.registerUser(context, secretMsg, containerData.composeService) 686 687 # Store the username in the context 688 context.userName = userName 689 # if we already have the chaincodeSpec, change secureContext 690 if 'chaincodeSpec' in context: 691 context.chaincodeSpec["secureContext"] = context.userName 692 693 694 @given(u'I use the following credentials for querying peers') 695 def step_impl(context): 696 assert 'compose_containers' in context, "compose_containers not found in context" 697 assert 'table' in context, "table (of peers, username, secret) not found in context" 698 699 peerToSecretMessage = {} 700 701 # Login to each container specified using username and secret 702 for row in context.table.rows: 703 peer, userName, secret = row['peer'], row['username'], row['secret'] 704 secretMsg = { 705 "enrollId": userName, 706 "enrollSecret" : secret 707 } 708 709 ipAddress = bdd_test_util.ipFromContainerNamePart(peer, context.compose_containers) 710 request_url = buildUrl(context, ipAddress, "/registrar") 711 print("POSTing to service = {0}, path = {1}".format(peer, request_url)) 712 713 resp = requests.post(request_url, headers={'Content-type': 'application/json'}, data=json.dumps(secretMsg), verify=False) 714 assert resp.status_code == 200, "Failed to POST to %s: %s" %(request_url, resp.text) 715 context.response = resp 716 print("message = {0}".format(resp.json())) 717 peerToSecretMessage[peer] = secretMsg 718 context.peerToSecretMessage = peerToSecretMessage 719 720 721 @given(u'I stop peers') 722 def step_impl(context): 723 compose_op(context, "stop") 724 725 726 @given(u'I start a listener') 727 def step_impl(context): 728 gopath = os.environ.get('GOPATH') 729 assert gopath is not None, "Please set GOPATH properly!" 730 listener = os.path.join(gopath, "src/github.com/hyperledger/fabric/build/bin/block-listener") 731 assert os.path.isfile(listener), "Please build the block-listener binary!" 732 bdd_test_util.start_background_process(context, "eventlistener", [listener, "-listen-to-rejections"] ) 733 734 735 @given(u'I start peers') 736 def step_impl(context): 737 compose_op(context, "start") 738 739 @given(u'I pause peers') 740 def step_impl(context): 741 compose_op(context, "pause") 742 743 @given(u'I unpause peers') 744 def step_impl(context): 745 compose_op(context, "unpause") 746 747 def compose_op(context, op): 748 assert 'table' in context, "table (of peers) not found in context" 749 assert 'composition' in context, "composition not found in context" 750 services = context.table.headings 751 context.composition.issueCommand([op] + services) 752 context.compose_containers = context.composition.containerDataList 753 754 def to_bytes(strlist): 755 return [base64.standard_b64encode(s.encode('ascii')) for s in strlist] 756 757 def prepend(elem, l): 758 if l is None or l == "": 759 tail = [] 760 else: 761 tail = l 762 if elem is None: 763 return tail 764 return [elem] + tail 765 766 @given(u'I do nothing') 767 def step_impl(context): 768 pass