Skip to content

Commit

Permalink
Add a container alias map to the bdd context
Browse files Browse the repository at this point in the history
To simplify the usage of mapping between the docker-compose service
to container name mapping add a dictionary mapping the service (or
alias) to the container data object. Also add a map of full container
name to container data object for convenience.

Standardize the naming of a compose service to containerAlias to
reduce confusion between the actual containerName and the service
defined in docker-compose.
e.g. I deploy chaincode "{chaincodePath}" with ctor "{ctor}" to
     "{containerAlias}"
containerAlias could refer to "vp0" when in reality the container is
called "bddtests_vp0_1"

Rename the ContainerData class to Container and its field:
containerName to name to reduce verbosity in the code base.

Remove functions that were no longer used afer changing the code to
use the map of alias->container.

Signed-off-by: Julian Carrivick <cjulian@au1.ibm.com>
Change-Id: I870719f3ff4db9d07f23d61f1d1a411b6e7ad804
  • Loading branch information
juliancarrivick-ibm committed Sep 8, 2016
1 parent af6d3e8 commit 9059fa1
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 175 deletions.
8 changes: 4 additions & 4 deletions bddtests/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ def after_scenario(context, scenario):
file_suffix = "_" + scenario.name.replace(" ", "_") + ".log"
# get logs from the peer containers
for containerData in context.compose_containers:
with open(containerData.containerName + file_suffix, "w+") as logfile:
sys_rc = subprocess.call(["docker", "logs", containerData.containerName], stdout=logfile, stderr=logfile)
with open(containerData.name + file_suffix, "w+") as logfile:
sys_rc = subprocess.call(["docker", "logs", containerData.name], stdout=logfile, stderr=logfile)
if sys_rc !=0 :
bdd_log("Cannot get logs for {0}. Docker rc = {1}".format(containerData.containerName,sys_rc))
bdd_log("Cannot get logs for {0}. Docker rc = {1}".format(containerData.name,sys_rc))
# get logs from the chaincode containers
cc_output, cc_error, cc_returncode = \
cli_call(["docker", "ps", "-f", "name=dev-", "--format", "{{.Names}}"], expect_success=True)
Expand All @@ -52,7 +52,7 @@ def after_scenario(context, scenario):

if coverageEnabled(context):
#Save the coverage files for this scenario before removing containers
containerNames = [containerData.containerName for containerData in context.compose_containers]
containerNames = [containerData.name for containerData in context.compose_containers]
saveCoverageFiles("coverage", scenario.name.replace(" ", "_"), containerNames, "cov")

context.compose_output, context.compose_error, context.compose_returncode = \
Expand Down
1 change: 0 additions & 1 deletion bddtests/peer_basic.feature
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ Feature: Network of Peers
| docker-compose-4-consensus-batch.yml | 60 |


# @doNotDecompose
@issue_724
Scenario Outline: chaincode example02 with 4 peers and 1 membersrvc, issue #724

Expand Down
57 changes: 40 additions & 17 deletions bddtests/steps/bdd_compose_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
from bdd_json_util import getAttributeFromJSON
from bdd_test_util import cli_call, bdd_log

class ContainerData:
def __init__(self, containerName, ipAddress, envFromInspect, composeService):
self.containerName = containerName
class Container:
def __init__(self, name, ipAddress, envFromInspect, composeService):
self.name = name
self.ipAddress = ipAddress
self.envFromInspect = envFromInspect
self.composeService = composeService
Expand All @@ -34,11 +34,11 @@ def getEnv(self, key):
envValue = val[len(key):]
break
if envValue == None:
raise Exception("ENV key not found ({0}) for container ({1})".format(key, self.containerName))
raise Exception("ENV key not found ({0}) for container ({1})".format(key, self.name))
return envValue

def __str__(self):
return "{} - {}".format(self.containerName, self.ipAddress)
return "{} - {}".format(self.name, self.ipAddress)

def __repr__(self):
return self.__str__()
Expand Down Expand Up @@ -87,7 +87,7 @@ def parseComposeOutput(context):
dockerComposeService = [composeService[27:] for composeService in labels if composeService.startswith("com.docker.compose.service:")][0]
bdd_log("dockerComposeService = {0}".format(dockerComposeService))
bdd_log("container {0} has env = {1}".format(containerName, env))
containerDataList.append(ContainerData(containerName, ipAddress, env, dockerComposeService))
containerDataList.append(Container(containerName, ipAddress, env, dockerComposeService))
# Now merge the new containerData info with existing
newContainerDataList = []
if "compose_containers" in context:
Expand Down Expand Up @@ -119,13 +119,13 @@ def allContainersAreReadyWithinTimeout(context, timeout):
def containerIsInitializedByTimestamp(container, timeoutTimestamp):
while containerIsNotInitialized(container):
if timestampExceeded(timeoutTimestamp):
bdd_log("Timed out waiting for {} to initialize".format(container.containerName))
bdd_log("Timed out waiting for {} to initialize".format(container.name))
return False

bdd_log("{} not initialized, waiting...".format(container.containerName))
bdd_log("{} not initialized, waiting...".format(container.name))
time.sleep(1)

bdd_log("{} now available".format(container.containerName))
bdd_log("{} now available".format(container.name))
return True

def timestampExceeded(timeoutTimestamp):
Expand All @@ -141,13 +141,13 @@ def containerIsInitialized(container):
return isReady

def tcpPortsAreReady(container):
netstatOutput = getContainerNetstatOutput(container.containerName)
netstatOutput = getContainerNetstatOutput(container.name)

for line in netstatOutput.splitlines():
if re.search("ESTABLISHED|LISTEN", line):
return True

bdd_log("No TCP connections are ready in container {}".format(container.containerName))
bdd_log("No TCP connections are ready in container {}".format(container.name))
return False

def getContainerNetstatOutput(containerName):
Expand All @@ -157,7 +157,7 @@ def getContainerNetstatOutput(containerName):
return stdout

def restPortRespondsIfContainerIsPeer(container):
containerName = container.containerName
containerName = container.name
command = ["docker", "exec", containerName, "curl", "localhost:{}".format(CORE_REST_PORT)]

if containerIsPeer(container):
Expand Down Expand Up @@ -195,18 +195,18 @@ def containerIsPeer(container):
# is to determine if the container is listening on the REST port. However, this method
# may run before the listening port is ready. Hence, as along as the current
# convention of vp[0-9] is adhered to this function will be good enough.
return re.search("vp[0-9]+", container.containerName, re.IGNORECASE)
return re.search("vp[0-9]+", container.name, re.IGNORECASE)

def peerIsReadyByTimestamp(context, peerContainer, allPeerContainers, timeoutTimestamp):
while peerIsNotReady(context, peerContainer, allPeerContainers):
if timestampExceeded(timeoutTimestamp):
bdd_log("Timed out waiting for peer {}".format(peerContainer.containerName))
bdd_log("Timed out waiting for peer {}".format(peerContainer.name))
return False

bdd_log("Peer {} not ready, waiting...".format(peerContainer.containerName))
bdd_log("Peer {} not ready, waiting...".format(peerContainer.name))
time.sleep(1)

bdd_log("Peer {} now available".format(peerContainer.containerName))
bdd_log("Peer {} now available".format(peerContainer.name))
return True

def peerIsNotReady(context, thisPeer, allPeers):
Expand Down Expand Up @@ -235,4 +235,27 @@ def getConnectedPeersFromPeer(context, thisPeer):
if response.status_code != 200:
return None

return getAttributeFromJSON("peers", response.json(), "There should be a peer json attribute")
return getAttributeFromJSON("peers", response.json(), "There should be a peer json attribute")

def mapAliasesToContainers(context):
aliasToContainerMap = {}

for container in context.compose_containers:
alias = extractAliasFromContainerName(container.name)
aliasToContainerMap[alias] = container

return aliasToContainerMap

def extractAliasFromContainerName(containerName):
""" Take a compose created container name and extract the alias to which it
will be refered. For example bddtests_vp1_0 will return vp0 """
return containerName.split("_")[1]

def mapContainerNamesToContainers(context):
nameToContainerMap = {}

for container in context.compose_containers:
name = container.name
nameToContainerMap[name] = container

return nameToContainerMap
2 changes: 1 addition & 1 deletion bddtests/steps/bdd_grpc_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def getGRPCChannelAndUser(context, enrollId):
userRegistration = bdd_test_util.getUserRegistration(context, enrollId)

# Get the IP address of the server that the user registered on
ipAddress = bdd_test_util.ipFromContainerNamePart(userRegistration.composeService, context.compose_containers)
ipAddress = context.containerAliasMap[userRegistration.composeService].ipAddress

channel = getGRPCChannel(ipAddress)

Expand Down
40 changes: 0 additions & 40 deletions bddtests/steps/bdd_test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,46 +75,6 @@ def getUserRegistration(context, enrollId):
raise Exception("User has not been registered: {0}".format(enrollId))
return userRegistration


def ipFromContainerNamePart(namePart, containerDataList):
"""Returns the IPAddress based upon a name part of the full container name"""
containerData = containerDataFromNamePart(namePart, containerDataList)

if containerData == None:
raise Exception("Could not find container with namePart = {0}".format(namePart))

return containerData.ipAddress

def fullNameFromContainerNamePart(namePart, containerDataList):
containerData = containerDataFromNamePart(namePart, containerDataList)

if containerData == None:
raise Exception("Could not find container with namePart = {0}".format(namePart))

return containerData.containerName

def containerDataFromNamePart(namePart, containerDataList):
containerNamePrefix = os.path.basename(os.getcwd()) + "_"
fullContainerName = containerNamePrefix + namePart

for containerData in containerDataList:
if containerData.containerName.startswith(fullContainerName):
return containerData

return None

def getContainerDataValuesFromContext(context, aliases, callback):
"""Returns the IPAddress based upon a name part of the full container name"""
assert 'compose_containers' in context, "compose_containers not found in context"
values = []
containerNamePrefix = os.path.basename(os.getcwd()) + "_"
for namePart in aliases:
for containerData in context.compose_containers:
if containerData.containerName.startswith(containerNamePrefix + namePart):
values.append(callback(containerData))
break
return values

def start_background_process(context, program_name, arg_list):
p = subprocess.Popen(arg_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
setattr(context, program_name, p)
Expand Down

0 comments on commit 9059fa1

Please sign in to comment.