Merge "Add min_client_version decorator for CLI tests"

This commit is contained in:
Jenkins 2014-08-12 20:15:35 +00:00 committed by Gerrit Code Review
commit fceab11864
4 changed files with 126 additions and 23 deletions

View File

@ -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."""

View File

@ -85,6 +85,7 @@ class SimpleReadOnlyHeatClientTest(tempest.cli.ClientTestBase):
def test_heat_help(self):
self.heat('help')
@tempest.cli.min_client_version(client='heat', version='0.2.7')
def test_heat_bash_completion(self):
self.heat('bash-completion')

View File

@ -144,6 +144,7 @@ class SimpleReadOnlyNovaClientTest(cli.ClientTestBase):
def test_admin_secgroup_list_rules(self):
self.nova('secgroup-list-rules')
@tempest.cli.min_client_version(client='nova', version='2.18')
def test_admin_server_group_list(self):
self.nova('server-group-list')

View File

@ -0,0 +1,59 @@
# Copyright 2014 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
import testtools
from tempest import cli
from tempest import exceptions
from tempest.tests import base
class TestMinClientVersion(base.TestCase):
"""Tests for the min_client_version decorator.
"""
def _test_min_version(self, required, installed, expect_skip):
@cli.min_client_version(client='nova', version=required)
def fake(self, expect_skip):
if expect_skip:
# If we got here, the decorator didn't raise a skipException as
# expected so we need to fail.
self.fail('Should not have gotten past the decorator.')
with mock.patch.object(cli, 'execute',
return_value=installed) as mock_cmd:
if expect_skip:
self.assertRaises(testtools.TestCase.skipException, fake,
self, expect_skip)
else:
fake(self, expect_skip)
mock_cmd.assert_called_once_with('nova', '', params='--version',
merge_stderr=True)
def test_min_client_version(self):
# required, installed, expect_skip
cases = (('2.17.0', '2.17.0', False),
('2.17.0', '2.18.0', False),
('2.18.0', '2.17.0', True))
for case in cases:
self._test_min_version(*case)
@mock.patch.object(cli, 'execute', return_value=' ')
def test_check_client_version_empty_output(self, mock_execute):
# Tests that an exception is raised if the command output is empty.
self.assertRaises(exceptions.TempestException,
cli.check_client_version, 'nova', '2.18.0')