Merge "Added neutron cli test case"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 4dcf460..e60b731 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -397,6 +397,9 @@
# If false, skip all nova v3 tests. (boolean value)
#api_v3=false
+# If false skip all v2 api tests with xml (boolean value)
+#xml_api_v2=true
+
# If false, skip disk config tests (boolean value)
#disk_config=true
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a3295eb..343a39a 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -37,6 +37,9 @@
def setUpClass(cls):
cls.set_network_resources()
super(BaseComputeTest, cls).setUpClass()
+ if getattr(cls, '_interface', None) == 'xml' and cls._api_version == 2:
+ if not CONF.compute_feature_enabled.xml_api_v2:
+ raise cls.skipException('XML API is not enabled')
# TODO(andreaf) WE should care also for the alt_manager here
# but only once client lazy load in the manager is done
diff --git a/tempest/api/compute/v3/servers/test_server_rescue_negative.py b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
index 83fe128..6d192a3 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -56,7 +56,8 @@
@classmethod
def tearDownClass(cls):
- cls.delete_volume(cls.volume['id'])
+ if hasattr(cls, 'volume'):
+ cls.delete_volume(cls.volume['id'])
super(ServerRescueNegativeV3Test, cls).tearDownClass()
def _detach(self, server_id, volume_id):
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 @@
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 @@
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 @@
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."""
diff --git a/tempest/cli/simple_read_only/test_heat.py b/tempest/cli/simple_read_only/test_heat.py
index 7a952fc..bd79fa6 100644
--- a/tempest/cli/simple_read_only/test_heat.py
+++ b/tempest/cli/simple_read_only/test_heat.py
@@ -85,6 +85,7 @@
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')
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/test_nova.py
index 7085cc9..9bac7a6 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -144,6 +144,7 @@
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')
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 05d758f..f711f2f 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -373,31 +373,6 @@
LOG.warn('network with name: %s not found for delete' %
network_name)
- def _cleanup_ports(self, network_id):
- # TODO(mlavalle) This method will be removed once patch
- # https://review.openstack.org/#/c/46563/ merges in Neutron
- if not self.ports:
- if self.tempest_client:
- resp, resp_body = self.network_admin_client.list_ports()
- else:
- resp_body = self.network_admin_client.list_ports()
- self.ports = resp_body['ports']
- ports_to_delete = [
- port
- for port in self.ports
- if (port['network_id'] == network_id and
- port['device_owner'] != 'network:router_interface' and
- port['device_owner'] != 'network:dhcp')
- ]
- for port in ports_to_delete:
- try:
- LOG.info('Cleaning up port id %s, name %s' %
- (port['id'], port['name']))
- self.network_admin_client.delete_port(port['id'])
- except exceptions.NotFound:
- LOG.warn('Port id: %s, name %s not found for clean-up' %
- (port['id'], port['name']))
-
def _clear_isolated_net_resources(self):
net_client = self.network_admin_client
for cred in self.isolated_net_resources:
@@ -419,11 +394,6 @@
router['name'])
self._clear_isolated_router(router['id'], router['name'])
if (not self.network_resources or
- self.network_resources.get('network')):
- # TODO(mlavalle) This method call will be removed once patch
- # https://review.openstack.org/#/c/46563/ merges in Neutron
- self._cleanup_ports(network['id'])
- if (not self.network_resources or
self.network_resources.get('subnet')):
self._clear_isolated_subnet(subnet['id'], subnet['name'])
if (not self.network_resources or
diff --git a/tempest/config.py b/tempest/config.py
index 3b61700..39c2be1 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -273,6 +273,9 @@
cfg.BoolOpt('api_v3',
default=False,
help="If false, skip all nova v3 tests."),
+ cfg.BoolOpt('xml_api_v2',
+ default=True,
+ help="If false skip all v2 api tests with xml"),
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
new file mode 100644
index 0000000..1fd5ccb
--- /dev/null
+++ b/tempest/tests/cli/test_cli.py
@@ -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')