diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py index 02f8c05..c33589a 100644 --- a/tempest/cli/__init__.py +++ b/tempest/cli/__init__.py @@ -13,14 +13,18 @@ # License for the specific language governing permissions and limitations # under the License. +import functools import os import shlex import subprocess +import testtools + import tempest.cli.output_parser from tempest import config from tempest import exceptions from tempest.openstack.common import log as logging +from tempest.openstack.common import versionutils import tempest.test @@ -29,6 +33,65 @@ LOG = logging.getLogger(__name__) CONF = config.CONF +def execute(cmd, action, flags='', params='', fail_ok=False, + merge_stderr=False): + """Executes specified command for the given action.""" + cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd), + flags, action, params]) + LOG.info("running: '%s'" % cmd) + cmd = shlex.split(cmd.encode('utf-8')) + result = '' + result_err = '' + stdout = subprocess.PIPE + stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE + proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr) + result, result_err = proc.communicate() + if not fail_ok and proc.returncode != 0: + raise exceptions.CommandFailed(proc.returncode, + cmd, + result, + result_err) + return result + + +def check_client_version(client, version): + """Checks if the client's version is compatible with the given version + + @param client: The client to check. + @param version: The version to compare against. + @return: True if the client version is compatible with the given version + parameter, False otherwise. + """ + current_version = execute(client, '', params='--version', + merge_stderr=True) + + if not current_version.strip(): + raise exceptions.TempestException('"%s --version" output was empty' % + client) + + return versionutils.is_compatible(version, current_version, + same_major=False) + + +def min_client_version(*args, **kwargs): + """A decorator to skip tests if the client used isn't of the right version. + + @param client: The client command to run. For python-novaclient, this is + 'nova', for python-cinderclient this is 'cinder', etc. + @param version: The minimum version required to run the CLI test. + """ + def decorator(func): + @functools.wraps(func) + def wrapper(*func_args, **func_kwargs): + if not check_client_version(kwargs['client'], kwargs['version']): + msg = "requires %s client version >= %s" % (kwargs['client'], + kwargs['version']) + raise testtools.TestCase.skipException(msg) + return func(*func_args, **func_kwargs) + return wrapper + return decorator + + class ClientTestBase(tempest.test.BaseTestCase): @classmethod def setUpClass(cls): @@ -50,7 +113,7 @@ class ClientTestBase(tempest.test.BaseTestCase): def nova_manage(self, action, flags='', params='', fail_ok=False, merge_stderr=False): """Executes nova-manage command for the given action.""" - return self.cmd( + return execute( 'nova-manage', action, flags, params, fail_ok, merge_stderr) def keystone(self, action, flags='', params='', admin=True, fail_ok=False): @@ -114,28 +177,7 @@ class ClientTestBase(tempest.test.BaseTestCase): CONF.identity.admin_password, CONF.identity.uri)) flags = creds + ' ' + flags - return self.cmd(cmd, action, flags, params, fail_ok, merge_stderr) - - def cmd(self, cmd, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes specified command for the given action.""" - cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd), - flags, action, params]) - LOG.info("running: '%s'" % cmd) - cmd = shlex.split(cmd.encode('utf-8')) - result = '' - result_err = '' - stdout = subprocess.PIPE - stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE - proc = subprocess.Popen( - cmd, stdout=stdout, stderr=stderr) - result, result_err = proc.communicate() - if not fail_ok and proc.returncode != 0: - raise exceptions.CommandFailed(proc.returncode, - cmd, - result, - result_err) - return result + return execute(cmd, action, flags, params, fail_ok, merge_stderr) def assertTableStruct(self, items, field_names): """Verify that all items has keys listed in field_names."""