Merge "Adds initial ceilometerclient testing code"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index cf838c0..e5444ae 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -51,17 +51,6 @@
project = u'Tempest'
copyright = u'2013, OpenStack QA Team'
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-import pbr.version
-version_info = pbr.version.VersionInfo('tempest')
-version = version_info.version_string()
-# The full version, including alpha/beta/rc tags.
-release = version_info.release_string()
-
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index d53dbfc..cd4faea 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -2,7 +2,7 @@
#log_config = /opt/stack/tempest/etc/logging.conf.sample
# disable logging to the stderr
-use_stderr = False
+use_stderr = false
# log file
log_file = tempest.log
@@ -23,7 +23,7 @@
catalog_type = identity
# Ignore SSL certificate validation failures? Use when in testing
# environments that have self-signed SSL certs.
-disable_ssl_certificate_validation = False
+disable_ssl_certificate_validation = false
# URL for where to find the OpenStack Identity API endpoint (Keystone)
uri = http://127.0.0.1:5000/v2.0/
# URL for where to find the OpenStack V3 Identity API endpoint (Keystone)
@@ -131,7 +131,7 @@
ssh_channel_timeout = 60
# Dose the SSH uses Floating IP?
-use_floatingip_for_ssh = True
+use_floatingip_for_ssh = true
# The type of endpoint for a Compute API service. Unless you have a
# custom Keystone service catalog implementation, you probably want to leave
@@ -147,12 +147,12 @@
create_image_enabled = true
# For resize to work with libvirt/kvm, one of the following must be true:
-# Single node: allow_resize_to_same_host=True must be set in nova.conf
+# Single node: allow_resize_to_same_host=true must be set in nova.conf
# Cluster: the 'nova' user must have scp access between cluster nodes
resize_available = true
# Does the compute API support changing the admin password?
-change_password_available=true
+change_password_available = true
# Run live migration tests (requires 2 hosts)
live_migration_available = false
@@ -291,10 +291,10 @@
# Number of seconds to wait while looping to check the status of a
# container to container synchronization
container_sync_interval = 5
-# Set to True if the Account Quota middleware is enabled
-accounts_quotas_available = True
-# Set to True if the Container Quota middleware is enabled
-container_quotas_available = True
+# Set to true if the Account Quota middleware is enabled
+accounts_quotas_available = true
+# Set to true if the Container Quota middleware is enabled
+container_quotas_available = true
# Set operator role for tests that require creating a container
operator_role = Member
@@ -403,7 +403,7 @@
[cli]
# Enable cli tests
-enabled = True
+enabled = true
# directory where python client binaries are located
cli_dir = /usr/local/bin
# Number of seconds to wait on a CLI timeout
@@ -411,21 +411,21 @@
[service_available]
# Whether or not cinder is expected to be available
-cinder = True
+cinder = true
# Whether or not neutron is expected to be available
neutron = false
# Whether or not glance is expected to be available
-glance = True
+glance = true
# Whether or not swift is expected to be available
-swift = True
+swift = true
# Whether or not nova is expected to be available
-nova = True
+nova = true
# Whether or not Heat is expected to be available
heat = false
# Whether or not Ceilometer is expected to be available
ceilometer = True
# Whether or not horizon is expected to be available
-horizon = True
+horizon = true
[stress]
# Maximum number of instances to create during test
@@ -433,8 +433,8 @@
# Time (in seconds) between log file error checks
log_check_interval = 60
# The default number of threads created while stress test
-default_thread_number_per_action=4
+default_thread_number_per_action = 4
[debug]
# Enable diagnostic commands
-enable = True
+enable = true
diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml
index 6762f9f..e6d28f5 100644
--- a/etc/whitelist.yaml
+++ b/etc/whitelist.yaml
@@ -21,6 +21,16 @@
message: "Instance failed to spawn"
- module: "nova.compute.manager"
message: "Error: Unexpected error while running command"
+ - module: "nova.virt.libvirt.driver"
+ message: "Error from libvirt during destroy"
+ - module: "nova.virt.libvirt.vif"
+ message: "Failed while unplugging vif"
+ - module: "nova.openstack.common.loopingcal"
+ message: "in fixed duration looping call"
+ - module: "nova.virt.libvirt.driver"
+ message: "Getting disk size of instance"
+ - module: "nova.virt.libvirt.driver"
+ message: "No such file or directory: '/opt/stack/data/nova/instances"
g-api:
- module: "glance.store.sheepdog"
@@ -34,6 +44,12 @@
message: "Requested operation is not valid: domain is not running"
- module: "ceilometer.compute.pollsters.disk"
message: "Domain not found: no domain with matching uuid"
+ - module: "ceilometer.compute.pollsters.net"
+ message: "No module named libvirt"
+
+ceilometer-alarm-evaluator:
+ - module: "ceilometer.alarm.service"
+ message: "alarm evaluation cycle failed"
h-api:
- module: "root"
@@ -63,6 +79,8 @@
message: "ServersTest"
- module: "nova.compute.api"
message: "\\{u'kernel_id'.*u'ramdisk_id':"
+ - module: "nova.api.openstack.wsgi"
+ message: "takes exactly 4 arguments"
n-cond:
- module: "nova.notifications"
@@ -75,6 +93,16 @@
c-api:
- module: "cinder.api.middleware.fault"
message: "Caught error: Volume .* could not be found"
+ - module: "cinder.api.middleware.fault"
+ message: "Caught error: Snapshot .* could not be found"
+
+c-vol:
+ - module: "cinder.brick.iscsi.iscsi"
+ message: "Failed to create iscsi target for volume id"
+ - module: "cinder.brick.local_dev.lvm"
+ message: "/dev/dm-1: stat failed: No such file or directory"
+ - module: "cinder.brick.local_dev.lvm"
+ message: "Can't remove open logical volume"
q-dhpc:
- module: "neutron.common.legacy"
@@ -89,6 +117,8 @@
message: ".*"
- module: "ceilometer.collector.dispatcher.database"
message: "duplicate key value violates unique constraint"
+ - module: "ceilometer.collector.dispatcher.database"
+ message: "Failed to record metering data: QueuePool limit"
q-agt:
- module: "neutron.agent.linux.ovs_lib"
@@ -108,6 +138,9 @@
- module: "neutron.agent.l3_agent"
message: "Failed synchronizing routers"
+q-vpn:
+ - module: "neutron.common.legacy"
+ message: "Skipping unknown group key: firewall_driver"
q-lbaas:
- module: "neutron.common.legacy"
@@ -123,9 +156,7 @@
- module: "neutron.openstack.common.rpc.amqp"
message: "Exception during message handling"
- module: "neutron.openstack.common.rpc.common"
- message: "Network .* could not be found"
- - module: "neutron.openstack.common.rpc.common"
- message: "Pool .* could not be found"
+ message: "(Network|Pool|Subnet|Agent|Port) .* could not be found"
- module: "neutron.api.v2.resource"
- message: "show failed"
+ message: ".* failed"
diff --git a/requirements.txt b/requirements.txt
index 3b9ec44..4f6a1d3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,20 +5,20 @@
jsonschema>=1.3.0,!=1.4.0
testtools>=0.9.32
lxml>=2.3
-boto>=2.4.0
+boto>=2.4.0,!=2.13.0
paramiko>=1.8.0
netaddr
python-glanceclient>=0.9.0
-python-keystoneclient>=0.3.0
-python-novaclient>=2.12.0
-python-neutronclient>=2.2.3,<3
-python-cinderclient>=1.0.4
+python-keystoneclient>=0.4.1
+python-novaclient>=2.15.0
+python-neutronclient>=2.3.0,<3
+python-cinderclient>=1.0.6
python-heatclient>=0.2.3
testresources>=0.2.4
-keyring>=1.6.1
+keyring>=1.6.1,<2.0
testrepository>=0.0.17
oslo.config>=1.2.0
eventlet>=0.13.0
-six<1.4.0
+six>=1.4.1
iso8601>=0.1.4
fixtures>=0.3.14
diff --git a/setup.cfg b/setup.cfg
index a4cf118..23a97ff 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = tempest
-version = 2013.2
+version = 2014.1
summary = OpenStack Integration Testing
description-file =
README.rst
@@ -17,20 +17,7 @@
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
-[global]
-setup-hooks =
- pbr.hooks.setup_hook
-
[build_sphinx]
all_files = 1
build-dir = doc/build
source-dir = doc/source
-
-[nosetests]
-# NOTE(jkoelker) To run the test suite under nose install the following
-# coverage http://pypi.python.org/pypi/coverage
-# openstack-nose https://github.com/openstack-dev/openstack-nose
-verbosity=2
-
-[pbr]
-autodoc_tree_index_modules=true
diff --git a/setup.py b/setup.py
index 59a0090..70c2b3f 100755
--- a/setup.py
+++ b/setup.py
@@ -14,8 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
setuptools.setup(
- setup_requires=['d2to1', 'pbr'],
- d2to1=True)
+ setup_requires=['pbr'],
+ pbr=True)
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 14ab236..4ff6b07 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -22,7 +22,7 @@
from tempest.test import attr
-class AggregatesAdminTestJSON(base.BaseComputeAdminTest):
+class AggregatesAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Aggregates API that require admin privileges
@@ -85,7 +85,7 @@
aggregates))
@attr(type='gate')
- def test_aggregate_create_get_details(self):
+ def test_aggregate_create_update_metadata_get_details(self):
# Create an aggregate and ensure its details are returned.
aggregate_name = rand_name(self.aggregate_name_prefix)
resp, aggregate = self.client.create_aggregate(aggregate_name)
@@ -96,6 +96,18 @@
self.assertEqual(aggregate['name'], body['name'])
self.assertEqual(aggregate['availability_zone'],
body['availability_zone'])
+ self.assertEqual({}, body["metadata"])
+
+ # set the metadata of the aggregate
+ meta = {"key": "value"}
+ resp, body = self.client.set_metadata(aggregate['id'], meta)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(meta, body["metadata"])
+
+ # verify the metadata has been set
+ resp, body = self.client.get_aggregate(aggregate['id'])
+ self.assertEqual(200, resp.status)
+ self.assertEqual(meta, body["metadata"])
@attr(type='gate')
def test_aggregate_create_update_with_az(self):
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index d1e1be6..d6488c4 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class AvailabilityZoneAdminTestJSON(base.BaseComputeAdminTest):
+class AvailabilityZoneAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Availability Zone API List that require admin privileges
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index ee262df..766589e 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class FixedIPsTestJson(base.BaseComputeAdminTest):
+class FixedIPsTestJson(base.BaseV2ComputeAdminTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 004268e..75b8dad 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -24,7 +24,7 @@
from tempest.test import skip_because
-class FlavorsAdminTestJSON(base.BaseComputeAdminTest):
+class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Flavors API Create and Delete that require admin privileges
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 5495778..e8ae3b4 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -25,7 +25,7 @@
from tempest.test import attr
-class FlavorsAccessTestJSON(base.BaseComputeAdminTest):
+class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Flavor Access API extension.
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index fb6a463..0fd4d11 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class FlavorsExtraSpecsTestJSON(base.BaseComputeAdminTest):
+class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Flavor Extra Spec API extension.
@@ -79,6 +79,12 @@
self.client.get_flavor_extra_spec(self.flavor['id'])
self.assertEqual(get_resp.status, 200)
self.assertEqual(get_body, specs)
+ # GET a key value and verify
+ get_resp, get_body = \
+ self.client.get_flavor_extra_spec_with_key(self.flavor['id'],
+ "key2")
+ self.assertEqual(get_resp.status, 200)
+ self.assertEqual(get_body, specs['key2'])
# UNSET extra specs that were set in this test
unset_resp, _ = \
self.client.unset_flavor_extra_spec(self.flavor['id'], "key1")
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index bf09428..8e451a0 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -16,12 +16,10 @@
from tempest.api.compute import base
from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
from tempest.test import attr
-class HostsAdminTestJSON(base.BaseComputeAdminTest):
+class HostsAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests hosts API using admin privileges.
@@ -33,7 +31,13 @@
def setUpClass(cls):
super(HostsAdminTestJSON, cls).setUpClass()
cls.client = cls.os_adm.hosts_client
- cls.non_admin_client = cls.os.hosts_client
+
+ def _get_host_name(self):
+ resp, hosts = self.client.list_hosts()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(hosts) >= 1)
+ hostname = hosts[0]['host_name']
+ return hostname
@attr(type='gate')
def test_list_hosts(self):
@@ -53,14 +57,7 @@
self.assertTrue(len(hosts) >= 1)
self.assertIn(host, hosts)
- @attr(type='negative')
- def test_list_hosts_with_non_existent_zone(self):
- params = {'zone': 'xxx'}
- resp, hosts = self.client.list_hosts(params)
- self.assertEqual(0, len(hosts))
- self.assertEqual(200, resp.status)
-
- @attr(type='negative')
+ @attr(type='gate')
def test_list_hosts_with_a_blank_zone(self):
# If send the request with a blank zone, the request will be successful
# and it will return all the hosts list
@@ -69,17 +66,18 @@
self.assertNotEqual(0, len(hosts))
self.assertEqual(200, resp.status)
- @attr(type=['negative', 'gate'])
- def test_list_hosts_with_non_admin_user(self):
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.list_hosts)
+ @attr(type='gate')
+ def test_list_hosts_with_nonexistent_zone(self):
+ # If send the request with a nonexistent zone, the request will be
+ # successful and no hosts will be retured
+ params = {'zone': 'xxx'}
+ resp, hosts = self.client.list_hosts(params)
+ self.assertEqual(0, len(hosts))
+ self.assertEqual(200, resp.status)
@attr(type='gate')
def test_show_host_detail(self):
- resp, hosts = self.client.list_hosts()
- self.assertEqual(200, resp.status)
- self.assertTrue(len(hosts) >= 1)
- hostname = hosts[0]['host_name']
+ hostname = self._get_host_name()
resp, resources = self.client.show_host_detail(hostname)
self.assertEqual(200, resp.status)
@@ -92,12 +90,6 @@
self.assertIsNotNone(host_resource['project'])
self.assertEqual(hostname, host_resource['host'])
- @attr(type='negative')
- def test_show_host_detail_with_nonexist_hostname(self):
- hostname = rand_name('rand_hostname')
- self.assertRaises(exceptions.NotFound,
- self.client.show_host_detail, hostname)
-
class HostsAdminTestXML(HostsAdminTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
new file mode 100644
index 0000000..6b24e72
--- /dev/null
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -0,0 +1,174 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+#
+# 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.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class HostsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+ """
+ Tests hosts API using admin privileges.
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(HostsAdminNegativeTestJSON, cls).setUpClass()
+ cls.client = cls.os_adm.hosts_client
+ cls.non_admin_client = cls.os.hosts_client
+
+ def _get_host_name(self):
+ resp, hosts = self.client.list_hosts()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(hosts) >= 1)
+ hostname = hosts[0]['host_name']
+ return hostname
+
+ @attr(type=['negative', 'gate'])
+ def test_list_hosts_with_non_admin_user(self):
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.list_hosts)
+
+ @attr(type=['negative', 'gate'])
+ def test_show_host_detail_with_nonexistent_hostname(self):
+ nonexitent_hostname = data_utils.rand_name('rand_hostname')
+ self.assertRaises(exceptions.NotFound,
+ self.client.show_host_detail, nonexitent_hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_show_host_detail_with_non_admin_user(self):
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.show_host_detail,
+ hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_update_host_with_non_admin_user(self):
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.update_host,
+ hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_update_host_with_extra_param(self):
+ # only 'status' and 'maintenance_mode' are the valid params.
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.BadRequest,
+ self.client.update_host,
+ hostname,
+ status='enable',
+ maintenance_mode='enable',
+ param='XXX')
+
+ @attr(type=['negative', 'gate'])
+ def test_update_host_with_invalid_status(self):
+ # 'status' can only be 'enable' or 'disable'
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.BadRequest,
+ self.client.update_host,
+ hostname,
+ status='invalid',
+ maintenance_mode='enable')
+
+ @attr(type=['negative', 'gate'])
+ def test_update_host_with_invalid_maintenance_mode(self):
+ # 'maintenance_mode' can only be 'enable' or 'disable'
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.BadRequest,
+ self.client.update_host,
+ hostname,
+ status='enable',
+ maintenance_mode='invalid')
+
+ @attr(type=['negative', 'gate'])
+ def test_update_host_without_param(self):
+ # 'status' or 'maintenance_mode' needed for host update
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.BadRequest,
+ self.client.update_host,
+ hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_update_nonexistent_host(self):
+ nonexitent_hostname = data_utils.rand_name('rand_hostname')
+
+ self.assertRaises(exceptions.NotFound,
+ self.client.update_host,
+ nonexitent_hostname,
+ status='enable',
+ maintenance_mode='enable')
+
+ @attr(type=['negative', 'gate'])
+ def test_startup_nonexistent_host(self):
+ nonexitent_hostname = data_utils.rand_name('rand_hostname')
+
+ self.assertRaises(exceptions.NotFound,
+ self.client.startup_host,
+ nonexitent_hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_startup_host_with_non_admin_user(self):
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.startup_host,
+ hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_shutdown_nonexistent_host(self):
+ nonexitent_hostname = data_utils.rand_name('rand_hostname')
+
+ self.assertRaises(exceptions.NotFound,
+ self.client.shutdown_host,
+ nonexitent_hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_shutdown_host_with_non_admin_user(self):
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.shutdown_host,
+ hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_reboot_nonexistent_host(self):
+ nonexitent_hostname = data_utils.rand_name('rand_hostname')
+
+ self.assertRaises(exceptions.NotFound,
+ self.client.reboot_host,
+ nonexitent_hostname)
+
+ @attr(type=['negative', 'gate'])
+ def test_reboot_host_with_non_admin_user(self):
+ hostname = self._get_host_name()
+
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.reboot_host,
+ hostname)
+
+
+class HostsAdminNegativeTestXML(HostsAdminNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index b7c3574..ef4f51f 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -19,7 +19,7 @@
from tempest.test import attr
-class HypervisorAdminTestJSON(base.BaseComputeAdminTest):
+class HypervisorAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Hypervisors API that require admin privileges
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 69b8d9c..c6455b5 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class HypervisorAdminNegativeTestJSON(base.BaseComputeAdminTest):
+class HypervisorAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Hypervisors API that require admin privileges
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 757dfc0..6c4d350 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -23,8 +23,9 @@
from tempest.test import skip_because
-class QuotasAdminTestJSON(base.BaseComputeAdminTest):
+class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
_interface = 'json'
+ force_tenant_isolation = True
@classmethod
def setUpClass(cls):
@@ -39,12 +40,8 @@
# NOTE(afazekas): these test cases should always create and use a new
# tenant most of them should be skipped if we can't do that
- if cls.config.compute.allow_tenant_isolation:
- cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
- 'tenantId')
- else:
- cls.demo_tenant_id = [tnt['id'] for tnt in tenants if tnt['name']
- == cls.config.identity.tenant_name][0]
+ cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
+ 'tenantId')
cls.default_quota_set = set(('injected_file_content_bytes',
'metadata_items', 'injected_files',
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 97e0e69..ebc661c 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -22,7 +22,7 @@
from tempest.test import skip_because
-class ServersAdminTestJSON(base.BaseComputeAdminTest):
+class ServersAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Servers API using admin privileges
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 434ea2f..327d8b8 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -21,7 +21,7 @@
from tempest.test import attr
-class ServicesAdminTestJSON(base.BaseComputeAdminTest):
+class ServicesAdminTestJSON(base.BaseV2ComputeAdminTest):
"""
Tests Services API. List and Enable/Disable require admin privileges.
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index ce05899..3178ead 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -23,7 +23,7 @@
import time
-class TenantUsagesTestJSON(base.BaseComputeAdminTest):
+class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
_interface = 'json'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 885adcf..5679a45 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -19,7 +19,6 @@
from tempest.api import compute
from tempest import clients
-from tempest.common import isolated_creds
from tempest.common.utils.data_utils import parse_image_id
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
@@ -34,6 +33,7 @@
"""Base test case class for all Compute API tests."""
conclusion = compute.generic_setup_package()
+ force_tenant_isolation = False
@classmethod
def setUpClass(cls):
@@ -41,50 +41,22 @@
if not cls.config.service_available.nova:
skip_msg = ("%s skipped as nova is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
- if cls.config.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_primary_creds()
- username, tenant_name, password = creds
- os = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name,
- interface=cls._interface)
- else:
- os = clients.Manager(interface=cls._interface)
+ os = cls.get_client_manager()
cls.os = os
- cls.servers_client = os.servers_client
- cls.flavors_client = os.flavors_client
- cls.images_client = os.images_client
- cls.extensions_client = os.extensions_client
- cls.floating_ips_client = os.floating_ips_client
- cls.keypairs_client = os.keypairs_client
- cls.security_groups_client = os.security_groups_client
- cls.quotas_client = os.quotas_client
- cls.limits_client = os.limits_client
- cls.volumes_extensions_client = os.volumes_extensions_client
- cls.volumes_client = os.volumes_client
- cls.interfaces_client = os.interfaces_client
- cls.fixed_ips_client = os.fixed_ips_client
- cls.availability_zone_client = os.availability_zone_client
- cls.aggregates_client = os.aggregates_client
- cls.services_client = os.services_client
- cls.hypervisor_client = os.hypervisor_client
cls.build_interval = cls.config.compute.build_interval
cls.build_timeout = cls.config.compute.build_timeout
cls.ssh_user = cls.config.compute.ssh_user
- cls.image_ssh_user = cls.config.compute.image_ssh_user
- cls.image_ssh_password = cls.config.compute.image_ssh_password
cls.image_ref = cls.config.compute.image_ref
cls.image_ref_alt = cls.config.compute.image_ref_alt
cls.flavor_ref = cls.config.compute.flavor_ref
cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
+ cls.image_ssh_user = cls.config.compute.image_ssh_user
+ cls.image_ssh_password = cls.config.compute.image_ssh_password
cls.servers = []
cls.images = []
- cls.servers_client_v3_auth = os.servers_client_v3_auth
-
@classmethod
def clear_servers(cls):
for server in cls.servers:
@@ -129,7 +101,7 @@
def tearDownClass(cls):
cls.clear_images()
cls.clear_servers()
- cls.isolated_creds.clear_isolated_creds()
+ cls.clear_isolated_creds()
super(BaseComputeTest, cls).tearDownClass()
@classmethod
@@ -162,7 +134,7 @@
@classmethod
def create_image_from_server(cls, server_id, **kwargs):
- """Wrapper utility that returns a test server."""
+ """Wrapper utility that returns an image created from the server."""
name = rand_name(cls.__name__ + "-image")
if 'name' in kwargs:
name = kwargs.pop('name')
@@ -195,12 +167,37 @@
time.sleep(self.build_interval)
-class BaseComputeAdminTest(BaseComputeTest):
- """Base test case class for all Compute Admin API tests."""
+class BaseV2ComputeTest(BaseComputeTest):
@classmethod
def setUpClass(cls):
- super(BaseComputeAdminTest, cls).setUpClass()
+ super(BaseV2ComputeTest, cls).setUpClass()
+ cls.servers_client = cls.os.servers_client
+ cls.flavors_client = cls.os.flavors_client
+ cls.images_client = cls.os.images_client
+ cls.extensions_client = cls.os.extensions_client
+ cls.floating_ips_client = cls.os.floating_ips_client
+ cls.keypairs_client = cls.os.keypairs_client
+ cls.security_groups_client = cls.os.security_groups_client
+ cls.quotas_client = cls.os.quotas_client
+ cls.limits_client = cls.os.limits_client
+ cls.volumes_extensions_client = cls.os.volumes_extensions_client
+ cls.volumes_client = cls.os.volumes_client
+ cls.interfaces_client = cls.os.interfaces_client
+ cls.fixed_ips_client = cls.os.fixed_ips_client
+ cls.availability_zone_client = cls.os.availability_zone_client
+ cls.aggregates_client = cls.os.aggregates_client
+ cls.services_client = cls.os.services_client
+ cls.hypervisor_client = cls.os.hypervisor_client
+ cls.servers_client_v3_auth = cls.os.servers_client_v3_auth
+
+
+class BaseV2ComputeAdminTest(BaseV2ComputeTest):
+ """Base test case class for Compute Admin V2 API tests."""
+
+ @classmethod
+ def setUpClass(cls):
+ super(BaseV2ComputeAdminTest, cls).setUpClass()
admin_username = cls.config.compute_admin.username
admin_password = cls.config.compute_admin.password
admin_tenant = cls.config.compute_admin.tenant_name
@@ -208,7 +205,8 @@
msg = ("Missing Compute Admin API credentials "
"in configuration.")
raise cls.skipException(msg)
- if cls.config.compute.allow_tenant_isolation:
+ if (cls.config.compute.allow_tenant_isolation or
+ cls.force_tenant_isolation is True):
creds = cls.isolated_creds.get_admin_creds()
admin_username, admin_tenant_name, admin_password = creds
cls.os_adm = clients.Manager(username=admin_username,
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index cea13a0..eac98ea 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class FlavorsTestJSON(base.BaseComputeTest):
+class FlavorsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index a5a361e..ff7188b 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class FloatingIPsTestJSON(base.BaseComputeTest):
+class FloatingIPsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
server_id = None
floating_ip = None
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index fb9610a..7fec2d1 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class FloatingIPDetailsTestJSON(base.BaseComputeTest):
+class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 8f19514..df857bf 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -21,7 +21,7 @@
from tempest.test import attr
-class ImagesMetadataTestJSON(base.BaseComputeTest):
+class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 57f26f8..383ea1d 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class ImagesTestJSON(base.BaseComputeTest):
+class ImagesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index accfc35..bec5ea4 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -30,7 +30,7 @@
LOG = logging.getLogger(__name__)
-class ImagesOneServerTestJSON(base.BaseComputeTest):
+class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
def tearDown(self):
@@ -46,7 +46,8 @@
super(ImagesOneServerTestJSON, self).setUp()
# Check if the server is in a clean state after test
try:
- self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+ self.servers_client.wait_for_server_status(self.server_id,
+ 'ACTIVE')
except Exception as exc:
LOG.exception(exc)
# Rebuild server if cannot reach the ACTIVE state
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 8a8d5bd..8d4e47b 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -25,7 +25,7 @@
LOG = logging.getLogger(__name__)
-class ListImageFiltersTestJSON(base.BaseComputeTest):
+class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index 0647f86..a6726b6 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -19,7 +19,7 @@
from tempest.test import attr
-class ListImagesTestJSON(base.BaseComputeTest):
+class ListImagesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 9b2a1de..d059994 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -21,7 +21,7 @@
from tempest.test import attr
-class KeyPairsTestJSON(base.BaseComputeTest):
+class KeyPairsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index d2430df..2809244 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class AbsoluteLimitsTestJSON(base.BaseComputeTest):
+class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 5faa9a4..9dc164d 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -23,7 +23,7 @@
from tempest.test import skip_because
-class SecurityGroupRulesTestJSON(base.BaseComputeTest):
+class SecurityGroupRulesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 2d9c62d..6e08700 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -25,7 +25,7 @@
from tempest.test import skip_because
-class SecurityGroupsTestJSON(base.BaseComputeTest):
+class SecurityGroupsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 9f66a6c..c554dc2 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -19,7 +19,7 @@
import time
-class AttachInterfacesTestJSON(base.BaseComputeTest):
+class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 31ca387..adbc048 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -28,7 +28,7 @@
from tempest.test import attr
-class ServersTestJSON(base.BaseComputeTest):
+class ServersTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
run_ssh = tempest.config.TempestConfig().compute.run_ssh
disk_config = 'AUTO'
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index ffc8b6b..76a7117 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -22,7 +22,7 @@
from tempest.test import attr
-class ServerDiskConfigTestJSON(base.BaseComputeTest):
+class ServerDiskConfigTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index f13e51e..61be50a 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class InstanceActionsTestJSON(base.BaseComputeTest):
+class InstanceActionsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 8e95671..778b8ec 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -24,7 +24,7 @@
from tempest.test import skip_because
-class ListServerFiltersTestJSON(base.BaseComputeTest):
+class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 9dd2e27..bef45a7 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -24,7 +24,7 @@
from tempest.test import attr
-class ListServersNegativeTestJSON(base.BaseComputeTest):
+class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 7e4a70b..d582894 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -21,7 +21,7 @@
from tempest.test import attr
-class MultipleCreateTestJSON(base.BaseComputeTest):
+class MultipleCreateTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
_name = 'multiple-create-test'
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f073ebc..6f50a02 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -30,7 +30,7 @@
from tempest.test import skip_because
-class ServerActionsTestJSON(base.BaseComputeTest):
+class ServerActionsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
resize_available = tempest.config.TempestConfig().compute.resize_available
run_ssh = tempest.config.TempestConfig().compute.run_ssh
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index b1b9253..a594f6c 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class ServerAddressesTest(base.BaseComputeTest):
+class ServerAddressesTest(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 15c3e6b..4e45e4b 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class ServerMetadataTestJSON(base.BaseComputeTest):
+class ServerMetadataTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 2019732..ba5c0df 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -22,7 +22,7 @@
from tempest.test import attr
-class ServerPersonalityTestJSON(base.BaseComputeTest):
+class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 3cbae56..f72d36e 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -22,7 +22,7 @@
from tempest.test import attr
-class ServerRescueTestJSON(base.BaseComputeTest):
+class ServerRescueTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
run_ssh = tempest.config.TempestConfig().compute.run_ssh
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 5ce51c0..5f68201 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class ServersTestJSON(base.BaseComputeTest):
+class ServersTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
@@ -119,6 +119,15 @@
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ @attr(type='gate')
+ def test_create_server_with_ipv6_addr_only(self):
+ # Create a server without an IPv4 address(only IPv6 address).
+ resp, server = self.create_server(accessIPv6='2001:2001::3')
+ self.assertEqual('202', resp['status'])
+ self.client.wait_for_server_status(server['id'], 'ACTIVE')
+ resp, server = self.client.get_server(server['id'])
+ self.assertEqual('2001:2001::3', server['accessIPv6'])
+
class ServersTestXML(ServersTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index d2088fa..0f753a0 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -26,7 +26,7 @@
from tempest.test import attr
-class ServersNegativeTestJSON(base.BaseComputeTest):
+class ServersNegativeTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
def setUp(self):
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 2c7ff32..a00e8ed 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -25,7 +25,7 @@
from tempest.test import skip_because
-class VirtualInterfacesTestJSON(base.BaseComputeTest):
+class VirtualInterfacesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
CONF = config.TempestConfig()
diff --git a/tempest/api/compute/test_auth_token.py b/tempest/api/compute/test_auth_token.py
index bbe92ef..ffeede8 100644
--- a/tempest/api/compute/test_auth_token.py
+++ b/tempest/api/compute/test_auth_token.py
@@ -19,7 +19,7 @@
import tempest.config as config
-class AuthTokenTestJSON(base.BaseComputeTest):
+class AuthTokenTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 0a8595f..a7d9310 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -27,7 +27,7 @@
LOG = logging.getLogger(__name__)
-class AuthorizationTestJSON(base.BaseComputeTest):
+class AuthorizationTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index c1b7aa5..8f1e446 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class ExtensionsTestJSON(base.BaseComputeTest):
+class ExtensionsTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@attr(type='gate')
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index 65daee0..bb8b372 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -26,7 +26,7 @@
from tempest.test import attr
-class LiveBlockMigrationTestJSON(base.BaseComputeAdminTest):
+class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
_interface = 'json'
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index 6453cf4..4617bd2 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -19,7 +19,7 @@
from tempest.test import attr
-class QuotasTestJSON(base.BaseComputeTest):
+class QuotasTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index ee1ad9e..a993077 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class AttachVolumeTestJSON(base.BaseComputeTest):
+class AttachVolumeTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
run_ssh = tempest.config.TempestConfig().compute.run_ssh
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index fba8347..192d81e 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class VolumesGetTestJSON(base.BaseComputeTest):
+class VolumesGetTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 956abdf..b4e00f9 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -20,7 +20,7 @@
from tempest.test import attr
-class VolumesTestJSON(base.BaseComputeTest):
+class VolumesTestJSON(base.BaseV2ComputeTest):
"""
This test creates a number of 1G volumes. To run successfully,
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 90e6946..785902e 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -23,7 +23,7 @@
from tempest.test import attr
-class VolumesNegativeTest(base.BaseComputeTest):
+class VolumesNegativeTest(base.BaseV2ComputeTest):
_interface = 'json'
@classmethod
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
new file mode 100644
index 0000000..7e3bde4
--- /dev/null
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -0,0 +1,45 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# All Rights Reserved.
+#
+# 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.
+
+from tempest.api.image import base
+from tempest.common.utils import data_utils
+from tempest.test import attr
+
+
+class ImagesTagsTest(base.BaseV2ImageTest):
+
+ @attr(type='gate')
+ def test_update_delete_tags_for_image(self):
+ resp, body = self.create_image(container_format='bare',
+ disk_format='raw',
+ visibility='public')
+ image_id = body['id']
+ tag = data_utils.rand_name('tag-')
+ self.addCleanup(self.client.delete_image, image_id)
+
+ # Creating image tag and verify it.
+ resp, body = self.client.add_image_tag(image_id, tag)
+ self.assertEqual(resp.status, 204)
+ resp, body = self.client.get_image_metadata(image_id)
+ self.assertEqual(resp.status, 200)
+ self.assertIn(tag, body['tags'])
+
+ # Deleting image tag and verify it.
+ resp = self.client.delete_image_tag(image_id, tag)
+ self.assertEqual(resp.status, 204)
+ resp, body = self.client.get_image_metadata(image_id)
+ self.assertEqual(resp.status, 200)
+ self.assertNotIn(tag, body['tags'])
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
new file mode 100644
index 0000000..e0d84de
--- /dev/null
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -0,0 +1,46 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# All Rights Reserved.
+#
+# 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 uuid
+
+from tempest.api.image import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ImagesTagsNegativeTest(base.BaseV2ImageTest):
+
+ @attr(type=['negative', 'gate'])
+ def test_update_tags_for_non_existing_image(self):
+ # Update tag with non existing image.
+ tag = data_utils.rand_name('tag-')
+ non_exist_image = str(uuid.uuid4())
+ self.assertRaises(exceptions.NotFound, self.client.add_image_tag,
+ non_exist_image, tag)
+
+ @attr(type=['negative', 'gate'])
+ def test_delete_non_existing_tag(self):
+ # Delete non existing tag.
+ resp, body = self.create_image(container_format='bare',
+ disk_format='raw',
+ is_public=True,
+ )
+ image_id = body['id']
+ tag = data_utils.rand_name('non-exist-tag-')
+ self.addCleanup(self.client.delete_image, image_id)
+ self.assertRaises(exceptions.NotFound, self.client.delete_image_tag,
+ image_id, tag)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index b6c2679..159c4f5 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -68,75 +68,39 @@
@classmethod
def tearDownClass(cls):
- has_exception = False
+ # Clean up vpn services
for vpnservice in cls.vpnservices:
- try:
- cls.client.delete_vpn_service(vpnservice['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
-
+ cls.client.delete_vpn_service(vpnservice['id'])
+ # Clean up routers
for router in cls.routers:
- try:
- resp, body = cls.client.list_router_interfaces(router['id'])
- interfaces = body['ports']
- for i in interfaces:
- cls.client.remove_router_interface_with_subnet_id(
- router['id'], i['fixed_ips'][0]['subnet_id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
- try:
- cls.client.delete_router(router['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
-
+ resp, body = cls.client.list_router_interfaces(router['id'])
+ interfaces = body['ports']
+ for i in interfaces:
+ cls.client.remove_router_interface_with_subnet_id(
+ router['id'], i['fixed_ips'][0]['subnet_id'])
+ cls.client.delete_router(router['id'])
+ # Clean up health monitors
for health_monitor in cls.health_monitors:
- try:
- cls.client.delete_health_monitor(health_monitor['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_health_monitor(health_monitor['id'])
+ # Clean up members
for member in cls.members:
- try:
- cls.client.delete_member(member['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_member(member['id'])
+ # Clean up vips
for vip in cls.vips:
- try:
- cls.client.delete_vip(vip['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_vip(vip['id'])
+ # Clean up pools
for pool in cls.pools:
- try:
- cls.client.delete_pool(pool['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_pool(pool['id'])
+ # Clean up ports
for port in cls.ports:
- try:
- cls.client.delete_port(port['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_port(port['id'])
+ # Clean up subnets
for subnet in cls.subnets:
- try:
- cls.client.delete_subnet(subnet['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_subnet(subnet['id'])
+ # Clean up networks
for network in cls.networks:
- try:
- cls.client.delete_network(network['id'])
- except Exception as exc:
- LOG.exception(exc)
- has_exception = True
+ cls.client.delete_network(network['id'])
super(BaseNetworkTest, cls).tearDownClass()
- if has_exception:
- raise exceptions.TearDownException()
@classmethod
def create_network(cls, network_name=None):
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
index c3fb821..43e7f68 100644
--- a/tempest/api/network/common.py
+++ b/tempest/api/network/common.py
@@ -56,7 +56,9 @@
class DeletableSubnet(DeletableResource):
- _router_ids = set()
+ def __init__(self, *args, **kwargs):
+ super(DeletableSubnet, self).__init__(*args, **kwargs)
+ self._router_ids = set()
def add_to_router(self, router_id):
self._router_ids.add(router_id)
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index d321e23..daeb89f 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -16,6 +16,7 @@
# under the License.
from tempest.api.network import test_security_groups as base
+from tempest.common.utils import data_utils
from tempest import exceptions
from tempest.test import attr
import uuid
@@ -37,6 +38,54 @@
self.client.show_security_group_rule,
non_exist_id)
+ @attr(type=['negative', 'smoke'])
+ def test_delete_non_existent_security_group(self):
+ non_exist_id = 'fictional-id'
+ self.assertRaises(exceptions.NotFound,
+ self.client.delete_security_group,
+ non_exist_id
+ )
+
+ @attr(type=['negative', 'smoke'])
+ def test_create_security_group_rule_with_bad_protocol(self):
+ # Create a security group
+ name = data_utils.rand_name('secgroup-')
+ resp, group_create_body = self.client.create_security_group(name)
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self._delete_security_group,
+ group_create_body['security_group']['id'])
+ self.assertEqual(group_create_body['security_group']['name'], name)
+
+ #Create rule with bad protocol name
+ pname = 'bad_protocol_name'
+ self.assertRaises(exceptions.BadRequest,
+ self.client.create_security_group_rule,
+ group_create_body['security_group']['id'],
+ protocol=pname)
+
+ @attr(type=['negative', 'smoke'])
+ def test_create_security_group_rule_with_invalid_ports(self):
+ # Create a security group
+ name = data_utils.rand_name('secgroup-')
+ resp, group_create_body = self.client.create_security_group(name)
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self._delete_security_group,
+ group_create_body['security_group']['id'])
+ self.assertEqual(group_create_body['security_group']['name'], name)
+
+ #Create rule with invalid ports
+ states = [(-16, 80, 'Invalid value for port -16'),
+ (80, 79, 'port_range_min must be <= port_range_max'),
+ (80, 65536, 'Invalid value for port 65536')]
+ for pmin, pmax, msg in states:
+ ex = self.assertRaises(exceptions.BadRequest,
+ self.client.create_security_group_rule,
+ group_create_body['security_group']['id'],
+ protocol='tcp',
+ port_range_min=pmin,
+ port_range_max=pmax)
+ self.assertIn(msg, str(ex))
+
class NegativeSecGroupTestXML(NegativeSecGroupTest):
_interface = 'xml'
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 1a3f775..90b0914 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -101,7 +101,7 @@
'limit': limit}
resp, container_list = \
self.account_client.list_account_containers(params=params)
- self.assertLessEqual(len(container_list), limit)
+ self.assertTrue(len(container_list) <= limit, str(container_list))
@attr(type='smoke')
def test_list_account_metadata(self):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 98694c5..cdf8638 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -18,7 +18,6 @@
import time
from tempest import clients
-from tempest.common import isolated_creds
from tempest.openstack.common import log as logging
import tempest.test
@@ -32,21 +31,12 @@
@classmethod
def setUpClass(cls):
super(BaseVolumeTest, cls).setUpClass()
- cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
if not cls.config.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- if cls.config.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_primary_creds()
- username, tenant_name, password = creds
- os = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name,
- interface=cls._interface)
- else:
- os = clients.Manager(interface=cls._interface)
+ os = cls.get_client_manager()
cls.os = os
cls.volumes_client = os.volumes_client
@@ -69,7 +59,7 @@
def tearDownClass(cls):
cls.clear_snapshots()
cls.clear_volumes()
- cls.isolated_creds.clear_isolated_creds()
+ cls.clear_isolated_creds()
super(BaseVolumeTest, cls).tearDownClass()
@classmethod
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
new file mode 100644
index 0000000..04a4774
--- /dev/null
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 uuid
+
+from tempest.api.volume import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class VolumesSnapshotNegativeTest(base.BaseVolumeTest):
+ _interface = "json"
+
+ @attr(type=['negative', 'gate'])
+ def test_create_snapshot_with_nonexistent_volume_id(self):
+ # Create a snapshot with nonexistent volume id
+ s_name = data_utils.rand_name('snap')
+ self.assertRaises(exceptions.NotFound,
+ self.snapshots_client.create_snapshot,
+ str(uuid.uuid4()), display_name=s_name)
+
+ @attr(type=['negative', 'gate'])
+ def test_create_snapshot_without_passing_volume_id(self):
+ # Create a snapshot without passing volume id
+ s_name = data_utils.rand_name('snap')
+ self.assertRaises(exceptions.NotFound,
+ self.snapshots_client.create_snapshot,
+ None, display_name=s_name)
+
+
+class VolumesSnapshotNegativeTestXML(VolumesSnapshotNegativeTest):
+ _interface = "xml"
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/test_nova.py
index 94415f0..1aa8f2c 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -22,6 +22,7 @@
import tempest.cli
from tempest.openstack.common import log as logging
+import tempest.test
CONF = cfg.CONF
@@ -73,7 +74,7 @@
def test_admin_dns_domains(self):
self.nova('dns-domains')
- @testtools.skip("Test needs parameters, Bug #1157349")
+ @tempest.test.skip_because(bug="1157349")
def test_admin_dns_list(self):
self.nova('dns-list')
@@ -111,7 +112,7 @@
def test_admin_image_list(self):
self.nova('image-list')
- @testtools.skip("Test needs parameters, Bug #1157349")
+ @tempest.test.skip_because(bug="1157349")
def test_admin_interface_list(self):
self.nova('interface-list')
@@ -136,7 +137,7 @@
def test_admin_secgroup_list(self):
self.nova('secgroup-list')
- @testtools.skip("Test needs parameters, Bug #1157349")
+ @tempest.test.skip_because(bug="1157349")
def test_admin_secgroup_list_rules(self):
self.nova('secgroup-list-rules')
diff --git a/tempest/clients.py b/tempest/clients.py
index 63ce1ba..dd104a7 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -116,151 +116,6 @@
LOG = logging.getLogger(__name__)
-IMAGES_CLIENTS = {
- "json": ImagesClientJSON,
- "xml": ImagesClientXML,
-}
-
-NETWORKS_CLIENTS = {
- "json": NetworkClientJSON,
- "xml": NetworkClientXML,
-}
-
-KEYPAIRS_CLIENTS = {
- "json": KeyPairsClientJSON,
- "xml": KeyPairsClientXML,
-}
-
-QUOTAS_CLIENTS = {
- "json": QuotasClientJSON,
- "xml": QuotasClientXML,
-}
-
-SERVERS_CLIENTS = {
- "json": ServersClientJSON,
- "xml": ServersClientXML,
-}
-
-LIMITS_CLIENTS = {
- "json": LimitsClientJSON,
- "xml": LimitsClientXML,
-}
-
-FLAVORS_CLIENTS = {
- "json": FlavorsClientJSON,
- "xml": FlavorsClientXML
-}
-
-EXTENSIONS_CLIENTS = {
- "json": ExtensionsClientJSON,
- "xml": ExtensionsClientXML
-}
-
-VOLUMES_EXTENSIONS_CLIENTS = {
- "json": VolumesExtensionsClientJSON,
- "xml": VolumesExtensionsClientXML,
-}
-
-FLOAT_CLIENTS = {
- "json": FloatingIPsClientJSON,
- "xml": FloatingIPsClientXML,
-}
-
-SNAPSHOTS_CLIENTS = {
- "json": SnapshotsClientJSON,
- "xml": SnapshotsClientXML,
-}
-
-VOLUMES_CLIENTS = {
- "json": VolumesClientJSON,
- "xml": VolumesClientXML,
-}
-
-VOLUME_TYPES_CLIENTS = {
- "json": VolumeTypesClientJSON,
- "xml": VolumeTypesClientXML,
-}
-
-IDENTITY_CLIENT = {
- "json": IdentityClientJSON,
- "xml": IdentityClientXML,
-}
-
-IDENTITY_V3_CLIENT = {
- "json": IdentityV3ClientJSON,
- "xml": IdentityV3ClientXML,
-}
-
-TOKEN_CLIENT = {
- "json": TokenClientJSON,
- "xml": TokenClientXML,
-}
-
-SECURITY_GROUPS_CLIENT = {
- "json": SecurityGroupsClientJSON,
- "xml": SecurityGroupsClientXML,
-}
-
-INTERFACES_CLIENT = {
- "json": InterfacesClientJSON,
- "xml": InterfacesClientXML,
-}
-
-ENDPOINT_CLIENT = {
- "json": EndPointClientJSON,
- "xml": EndPointClientXML,
-}
-
-FIXED_IPS_CLIENT = {
- "json": FixedIPsClientJSON,
- "xml": FixedIPsClientXML
-}
-
-AVAILABILITY_ZONE_CLIENT = {
- "json": AvailabilityZoneClientJSON,
- "xml": AvailabilityZoneClientXML,
-}
-
-SERVICE_CLIENT = {
- "json": ServiceClientJSON,
- "xml": ServiceClientXML,
-}
-
-AGGREGATES_CLIENT = {
- "json": AggregatesClientJSON,
- "xml": AggregatesClientXML,
-}
-
-SERVICES_CLIENT = {
- "json": ServicesClientJSON,
- "xml": ServicesClientXML,
-}
-
-TENANT_USAGES_CLIENT = {
- "json": TenantUsagesClientJSON,
- "xml": TenantUsagesClientXML,
-}
-
-POLICY_CLIENT = {
- "json": PolicyClientJSON,
- "xml": PolicyClientXML,
-}
-
-HYPERVISOR_CLIENT = {
- "json": HypervisorClientJSON,
- "xml": HypervisorClientXML,
-}
-
-V3_TOKEN_CLIENT = {
- "json": V3TokenClientJSON,
- "xml": V3TokenClientXML,
-}
-
-CREDENTIALS_CLIENT = {
- "json": CredentialsClientJSON,
- "xml": CredentialsClientXML,
-}
-
class Manager(object):
@@ -308,55 +163,88 @@
else:
client_args_v3_auth = None
- try:
- self.servers_client = SERVERS_CLIENTS[interface](*client_args)
- self.network_client = NETWORKS_CLIENTS[interface](*client_args)
- self.limits_client = LIMITS_CLIENTS[interface](*client_args)
- if self.config.service_available.glance:
- self.images_client = IMAGES_CLIENTS[interface](*client_args)
- self.keypairs_client = KEYPAIRS_CLIENTS[interface](*client_args)
- self.quotas_client = QUOTAS_CLIENTS[interface](*client_args)
- self.flavors_client = FLAVORS_CLIENTS[interface](*client_args)
- ext_cli = EXTENSIONS_CLIENTS[interface](*client_args)
- self.extensions_client = ext_cli
- vol_ext_cli = VOLUMES_EXTENSIONS_CLIENTS[interface](*client_args)
- self.volumes_extensions_client = vol_ext_cli
- self.floating_ips_client = FLOAT_CLIENTS[interface](*client_args)
- self.snapshots_client = SNAPSHOTS_CLIENTS[interface](*client_args)
- self.volumes_client = VOLUMES_CLIENTS[interface](*client_args)
- self.volume_types_client = \
- VOLUME_TYPES_CLIENTS[interface](*client_args)
- self.identity_client = IDENTITY_CLIENT[interface](*client_args)
- self.identity_v3_client = \
- IDENTITY_V3_CLIENT[interface](*client_args)
- self.token_client = TOKEN_CLIENT[interface](self.config)
- self.security_groups_client = \
- SECURITY_GROUPS_CLIENT[interface](*client_args)
- self.interfaces_client = INTERFACES_CLIENT[interface](*client_args)
- self.endpoints_client = ENDPOINT_CLIENT[interface](*client_args)
- self.fixed_ips_client = FIXED_IPS_CLIENT[interface](*client_args)
- self.availability_zone_client = \
- AVAILABILITY_ZONE_CLIENT[interface](*client_args)
- self.service_client = SERVICE_CLIENT[interface](*client_args)
- self.aggregates_client = AGGREGATES_CLIENT[interface](*client_args)
- self.services_client = SERVICES_CLIENT[interface](*client_args)
- self.tenant_usages_client = \
- TENANT_USAGES_CLIENT[interface](*client_args)
- self.policy_client = POLICY_CLIENT[interface](*client_args)
- self.hypervisor_client = HYPERVISOR_CLIENT[interface](*client_args)
- self.token_v3_client = V3_TOKEN_CLIENT[interface](*client_args)
- self.credentials_client = \
- CREDENTIALS_CLIENT[interface](*client_args)
+ self.servers_client_v3_auth = None
+
+ if interface == 'xml':
+ self.servers_client = ServersClientXML(*client_args)
+ self.limits_client = LimitsClientXML(*client_args)
+ self.images_client = ImagesClientXML(*client_args)
+ self.keypairs_client = KeyPairsClientXML(*client_args)
+ self.quotas_client = QuotasClientXML(*client_args)
+ self.flavors_client = FlavorsClientXML(*client_args)
+ self.extensions_client = ExtensionsClientXML(*client_args)
+ self.volumes_extensions_client = VolumesExtensionsClientXML(
+ *client_args)
+ self.floating_ips_client = FloatingIPsClientXML(*client_args)
+ self.snapshots_client = SnapshotsClientXML(*client_args)
+ self.volumes_client = VolumesClientXML(*client_args)
+ self.volume_types_client = VolumeTypesClientXML(*client_args)
+ self.identity_client = IdentityClientXML(*client_args)
+ self.identity_v3_client = IdentityV3ClientXML(*client_args)
+ self.token_client = TokenClientXML(self.config)
+ self.security_groups_client = SecurityGroupsClientXML(
+ *client_args)
+ self.interfaces_client = InterfacesClientXML(*client_args)
+ self.endpoints_client = EndPointClientXML(*client_args)
+ self.fixed_ips_client = FixedIPsClientXML(*client_args)
+ self.availability_zone_client = AvailabilityZoneClientXML(
+ *client_args)
+ self.service_client = ServiceClientXML(*client_args)
+ self.aggregates_client = AggregatesClientXML(*client_args)
+ self.services_client = ServicesClientXML(*client_args)
+ self.tenant_usages_client = TenantUsagesClientXML(*client_args)
+ self.policy_client = PolicyClientXML(*client_args)
+ self.hypervisor_client = HypervisorClientXML(*client_args)
+ self.token_v3_client = V3TokenClientXML(*client_args)
+ self.network_client = NetworkClientXML(*client_args)
+ self.credentials_client = CredentialsClientXML(*client_args)
if client_args_v3_auth:
- self.servers_client_v3_auth = SERVERS_CLIENTS[interface](
+ self.servers_client_v3_auth = ServersClientXML(
*client_args_v3_auth)
- else:
- self.servers_client_v3_auth = None
- except KeyError:
+ elif interface == 'json':
+ self.servers_client = ServersClientJSON(*client_args)
+ self.limits_client = LimitsClientJSON(*client_args)
+ self.images_client = ImagesClientJSON(*client_args)
+ self.keypairs_client = KeyPairsClientJSON(*client_args)
+ self.quotas_client = QuotasClientJSON(*client_args)
+ self.flavors_client = FlavorsClientJSON(*client_args)
+ self.extensions_client = ExtensionsClientJSON(*client_args)
+ self.volumes_extensions_client = VolumesExtensionsClientJSON(
+ *client_args)
+ self.floating_ips_client = FloatingIPsClientJSON(*client_args)
+ self.snapshots_client = SnapshotsClientJSON(*client_args)
+ self.volumes_client = VolumesClientJSON(*client_args)
+ self.volume_types_client = VolumeTypesClientJSON(*client_args)
+ self.identity_client = IdentityClientJSON(*client_args)
+ self.identity_v3_client = IdentityV3ClientJSON(*client_args)
+ self.token_client = TokenClientJSON(self.config)
+ self.security_groups_client = SecurityGroupsClientJSON(
+ *client_args)
+ self.interfaces_client = InterfacesClientJSON(*client_args)
+ self.endpoints_client = EndPointClientJSON(*client_args)
+ self.fixed_ips_client = FixedIPsClientJSON(*client_args)
+ self.availability_zone_client = AvailabilityZoneClientJSON(
+ *client_args)
+ self.service_client = ServiceClientJSON(*client_args)
+ self.aggregates_client = AggregatesClientJSON(*client_args)
+ self.services_client = ServicesClientJSON(*client_args)
+ self.tenant_usages_client = TenantUsagesClientJSON(*client_args)
+ self.policy_client = PolicyClientJSON(*client_args)
+ self.hypervisor_client = HypervisorClientJSON(*client_args)
+ self.token_v3_client = V3TokenClientJSON(*client_args)
+ self.network_client = NetworkClientJSON(*client_args)
+ self.credentials_client = CredentialsClientJSON(*client_args)
+
+ if client_args_v3_auth:
+ self.servers_client_v3_auth = ServersClientJSON(
+ *client_args_v3_auth)
+ else:
msg = "Unsupported interface type `%s'" % interface
raise exceptions.InvalidConfiguration(msg)
+
+ # common clients
self.hosts_client = HostsClientJSON(*client_args)
self.account_client = AccountClient(*client_args)
if self.config.service_available.glance:
diff --git a/tempest/config.py b/tempest/config.py
index acca7e0..18eac02 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -410,7 +410,7 @@
default=None,
help="Name of existing keypair to launch servers with."),
cfg.IntOpt('max_template_size',
- default=32768,
+ default=524288,
help="Value must match heat configuration of the same name."),
]
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 8d05fd8..67406b0 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -81,6 +81,10 @@
message = "Server %(server_id)s failed to build and is in ERROR status"
+class ImageKilledException(TempestException):
+ message = "Image %(image_id)s 'killed' while waiting for %(status)s"
+
+
class AddImageException(TempestException):
message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 4f49d65..6812d64 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -18,7 +18,6 @@
import time
from cinderclient import exceptions as cinder_exceptions
-import testtools
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
@@ -142,7 +141,7 @@
got_timestamp = ssh_client.exec_command('sudo cat /mnt/timestamp')
self.assertEqual(self.timestamp, got_timestamp)
- @testtools.skip("Skipped until the Bug #1205344 is resolved.")
+ @tempest.test.skip_because(bug="1205344")
@tempest.test.services('compute', 'network', 'volume', 'image')
def test_stamp_pattern(self):
# prepare for booting a instance
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 75ce9ff..b7c6bf1 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -97,3 +97,14 @@
post_body, self.headers)
body = json.loads(body)
return resp, body['aggregate']
+
+ def set_metadata(self, aggregate_id, meta):
+ """Replaces the aggregate's existing metadata with new metadata."""
+ post_body = {
+ 'metadata': meta,
+ }
+ post_body = json.dumps({'set_metadata': post_body})
+ resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
+ post_body, self.headers)
+ body = json.loads(body)
+ return resp, body['aggregate']
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index c3b568d..dc05e3e 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -102,6 +102,13 @@
body = json.loads(body)
return resp, body['extra_specs']
+ def get_flavor_extra_spec_with_key(self, flavor_id, key):
+ """Gets a specified key value for the mentioned flavor."""
+ resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
+ key))
+ body = json.loads(body)
+ return resp, body[key]
+
def unset_flavor_extra_spec(self, flavor_id, key):
"""Unsets extra Specs from the mentioned flavor."""
return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 30a3f7b..f51879d 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -44,3 +44,39 @@
resp, body = self.get("os-hosts/%s" % str(hostname))
body = json.loads(body)
return resp, body['host']
+
+ def update_host(self, hostname, **kwargs):
+ """Update a host."""
+
+ request_body = {
+ 'status': None,
+ 'maintenance_mode': None,
+ }
+ request_body.update(**kwargs)
+ request_body = json.dumps(request_body)
+
+ resp, body = self.put("os-hosts/%s" % str(hostname), request_body,
+ self.headers)
+ body = json.loads(body)
+ return resp, body
+
+ def startup_host(self, hostname):
+ """Startup a host."""
+
+ resp, body = self.get("os-hosts/%s/startup" % str(hostname))
+ body = json.loads(body)
+ return resp, body['host']
+
+ def shutdown_host(self, hostname):
+ """Shutdown a host."""
+
+ resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
+ body = json.loads(body)
+ return resp, body['host']
+
+ def reboot_host(self, hostname):
+ """reboot a host."""
+
+ resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
+ body = json.loads(body)
+ return resp, body['host']
diff --git a/tempest/services/compute/xml/aggregates_client.py b/tempest/services/compute/xml/aggregates_client.py
index 8ef0af6..5faaff5 100644
--- a/tempest/services/compute/xml/aggregates_client.py
+++ b/tempest/services/compute/xml/aggregates_client.py
@@ -21,6 +21,7 @@
from tempest import exceptions
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import Text
from tempest.services.compute.xml.common import xml_to_json
@@ -112,3 +113,18 @@
self.headers)
aggregate = self._format_aggregate(etree.fromstring(body))
return resp, aggregate
+
+ def set_metadata(self, aggregate_id, meta):
+ """Replaces the aggregate's existing metadata with new metadata."""
+ post_body = Element("set_metadata")
+ metadata = Element("metadata")
+ post_body.append(metadata)
+ for k, v in meta.items():
+ meta = Element(k)
+ meta.append(Text(v))
+ metadata.append(meta)
+ resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
+ str(Document(post_body)),
+ self.headers)
+ aggregate = self._format_aggregate(etree.fromstring(body))
+ return resp, aggregate
diff --git a/tempest/services/compute/xml/common.py b/tempest/services/compute/xml/common.py
index 84b56c2..ad79ed6 100644
--- a/tempest/services/compute/xml/common.py
+++ b/tempest/services/compute/xml/common.py
@@ -36,7 +36,9 @@
self._elements.append(element)
def __str__(self):
- args = " ".join(['%s="%s"' % (k, v) for k, v in self._attrs.items()])
+ args = " ".join(['%s="%s"' %
+ (k, v if v is not None else "")
+ for k, v in self._attrs.items()])
string = '<%s %s' % (self.element_name, args)
if not self._elements:
string += '/>'
@@ -78,7 +80,9 @@
Element.__init__(self, '?xml', *args, **kwargs)
def __str__(self):
- args = " ".join(['%s="%s"' % (k, v) for k, v in self._attrs.items()])
+ args = " ".join(['%s="%s"' %
+ (k, v if v is not None else "")
+ for k, v in self._attrs.items()])
string = '<?xml %s?>\n' % args
for element in self._elements:
string += str(element)
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index c5886ee..c7ed044 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -148,6 +148,13 @@
body = xml_to_json(etree.fromstring(body))
return resp, body
+ def get_flavor_extra_spec_with_key(self, flavor_id, key):
+ """Gets a specified key detail for the mentioned flavor."""
+ resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
+ key), self.headers)
+ body = xml_to_json(etree.fromstring(body))
+ return resp, body
+
def unset_flavor_extra_spec(self, flavor_id, key):
"""Unsets an extra spec based on the mentioned flavor and key."""
return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
diff --git a/tempest/services/compute/xml/hosts_client.py b/tempest/services/compute/xml/hosts_client.py
index 9743143..f7d7b0a 100644
--- a/tempest/services/compute/xml/hosts_client.py
+++ b/tempest/services/compute/xml/hosts_client.py
@@ -18,6 +18,8 @@
from lxml import etree
from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
from tempest.services.compute.xml.common import xml_to_json
@@ -47,3 +49,46 @@
node = etree.fromstring(body)
body = [xml_to_json(x) for x in node.getchildren()]
return resp, body
+
+ def update_host(self, hostname, status=None, maintenance_mode=None,
+ **kwargs):
+ """Update a host."""
+
+ request_body = Element(status=status,
+ maintenance_mode=maintenance_mode)
+ if kwargs:
+ for k, v in kwargs.iteritem():
+ request_body.add_attr(k, v)
+ resp, body = self.put("os-hosts/%s" % str(hostname),
+ str(Document(request_body)),
+ self.headers)
+ node = etree.fromstring(body)
+ body = [xml_to_json(x) for x in node.getchildren()]
+ return resp, body
+
+ def startup_host(self, hostname):
+ """Startup a host."""
+
+ resp, body = self.get("os-hosts/%s/startup" % str(hostname),
+ self.headers)
+ node = etree.fromstring(body)
+ body = [xml_to_json(x) for x in node.getchildren()]
+ return resp, body
+
+ def shutdown_host(self, hostname):
+ """Shutdown a host."""
+
+ resp, body = self.get("os-hosts/%s/shutdown" % str(hostname),
+ self.headers)
+ node = etree.fromstring(body)
+ body = [xml_to_json(x) for x in node.getchildren()]
+ return resp, body
+
+ def reboot_host(self, hostname):
+ """Reboot a host."""
+
+ resp, body = self.get("os-hosts/%s/reboot" % str(hostname),
+ self.headers)
+ node = etree.fromstring(body)
+ body = [xml_to_json(x) for x in node.getchildren()]
+ return resp, body
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index 1921d78..41b9e81 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -265,9 +265,12 @@
LOG.info('Value transition from "%s" to "%s"'
'in %d second(s).', old_value,
value, dtime)
- if (value == status):
+ if value == status:
return value
+ if value == 'killed':
+ raise exceptions.ImageKilledException(image_id=image_id,
+ status=value)
if dtime > self.build_timeout:
message = ('Time Limit Exceeded! (%ds)'
'while waiting for %s, '
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index f0531ec..62b8ff6 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -124,3 +124,13 @@
url = 'v2/images/%s/file' % image_id
resp, body = self.get(url)
return resp, body
+
+ def add_image_tag(self, image_id, tag):
+ url = 'v2/images/%s/tags/%s' % (image_id, tag)
+ resp, body = self.put(url, body=None, headers=self.headers)
+ return resp, body
+
+ def delete_image_tag(self, image_id, tag):
+ url = 'v2/images/%s/tags/%s' % (image_id, tag)
+ resp, _ = self.delete(url)
+ return resp
diff --git a/tempest/test.py b/tempest/test.py
index 8ce7af8..edba709 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -26,6 +26,7 @@
import testtools
from tempest import clients
+from tempest.common import isolated_creds
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -216,7 +217,36 @@
os.environ.get('OS_LOG_CAPTURE') != '0'):
log_format = '%(asctime)-15s %(message)s'
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
- format=log_format))
+ format=log_format,
+ level=None))
+
+ @classmethod
+ def get_client_manager(cls):
+ """
+ Returns an Openstack client manager
+ """
+ cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+
+ force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
+ if (cls.config.compute.allow_tenant_isolation or
+ force_tenant_isolation):
+ creds = cls.isolated_creds.get_primary_creds()
+ username, tenant_name, password = creds
+ os = clients.Manager(username=username,
+ password=password,
+ tenant_name=tenant_name,
+ interface=cls._interface)
+ else:
+ os = clients.Manager(interface=cls._interface)
+ return os
+
+ @classmethod
+ def clear_isolated_creds(cls):
+ """
+ Clears isolated creds if set
+ """
+ if getattr(cls, 'isolated_creds'):
+ cls.isolated_creds.clear_isolated_creds()
@classmethod
def _get_identity_admin_client(cls):
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index ffaf134..0ae3323 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -46,14 +46,24 @@
test methods that have been decorated to skip because of
a particular bug.
"""
- results = []
+ results = {}
debug("Searching in %s", start)
for root, _dirs, files in os.walk(start):
for name in files:
if name.startswith('test_') and name.endswith('py'):
path = os.path.join(root, name)
debug("Searching in %s", path)
- results += find_skips_in_file(path)
+ temp_result = find_skips_in_file(path)
+ for method_name, bug_no in temp_result:
+ if results.get(bug_no):
+ result_dict = results.get(bug_no)
+ if result_dict.get(name):
+ result_dict[name].append(method_name)
+ else:
+ result_dict[name] = [method_name]
+ results[bug_no] = result_dict
+ else:
+ results[bug_no] = {name: [method_name]}
return results
@@ -83,11 +93,19 @@
return results
+def get_results(result_dict):
+ results = []
+ for bug_no in result_dict.keys():
+ for method in result_dict[bug_no]:
+ results.append((method, bug_no))
+ return results
+
+
if __name__ == '__main__':
logging.basicConfig(format='%(levelname)s: %(message)s',
level=logging.INFO)
results = find_skips()
- unique_bugs = sorted(set([bug for (method, bug) in results]))
+ unique_bugs = sorted(set([bug for (method, bug) in get_results(results)]))
unskips = []
duplicates = []
info("Total bug skips found: %d", len(results))
@@ -122,4 +140,7 @@
print("should be removed from the test cases:")
print()
for bug in unskips:
- print(" %7s" % bug)
+ message = " %7s in " % bug
+ locations = ["%s" % x for x in results[bug].keys()]
+ message += " and ".join(locations)
+ print(message)