Files
deb-python-dcos/cli/tests/integrations/common.py

227 lines
5.5 KiB
Python

import collections
import json
import os
import subprocess
import requests
from six.moves import urllib
def exec_command(cmd, env=None, stdin=None):
"""Execute CLI command
:param cmd: Program and arguments
:type cmd: [str]
:param env: Environment variables
:type env: dict
:param stdin: File to use for stdin
:type stdin: file
:returns: A tuple with the returncode, stdout and stderr
:rtype: (int, bytes, bytes)
"""
print('CMD: {!r}'.format(cmd))
process = subprocess.Popen(
cmd,
stdin=stdin,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
stdout, stderr = process.communicate()
# We should always print the stdout and stderr
print('STDOUT: {}'.format(stdout.decode('utf-8')))
print('STDERR: {}'.format(stderr.decode('utf-8')))
return (process.returncode, stdout, stderr)
def assert_command(
cmd,
returncode=0,
stdout=b'',
stderr=b'',
env=None,
stdin=None):
"""Execute CLI command and assert expected behavior.
:param cmd: Program and arguments
:type cmd: list of str
:param returncode: Expected return code
:type returncode: int
:param stdout: Expected stdout
:type stdout: str
:param stderr: Expected stderr
:type stderr: str
:param env: Environment variables
:type env: dict of str to str
:param stdin: File to use for stdin
:type stdin: file
:rtype: None
"""
returncode_, stdout_, stderr_ = exec_command(cmd, env, stdin)
assert returncode_ == returncode
assert stdout_ == stdout
assert stderr_ == stderr
def mock_called_some_args(mock, *args, **kwargs):
"""Convience method for some mock assertions. Returns True if the
arguments to one of the calls of `mock` contains `args` and
`kwargs`.
:param mock: the mock to check
:type mock: mock.Mock
:returns: True if the arguments to one of the calls for `mock`
contains `args` and `kwargs`.
:rtype: bool
"""
for call in mock.call_args_list:
call_args, call_kwargs = call
if any(arg not in call_args for arg in args):
continue
if any(k not in call_kwargs or call_kwargs[k] != v
for k, v in kwargs.items()):
continue
return True
return False
def watch_deployment(deployment_id, count):
""" Wait for a deployment to complete.
:param deployment_id: deployment id
:type deployment_id: str
:param count: max number of seconds to wait
:type count: int
:rtype: None
"""
returncode, stdout, stderr = exec_command(
['dcos', 'marathon', 'deployment', 'watch',
'--max-count={}'.format(count), deployment_id])
assert returncode == 0
assert stderr == b''
def watch_all_deployments(count=300):
""" Wait for all deployments to complete.
:param count: max number of seconds to wait
:type count: int
:rtype: None
"""
deps = list_deployments()
for dep in deps:
watch_deployment(dep['id'], count)
def list_deployments(expected_count=None, app_id=None):
"""Get all active deployments.
:param expected_count: assert that number of active deployments
equals `expected_count`
:type expected_count: int
:param app_id: only get deployments for this app
:type app_id: str
:returns: active deployments
:rtype: [dict]
"""
cmd = ['dcos', 'marathon', 'deployment', 'list', '--json']
if app_id is not None:
cmd.append(app_id)
returncode, stdout, stderr = exec_command(cmd)
result = json.loads(stdout.decode('utf-8'))
assert returncode == 0
if expected_count is not None:
assert len(result) == expected_count
assert stderr == b''
return result
def get_services(expected_count=None, args=[]):
"""Get services
:param expected_count: assert exactly this number of services are
running
:type expected_count: int | None
:param args: cli arguments
:type args: [str]
:returns: services
:rtype: [dict]
"""
returncode, stdout, stderr = exec_command(
['dcos', 'service', '--json'] + args)
assert returncode == 0
assert stderr == b''
services = json.loads(stdout.decode('utf-8'))
assert isinstance(services, collections.Sequence)
if expected_count is not None:
assert len(services) == expected_count
return services
def service_shutdown(service_id):
"""Shuts down a service using the command line program
:param service_id: the id of the service
:type: service_id: str
:rtype: None
"""
assert_command(['dcos', 'service', 'shutdown', service_id])
def delete_zk_nodes():
"""Delete Zookeeper nodes that were created during the tests
:rtype: None
"""
base_url = os.environ['EXHIBITOR_URL']
base_path = 'exhibitor/v1/explorer/znode/{}'
for znode in ['universe', 'cassandra-mesos', 'chronos']:
znode_url = urllib.parse.urljoin(
base_url,
base_path.format(znode))
requests.delete(znode_url)
def assert_lines(cmd, num_lines):
""" Assert stdout contains the expected number of lines
:param cmd: program and arguments
:type cmd: [str]
:param num_lines: expected number of lines for stdout
:type num_lines: int
:rtype: None
"""
returncode, stdout, stderr = exec_command(cmd)
assert returncode == 0
assert stderr == b''
assert len(stdout.decode('utf-8').split('\n')) - 1 == num_lines