Merge "Mildly wound the interlopers"
diff --git a/HACKING.rst b/HACKING.rst
index 3fa1ff5..c0df0fb 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -11,6 +11,7 @@
- [T102] Cannot import OpenStack python clients in tempest/api tests
- [T104] Scenario tests require a services decorator
- [T105] Unit tests cannot use setUpClass
+- [T106] vim configuration should not be kept in source files.
Test Data/Configuration
-----------------------
@@ -107,16 +108,36 @@
Negative Tests
--------------
-When adding negative tests to tempest there are 2 requirements. First the tests
-must be marked with a negative attribute. For example::
+Newly added negative tests should use the negative test framework. First step
+is to create an interface description in a json file under `etc/schemas`.
+These descriptions consists of two important sections for the test
+(one of those is mandatory):
- @attr(type=negative)
- def test_resource_no_uuid(self):
- ...
+ - A resource (part of the URL of the request): Resources needed for a test
+ must be created in `setUpClass` and registered with `set_resource` e.g.:
+ `cls.set_resource("server", server['id'])`
-The second requirement is that all negative tests must be added to a negative
-test file. If such a file doesn't exist for the particular resource being
-tested a new test file should be added.
+ - A json schema: defines properties for a request.
+
+After that a test class must be added to automatically generate test scenarios
+out of the given interface description:
+
+ class SampeTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
+ _interface = 'json'
+ _service = 'compute'
+ _schema_file = 'compute/servers/get_console_output.json'
+ scenarios = test.NegativeAutoTest.generate_scenario(_schema_file)
+
+Negative tests must be marked with a negative attribute::
+
+ @test.attr(type=['negative', 'gate'])
+ def test_get_console_output(self):
+ self.execute(self._schema_file)
+
+All negative tests should be added into a separate negative test file.
+If such a file doesn't exist for the particular resource being tested a new
+test file should be added. Old XML based negative tests can be kept but should
+be renamed to `_xml.py`.
Test skips because of Known Bugs
--------------------------------
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 025d0f3..0f18f5e 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -261,6 +261,10 @@
# value)
#region=
+# The endpoint type to use for the compute service. (string
+# value)
+#endpoint_type=publicURL
+
# Catalog type of the Compute v3 service. (string value)
#catalog_v3_type=computev3
@@ -316,6 +320,10 @@
# If false, skip disk config tests (boolean value)
#disk_config=true
+# A list of enabled compute extensions with a special entry
+# all which indicates every extension is enabled (list value)
+#api_extensions=all
+
# A list of enabled v3 extensions with a special entry all
# which indicates every extension is enabled (list value)
#api_v3_extensions=all
@@ -407,6 +415,10 @@
# one is used. (string value)
#region=RegionOne
+# The endpoint type to use for the identity service. (string
+# value)
+#endpoint_type=publicURL
+
# Username to use for Nova API requests. (string value)
#username=demo
@@ -475,6 +487,10 @@
# value)
#region=
+# The endpoint type to use for the image service. (string
+# value)
+#endpoint_type=publicURL
+
# http accessible image (string value)
#http_image=http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
@@ -530,6 +546,10 @@
# value)
#region=
+# The endpoint type to use for the network service. (string
+# value)
+#endpoint_type=publicURL
+
# The cidr block to allocate tenant ipv4 subnets from (string
# value)
#tenant_network_cidr=10.100.0.0/16
@@ -537,6 +557,9 @@
# The mask bits for tenant ipv4 subnets (integer value)
#tenant_network_mask_bits=28
+# Allow the execution of IPv6 tests (boolean value)
+#ipv6_enabled=true
+
# The cidr block to allocate tenant ipv6 subnets from (string
# value)
#tenant_network_v6_cidr=2003::/64
@@ -563,16 +586,8 @@
# Options defined in tempest.config
#
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
-#api_extensions=all
-
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
-#api_extensions=all
-
-# A list of enabled extensions with a special entry all which
-# indicates every extension is enabled (list value)
+# A list of enabled network extensions with a special entry
+# all which indicates every extension is enabled (list value)
#api_extensions=all
@@ -591,6 +606,10 @@
# (string value)
#region=
+# The endpoint type to use for the object-store service.
+# (string value)
+#endpoint_type=publicURL
+
# Number of seconds to time on waiting for a container to
# container synchronization complete. (integer value)
#container_sync_timeout=120
@@ -631,6 +650,10 @@
# value)
#region=
+# The endpoint type to use for the orchestration service.
+# (string value)
+#endpoint_type=publicURL
+
# Time in seconds between build status checks. (integer value)
#build_interval=1
@@ -664,6 +687,9 @@
# Directory containing image files (string value)
#img_dir=/opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+# QCOW2 image file name (string value)
+#qcow2_img_file=cirros-0.3.1-x86_64-disk.img
+
# AMI image file name (string value)
#ami_img_file=cirros-0.3.1-x86_64-blank.img
@@ -770,6 +796,11 @@
# value)
#leave_dirty_stack=false
+# Allows a full cleaning process after a stress test. Caution
+# : this cleanup will remove every objects of every tenant.
+# (boolean value)
+#full_clean_stack=false
+
[telemetry]
@@ -804,6 +835,10 @@
# value)
#region=
+# The endpoint type to use for the volume service. (string
+# value)
+#endpoint_type=publicURL
+
# Name of the backend1 (must be declared in cinder.conf)
# (string value)
#backend1_name=BACKEND_1
@@ -835,6 +870,13 @@
# (boolean value)
#multi_backend=false
+# Runs Cinder volumes backup test (boolean value)
+#backup=true
+
+# A list of enabled volume extensions with a special entry all
+# which indicates every extension is enabled (list value)
+#api_extensions=all
+
# Is the v1 volume API enabled (boolean value)
#api_v1=true
diff --git a/requirements.txt b/requirements.txt
index feead92..a08a437 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,6 +13,7 @@
python-neutronclient>=2.3.3,<3
python-cinderclient>=1.0.6
python-heatclient>=0.2.3
+python-savannaclient>=0.4.1
python-swiftclient>=1.5
testresources>=0.2.4
keyring>=1.6.1,<2.0,>=2.1
diff --git a/run_tests.sh b/run_tests.sh
index 34b821b..a12bf46 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -84,6 +84,11 @@
return $?
fi
+ if [ $coverage -eq 1 ]; then
+ ${wrapper} python setup.py test --coverage
+ return $?
+ fi
+
if [ $serial -eq 1 ]; then
${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
else
@@ -98,6 +103,8 @@
echo "Running flake8 without virtual env may miss OpenStack HACKING detection" >&2
fi
${wrapper} flake8
+ export MODULEPATH=tempest.common.generate_sample_tempest
+ ${wrapper} tools/config/check_uptodate.sh
}
if [ $never_venv -eq 0 ]
@@ -135,10 +142,6 @@
exit
fi
-if [ $coverage -eq 1 ]; then
- $testrargs = "--coverage $testrargs"
-fi
-
run_tests
retval=$?
diff --git a/setup.cfg b/setup.cfg
index 79f538f..a701572 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -4,8 +4,8 @@
summary = OpenStack Integration Testing
description-file =
README.rst
-author = OpenStack QA
-author-email = openstack-qa@lists.openstack.org
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Intended Audience :: Information Technology
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 18e4452..283a45a 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,7 +29,6 @@
def setUpClass(cls):
super(AZAdminTestJSON, cls).setUpClass()
cls.client = cls.os_adm.availability_zone_client
- cls.non_adm_client = cls.availability_zone_client
@attr(type='gate')
def test_get_availability_zone_list(self):
@@ -46,14 +45,6 @@
self.assertEqual(200, resp.status)
self.assertTrue(len(availability_zone) > 0)
- @attr(type='gate')
- def test_get_availability_zone_list_with_non_admin_user(self):
- # List of availability zone with non-administrator user
- resp, availability_zone = \
- self.non_adm_client.get_availability_zone_list()
- self.assertEqual(200, resp.status)
- self.assertTrue(len(availability_zone) > 0)
-
class AZAdminTestXML(AZAdminTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index d4a32e6..81b0328 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -25,7 +25,6 @@
@classmethod
def setUpClass(cls):
super(QuotasAdminTestJSON, cls).setUpClass()
- cls.client = cls.os.quotas_client
cls.adm_client = cls.os_adm.quotas_client
# NOTE(afazekas): these test cases should always create and use a new
@@ -45,7 +44,7 @@
def test_get_default_quotas(self):
# Admin can get the default resource quota set for a tenant
expected_quota_set = self.default_quota_set | set(['id'])
- resp, quota_set = self.client.get_default_quota_set(
+ resp, quota_set = self.adm_client.get_default_quota_set(
self.demo_tenant_id)
self.assertEqual(200, resp.status)
self.assertEqual(sorted(expected_quota_set),
@@ -55,7 +54,7 @@
@test.attr(type='gate')
def test_update_all_quota_resources_for_tenant(self):
# Admin can update all the resource quota limits for a tenant
- resp, default_quota_set = self.client.get_default_quota_set(
+ resp, default_quota_set = self.adm_client.get_default_quota_set(
self.demo_tenant_id)
new_quota_set = {'injected_file_content_bytes': 20480,
'metadata_items': 256, 'injected_files': 10,
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index d3696a1..4c4acd4 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -49,7 +49,7 @@
@test.attr(type=['negative', 'gate'])
def test_create_server_when_cpu_quota_is_full(self):
# Disallow server creation when tenant's vcpu quota is full
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
default_vcpu_quota = quota_set['cores']
vcpu_quota = 0 # Set the quota to zero to conserve resources
@@ -64,7 +64,7 @@
@test.attr(type=['negative', 'gate'])
def test_create_server_when_memory_quota_is_full(self):
# Disallow server creation when tenant's memory quota is full
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
default_mem_quota = quota_set['ram']
mem_quota = 0 # Set the quota to zero to conserve resources
@@ -79,7 +79,7 @@
@test.attr(type=['negative', 'gate'])
def test_create_server_when_instances_quota_is_full(self):
# Once instances quota limit is reached, disallow server creation
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
default_instances_quota = quota_set['instances']
instances_quota = 0 # Set quota to zero to disallow server creation
@@ -96,7 +96,7 @@
def test_security_groups_exceed_limit(self):
# Negative test: Creation Security Groups over limit should FAIL
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
default_sg_quota = quota_set['security_groups']
sg_quota = 0 # Set the quota to zero to conserve resources
@@ -121,7 +121,7 @@
# Negative test: Creation of Security Group Rules should FAIL
# when we reach limit maxSecurityGroupRules
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
default_sg_rules_quota = quota_set['security_group_rules']
sg_rules_quota = 0 # Set the quota to zero to conserve resources
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 1078847..8a5f1a5 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -118,26 +118,6 @@
map(lambda x: x['id'], nonexistent_servers))
@test.attr(type='gate')
- def test_admin_delete_servers_of_others(self):
- # Administrator can delete servers of others
- _, server = self.create_test_server()
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
- self.servers_client.wait_for_server_termination(server['id'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_error_state(self):
- # Delete a server while it's VM state is error
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.reset_state(server['id'], state='error')
- self.assertEqual(202, resp.status)
- # Verify server's state
- resp, server = self.client.get_server(server['id'])
- self.assertEqual(server['status'], 'ERROR')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
def test_reset_state_server(self):
# Reset server's state to 'error'
resp, server = self.client.reset_state(self.s1_id)
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 16dcfcc..ac800fb 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -30,7 +30,6 @@
def setUpClass(cls):
super(ServicesAdminTestJSON, cls).setUpClass()
cls.client = cls.os_adm.services_client
- cls.non_admin_client = cls.services_client
@attr(type='gate')
def test_list_services(self):
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index e6ddf1c..72bb723 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -51,6 +51,7 @@
cls.servers = []
cls.images = []
cls.multi_user = cls.get_multi_user()
+ cls.security_groups = []
@classmethod
def get_multi_user(cls):
@@ -102,9 +103,25 @@
pass
@classmethod
+ def clear_security_groups(cls):
+ for sg in cls.security_groups:
+ try:
+ resp, body =\
+ cls.security_groups_client.delete_security_group(sg['id'])
+ except exceptions.NotFound:
+ # The security group may have already been deleted which is OK.
+ pass
+ except Exception as exc:
+ LOG.info('Exception raised deleting security group %s',
+ sg['id'])
+ LOG.exception(exc)
+ pass
+
+ @classmethod
def tearDownClass(cls):
cls.clear_images()
cls.clear_servers()
+ cls.clear_security_groups()
cls.clear_isolated_creds()
super(BaseComputeTest, cls).tearDownClass()
@@ -146,6 +163,19 @@
return resp, body
+ @classmethod
+ def create_security_group(cls, name=None, description=None):
+ if name is None:
+ name = data_utils.rand_name(cls.__name__ + "-securitygroup")
+ if description is None:
+ description = data_utils.rand_name('description-')
+ resp, body = \
+ cls.security_groups_client.create_security_group(name,
+ description)
+ cls.security_groups.append(body)
+
+ return resp, body
+
def wait_for(self, condition):
"""Repeatedly calls condition() until a timeout."""
start_time = int(time.time())
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 56bd291..ea785b3 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -14,9 +14,9 @@
# under the License.
from tempest.api.compute.floating_ips import base
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class FloatingIPsTestJSON(base.BaseFloatingIPsTest):
@@ -44,7 +44,7 @@
resp, body = cls.client.delete_floating_ip(cls.floating_ip_id)
super(FloatingIPsTestJSON, cls).tearDownClass()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_allocate_floating_ip(self):
# Positive test:Allocation of a new floating IP to a project
# should be successful
@@ -59,7 +59,7 @@
resp, body = self.client.list_floating_ips()
self.assertIn(floating_ip_details, body)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_floating_ip(self):
# Positive test:Deletion of valid floating IP from project
# should be successful
@@ -74,7 +74,7 @@
# Check it was really deleted.
self.client.wait_for_resource_deletion(floating_ip_body['id'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_associate_disassociate_floating_ip(self):
# Positive test:Associate and disassociate the provided floating IP
# to a specific server should be successful
@@ -90,12 +90,12 @@
self.server_id)
self.assertEqual(202, resp.status)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_associate_already_associated_floating_ip(self):
# positive test:Association of an already associated floating IP
# to specific server should change the association of the Floating IP
# Create server so as to use for Multiple association
- new_name = rand_name('floating_server')
+ new_name = data_utils.rand_name('floating_server')
resp, body = self.create_test_server(name=new_name)
self.servers_client.wait_for_server_status(body['id'], 'ACTIVE')
self.new_server_id = body['id']
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 4cc36c9..8964dcf 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -13,11 +13,10 @@
# under the License.
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -36,18 +35,6 @@
cls.image_ids = []
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
def tearDown(self):
"""Terminate test instances created after a test is executed."""
for image_id in self.image_ids:
@@ -62,7 +49,7 @@
self.image_ids.append(image_id)
return resp, body
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_deleted_server(self):
# An image should not be created if the server instance is removed
resp, server = self.create_test_server(wait_until='ACTIVE')
@@ -77,7 +64,7 @@
self.__create_image__,
server['id'], name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_invalid_server(self):
# An image should not be created with invalid server id
# Create a new image with invalid server id
@@ -88,7 +75,7 @@
self.assertRaises(exceptions.NotFound, self.__create_image__,
'!@#$%^&*()', name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_stopped_server(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
self.servers_client.stop(server['id'])
@@ -103,7 +90,7 @@
self.addCleanup(self.client.delete_image, image['id'])
self.assertEqual(snapshot_name, image['name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_saving_image(self):
snapshot_name = data_utils.rand_name('test-snap-')
resp, server = self.create_test_server(wait_until='ACTIVE')
@@ -114,7 +101,7 @@
resp, body = self.client.delete_image(image['id'])
self.assertEqual('204', resp['status'])
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_uuid_35_characters_or_less(self):
# Return an error if Image ID passed is 35 characters or less
snapshot_name = data_utils.rand_name('test-snap-')
@@ -122,7 +109,7 @@
self.assertRaises(exceptions.NotFound, self.client.create_image,
test_uuid, snapshot_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_uuid_37_characters_or_more(self):
# Return an error if Image ID passed is 37 characters or more
snapshot_name = data_utils.rand_name('test-snap-')
@@ -130,13 +117,13 @@
self.assertRaises(exceptions.NotFound, self.client.create_image,
test_uuid, snapshot_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_with_invalid_image_id(self):
# An image should not be deleted with invalid image id
self.assertRaises(exceptions.NotFound, self.client.delete_image,
'!@$%^&*()')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_non_existent_image(self):
# Return an error while trying to delete a non-existent image
@@ -144,24 +131,24 @@
self.assertRaises(exceptions.NotFound, self.client.delete_image,
non_existent_image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_blank_id(self):
# Return an error while trying to delete an image with blank Id
self.assertRaises(exceptions.NotFound, self.client.delete_image, '')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_non_hex_string_id(self):
# Return an error while trying to delete an image with non hex id
image_id = '11a22b9-120q-5555-cc11-00ab112223gj'
self.assertRaises(exceptions.NotFound, self.client.delete_image,
image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_negative_image_id(self):
# Return an error while trying to delete an image with negative id
self.assertRaises(exceptions.NotFound, self.client.delete_image, -1)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_id_is_over_35_character_limit(self):
# Return an error while trying to delete image with id over limit
self.assertRaises(exceptions.NotFound, self.client.delete_image,
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 8d60623..7d5593d 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -16,11 +16,10 @@
import testtools
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -29,13 +28,6 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
- def tearDown(self):
- """Terminate test instances created after a test is executed."""
- for image_id in self.image_ids:
- self.client.delete_image(image_id)
- self.image_ids.remove(image_id)
- super(ImagesOneServerTestJSON, self).tearDown()
-
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
# but if it has an issue, we build a new one
@@ -66,27 +58,13 @@
cls.tearDownClass()
raise
- cls.image_ids = []
-
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
def _get_default_flavor_disk_size(self, flavor_id):
resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
return flavor['disk']
@testtools.skipUnless(CONF.compute_feature_enabled.create_image,
'Environment unable to create images.')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_delete_image(self):
# Create a new image
@@ -117,7 +95,7 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_resource_deletion(image_id)
- @attr(type=['gate'])
+ @test.attr(type=['gate'])
def test_create_image_specify_multibyte_character_image_name(self):
if self.__class__._interface == "xml":
# NOTE(sdague): not entirely accurage, but we'd need a ton of work
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index c96c4a4..82955d8 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -15,13 +15,11 @@
# under the License.
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -73,20 +71,8 @@
cls.image_ids = []
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
- @skip_because(bug="1006725")
- @attr(type=['negative', 'gate'])
+ @test.skip_because(bug="1006725")
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_multibyte_character_image_name(self):
if self.__class__._interface == "xml":
raise self.skipException("Not testable in XML")
@@ -98,7 +84,7 @@
self.client.create_image, self.server_id,
invalid_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_invalid_metadata(self):
# Return an error when creating image with invalid metadata
snapshot_name = data_utils.rand_name('test-snap-')
@@ -106,7 +92,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_image,
self.server_id, snapshot_name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_metadata_over_limits(self):
# Return an error when creating image with meta data over 256 chars
snapshot_name = data_utils.rand_name('test-snap-')
@@ -114,7 +100,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_image,
self.server_id, snapshot_name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_second_image_when_first_image_is_being_saved(self):
# Disallow creating another image when first image is being saved
@@ -132,7 +118,7 @@
self.assertRaises(exceptions.Conflict, self.client.create_image,
self.server_id, alt_snapshot_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_name_over_256_chars(self):
# Return an error if snapshot name over 256 characters is passed
@@ -140,7 +126,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_image,
self.server_id, snapshot_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_that_is_not_yet_active(self):
# Return an error while trying to delete an image what is creating
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 6cbf18d..9cff3a8 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -16,7 +16,7 @@
from tempest.api.compute import base
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -33,7 +33,6 @@
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
cls.client = cls.images_client
- cls.image_ids = []
try:
resp, cls.server1 = cls.create_test_server()
@@ -63,7 +62,7 @@
cls.tearDownClass()
raise
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_status(self):
# The list of images should contain only images with the
# provided status
@@ -74,7 +73,7 @@
self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_name(self):
# List of all images should contain the expected images filtered
# by name
@@ -85,7 +84,7 @@
self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_server_id(self):
# The images should contain images filtered by server id
params = {'server': self.server1['id']}
@@ -97,7 +96,7 @@
self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_server_ref(self):
# The list of servers should be filtered by server ref
server_links = self.server2['links']
@@ -114,7 +113,7 @@
self.assertTrue(any([i for i in images
if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_type(self):
# The list of servers should be filtered by image type
params = {'type': 'snapshot'}
@@ -125,7 +124,7 @@
self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_limit_results(self):
# Verify only the expected number of results are returned
params = {'limit': '1'}
@@ -134,7 +133,7 @@
# ref: Question #224349
self.assertEqual(1, len([x for x in images if 'id' in x]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_filter_by_changes_since(self):
# Verify only updated images are returned in the detailed list
@@ -145,7 +144,7 @@
found = any([i for i in images if i['id'] == self.image3_id])
self.assertTrue(found)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_filter_by_status(self):
# Detailed list of all images should only contain images
# with the provided status
@@ -156,7 +155,7 @@
self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_filter_by_name(self):
# Detailed list of all images should contain the expected
# images filtered by name
@@ -167,7 +166,7 @@
self.assertFalse(any([i for i in images if i['id'] == self.image2_id]))
self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_limit_results(self):
# Verify only the expected number of results (with full details)
# are returned
@@ -175,7 +174,7 @@
resp, images = self.client.list_images_with_detail(params)
self.assertEqual(1, len(images))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_filter_by_server_ref(self):
# Detailed list of servers should be filtered by server ref
server_links = self.server2['links']
@@ -192,7 +191,7 @@
self.assertTrue(any([i for i in images
if i['id'] == self.image3_id]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_filter_by_type(self):
# The detailed list of servers should be filtered by image type
params = {'type': 'snapshot'}
@@ -204,7 +203,7 @@
self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_with_detail_filter_by_changes_since(self):
# Verify an update image is returned
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 375105e..17bb489 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -14,9 +14,8 @@
# under the License.
from tempest.api.compute.security_groups import base
-from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -30,17 +29,13 @@
cls.client = cls.security_groups_client
cls.neutron_available = CONF.service_available.neutron
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_security_group_rules_create(self):
# Positive test: Creation of Security Group rule
# should be successful
# Creating a Security Group to add rules to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
- securitygroup_id = securitygroup['id']
- self.addCleanup(self.client.delete_security_group, securitygroup_id)
+ resp, security_group = self.create_security_group()
+ securitygroup_id = security_group['id']
# Adding rules to the created Security Group
ip_protocol = 'tcp'
from_port = 22
@@ -53,7 +48,7 @@
self.addCleanup(self.client.delete_security_group_rule, rule['id'])
self.assertEqual(200, resp.status)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_security_group_rules_create_with_optional_arguments(self):
# Positive test: Creation of Security Group rule
# with optional arguments
@@ -62,19 +57,11 @@
secgroup1 = None
secgroup2 = None
# Creating a Security Group to add rules to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
- secgroup1 = securitygroup['id']
- self.addCleanup(self.client.delete_security_group, secgroup1)
+ resp, security_group = self.create_security_group()
+ secgroup1 = security_group['id']
# Creating a Security Group so as to assign group_id to the rule
- s_name2 = data_utils.rand_name('securitygroup-')
- s_description2 = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name2, s_description2)
- secgroup2 = securitygroup['id']
- self.addCleanup(self.client.delete_security_group, secgroup2)
+ resp, security_group = self.create_security_group()
+ secgroup2 = security_group['id']
# Adding rules to the created Security Group with optional arguments
parent_group_id = secgroup1
ip_protocol = 'tcp'
@@ -92,18 +79,13 @@
self.addCleanup(self.client.delete_security_group_rule, rule['id'])
self.assertEqual(200, resp.status)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_security_group_rules_list(self):
# Positive test: Created Security Group rules should be
# in the list of all rules
# Creating a Security Group to add rules to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
- securitygroup_id = securitygroup['id']
- # Delete the Security Group at the end of this method
- self.addCleanup(self.client.delete_security_group, securitygroup_id)
+ resp, security_group = self.create_security_group()
+ securitygroup_id = security_group['id']
# Add a first rule to the created Security Group
ip_protocol1 = 'tcp'
@@ -135,29 +117,21 @@
self.assertTrue(any([i for i in rules if i['id'] == rule1_id]))
self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_security_group_rules_delete_when_peer_group_deleted(self):
# Positive test:rule will delete when peer group deleting
# Creating a Security Group to add rules to it
- s1_name = data_utils.rand_name('securitygroup1-')
- s1_description = data_utils.rand_name('description1-')
- resp, sg1 = \
- self.client.create_security_group(s1_name, s1_description)
- self.addCleanup(self.client.delete_security_group, sg1['id'])
- self.assertEqual(200, resp.status)
+ resp, security_group = self.create_security_group()
+ sg1_id = security_group['id']
# Creating other Security Group to access to group1
- s2_name = data_utils.rand_name('securitygroup2-')
- s2_description = data_utils.rand_name('description2-')
- resp, sg2 = \
- self.client.create_security_group(s2_name, s2_description)
- self.assertEqual(200, resp.status)
- sg2_id = sg2['id']
+ resp, security_group = self.create_security_group()
+ sg2_id = security_group['id']
# Adding rules to the Group1
ip_protocol = 'tcp'
from_port = 22
to_port = 22
resp, rule = \
- self.client.create_security_group_rule(sg1['id'],
+ self.client.create_security_group_rule(sg1_id,
ip_protocol,
from_port,
to_port,
@@ -169,7 +143,7 @@
self.assertEqual(202, resp.status)
# Get rules of the Group1
resp, rules = \
- self.client.list_security_group_rules(sg1['id'])
+ self.client.list_security_group_rules(sg1_id)
# The group1 has no rules because group2 has deleted
self.assertEqual(0, len(rules))
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 4831939..680bc2f 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -19,8 +19,7 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -33,9 +32,9 @@
super(SecurityGroupRulesNegativeTestJSON, cls).setUpClass()
cls.client = cls.security_groups_client
- @skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
- @attr(type=['negative', 'smoke'])
+ @test.skip_because(bug="1182384",
+ condition=CONF.service_available.neutron)
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_non_existent_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
@@ -50,7 +49,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_id")
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with Parent group id which is not integer
@@ -63,21 +62,17 @@
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_duplicate(self):
# Negative test: Create Security Group rule duplicate should fail
# Creating a Security Group to add rule to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, sg = self.client.create_security_group(s_name, s_description)
- self.assertEqual(200, resp.status)
+ resp, sg = self.create_security_group()
# Adding rules to the created Security Group
parent_group_id = sg['id']
ip_protocol = 'tcp'
from_port = 22
to_port = 22
- self.addCleanup(self.client.delete_security_group, sg['id'])
resp, rule = \
self.client.create_security_group_rule(parent_group_id,
ip_protocol,
@@ -90,86 +85,70 @@
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_ip_protocol(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid ip_protocol
# Creating a Security Group to add rule to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = self.client.create_security_group(s_name,
- s_description)
+ resp, sg = self.create_security_group()
# Adding rules to the created Security Group
- parent_group_id = securitygroup['id']
+ parent_group_id = sg['id']
ip_protocol = data_utils.rand_name('999')
from_port = 22
to_port = 22
- self.addCleanup(self.client.delete_security_group, securitygroup['id'])
self.assertRaises(exceptions.BadRequest,
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_from_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid from_port
# Creating a Security Group to add rule to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = self.client.create_security_group(s_name,
- s_description)
+ resp, sg = self.create_security_group()
# Adding rules to the created Security Group
- parent_group_id = securitygroup['id']
+ parent_group_id = sg['id']
ip_protocol = 'tcp'
from_port = data_utils.rand_int_id(start=65536)
to_port = 22
- self.addCleanup(self.client.delete_security_group, securitygroup['id'])
self.assertRaises(exceptions.BadRequest,
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_to_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid to_port
# Creating a Security Group to add rule to it
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = self.client.create_security_group(s_name,
- s_description)
+ resp, sg = self.create_security_group()
# Adding rules to the created Security Group
- parent_group_id = securitygroup['id']
+ parent_group_id = sg['id']
ip_protocol = 'tcp'
from_port = 22
to_port = data_utils.rand_int_id(start=65536)
- self.addCleanup(self.client.delete_security_group, securitygroup['id'])
self.assertRaises(exceptions.BadRequest,
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_port_range(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid port range.
# Creating a Security Group to add rule to it.
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = self.client.create_security_group(s_name,
- s_description)
+ resp, sg = self.create_security_group()
# Adding a rule to the created Security Group
- secgroup_id = securitygroup['id']
+ secgroup_id = sg['id']
ip_protocol = 'tcp'
from_port = 22
to_port = 21
- self.addCleanup(self.client.delete_security_group, securitygroup['id'])
self.assertRaises(exceptions.BadRequest,
self.client.create_security_group_rule,
secgroup_id, ip_protocol, from_port, to_port)
- @skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
- @attr(type=['negative', 'smoke'])
+ @test.skip_because(bug="1182384",
+ condition=CONF.service_available.neutron)
+ @test.attr(type=['negative', 'smoke'])
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 2c67581..b376edc 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -27,68 +27,43 @@
super(SecurityGroupsTestJSON, cls).setUpClass()
cls.client = cls.security_groups_client
- def _delete_security_group(self, securitygroup_id):
- resp, _ = self.client.delete_security_group(securitygroup_id)
- self.assertEqual(202, resp.status)
-
@test.attr(type='gate')
def test_security_groups_create_list_delete(self):
# Positive test:Should return the list of Security Groups
# Create 3 Security Groups
- security_group_list = list()
for i in range(3):
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
+ resp, securitygroup = self.create_security_group()
self.assertEqual(200, resp.status)
- self.addCleanup(self._delete_security_group,
- securitygroup['id'])
- security_group_list.append(securitygroup)
# Fetch all Security Groups and verify the list
# has all created Security Groups
resp, fetched_list = self.client.list_security_groups()
self.assertEqual(200, resp.status)
# Now check if all the created Security Groups are in fetched list
missing_sgs = \
- [sg for sg in security_group_list if sg not in fetched_list]
+ [sg for sg in self.security_groups if sg not in fetched_list]
self.assertFalse(missing_sgs,
"Failed to find Security Group %s in fetched "
"list" % ', '.join(m_group['name']
for m_group in missing_sgs))
-
- # TODO(afazekas): scheduled for delete,
- # test_security_group_create_get_delete covers it
- @test.attr(type='gate')
- def test_security_group_create_delete(self):
- # Security Group should be created, verified and deleted
- s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
- self.assertIn('id', securitygroup)
- securitygroup_id = securitygroup['id']
- self.addCleanup(self._delete_security_group,
- securitygroup_id)
- self.assertEqual(200, resp.status)
- self.assertFalse(securitygroup_id is None)
- self.assertIn('name', securitygroup)
- securitygroup_name = securitygroup['name']
- self.assertEqual(securitygroup_name, s_name,
- "The created Security Group name is "
- "not equal to the requested name")
+ # Delete all security groups
+ for sg in self.security_groups:
+ resp, _ = self.client.delete_security_group(sg['id'])
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_resource_deletion(sg['id'])
+ # Now check if all the created Security Groups are deleted
+ resp, fetched_list = self.client.list_security_groups()
+ deleted_sgs = \
+ [sg for sg in self.security_groups if sg in fetched_list]
+ self.assertFalse(deleted_sgs,
+ "Failed to delete Security Group %s "
+ "list" % ', '.join(m_group['name']
+ for m_group in deleted_sgs))
@test.attr(type='gate')
def test_security_group_create_get_delete(self):
# Security Group should be created, fetched and deleted
s_name = data_utils.rand_name('securitygroup-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
- self.addCleanup(self._delete_security_group,
- securitygroup['id'])
-
- self.assertEqual(200, resp.status)
+ resp, securitygroup = self.create_security_group(name=s_name)
self.assertIn('name', securitygroup)
securitygroup_name = securitygroup['name']
self.assertEqual(securitygroup_name, s_name,
@@ -108,15 +83,8 @@
# and not deleted if the server is active.
# Create a couple security groups that we will use
# for the server resource this test creates
- sg_name = data_utils.rand_name('sg')
- sg_desc = data_utils.rand_name('sg-desc')
- resp, sg = self.client.create_security_group(sg_name, sg_desc)
- sg_id = sg['id']
-
- sg2_name = data_utils.rand_name('sg')
- sg2_desc = data_utils.rand_name('sg-desc')
- resp, sg2 = self.client.create_security_group(sg2_name, sg2_desc)
- sg2_id = sg2['id']
+ resp, sg = self.create_security_group()
+ resp, sg2 = self.create_security_group()
# Create server and add the security group created
# above to the server we just created
@@ -125,50 +93,44 @@
server_id = server['id']
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
resp, body = self.servers_client.add_security_group(server_id,
- sg_name)
+ sg['name'])
# Check that we are not able to delete the security
# group since it is in use by an active server
self.assertRaises(exceptions.BadRequest,
self.client.delete_security_group,
- sg_id)
+ sg['id'])
# Reboot and add the other security group
resp, body = self.servers_client.reboot(server_id, 'HARD')
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
resp, body = self.servers_client.add_security_group(server_id,
- sg2_name)
+ sg2['name'])
# Check that we are not able to delete the other security
# group since it is in use by an active server
self.assertRaises(exceptions.BadRequest,
self.client.delete_security_group,
- sg2_id)
+ sg2['id'])
# Shutdown the server and then verify we can destroy the
# security groups, since no active server instance is using them
self.servers_client.delete_server(server_id)
self.servers_client.wait_for_server_termination(server_id)
- self.client.delete_security_group(sg_id)
+ self.client.delete_security_group(sg['id'])
self.assertEqual(202, resp.status)
-
- self.client.delete_security_group(sg2_id)
+ self.client.delete_security_group(sg2['id'])
self.assertEqual(202, resp.status)
@test.attr(type='gate')
def test_update_security_groups(self):
# Update security group name and description
# Create a security group
- s_name = data_utils.rand_name('sg-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
+ resp, securitygroup = self.create_security_group()
self.assertEqual(200, resp.status)
self.assertIn('id', securitygroup)
securitygroup_id = securitygroup['id']
- self.addCleanup(self._delete_security_group,
- securitygroup_id)
# Update the name and description
s_new_name = data_utils.rand_name('sg-hth-')
s_new_des = data_utils.rand_name('description-hth-')
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index ce1eada..edf38e9 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -33,10 +33,6 @@
cls.client = cls.security_groups_client
cls.neutron_available = CONF.service_available.neutron
- def _delete_security_group(self, securitygroup_id):
- resp, _ = self.client.delete_security_group(securitygroup_id)
- self.assertEqual(202, resp.status)
-
def _generate_a_non_existent_security_group_id(self):
security_group_id = []
resp, body = self.client.list_security_groups()
@@ -107,11 +103,8 @@
s_name = data_utils.rand_name('securitygroup-')
s_description = data_utils.rand_name('description-')
resp, security_group =\
- self.client.create_security_group(s_name, s_description)
+ self.create_security_group(s_name, s_description)
self.assertEqual(200, resp.status)
-
- self.addCleanup(self.client.delete_security_group,
- security_group['id'])
# Now try the Security Group with the same 'Name'
self.assertRaises(exceptions.BadRequest,
self.client.create_security_group, s_name,
@@ -163,15 +156,10 @@
@test.attr(type=['negative', 'gate'])
def test_update_security_group_with_invalid_sg_name(self):
# Update security_group with invalid sg_name should fail
- s_name = data_utils.rand_name('sg-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
+ resp, securitygroup = self.create_security_group()
self.assertEqual(200, resp.status)
self.assertIn('id', securitygroup)
securitygroup_id = securitygroup['id']
- self.addCleanup(self._delete_security_group,
- securitygroup_id)
# Update Security Group with group name longer than 255 chars
s_new_name = 'securitygroup-'.ljust(260, '0')
self.assertRaises(exceptions.BadRequest,
@@ -183,15 +171,10 @@
@test.attr(type=['negative', 'gate'])
def test_update_security_group_with_invalid_sg_des(self):
# Update security_group with invalid sg_des should fail
- s_name = data_utils.rand_name('sg-')
- s_description = data_utils.rand_name('description-')
- resp, securitygroup = \
- self.client.create_security_group(s_name, s_description)
+ resp, securitygroup = self.create_security_group()
self.assertEqual(200, resp.status)
self.assertIn('id', securitygroup)
securitygroup_id = securitygroup['id']
- self.addCleanup(self._delete_security_group,
- securitygroup_id)
# Update Security Group with group description longer than 255 chars
s_new_des = 'des-'.ljust(260, '0')
self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
new file mode 100644
index 0000000..748ba41
--- /dev/null
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -0,0 +1,42 @@
+# Copyright 2014 NEC Corporation
+# 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.compute import base
+from tempest import test
+
+
+class AZTestJSON(base.BaseV2ComputeTest):
+
+ """
+ Tests Availability Zone API List
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(AZTestJSON, cls).setUpClass()
+ cls.client = cls.availability_zone_client
+
+ @test.attr(type='gate')
+ def test_get_availability_zone_list_with_non_admin_user(self):
+ # List of availability zone with non-administrator user
+ resp, availability_zone = self.client.get_availability_zone_list()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(availability_zone) > 0)
+
+
+class AZTestXML(AZTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 887608f..f705308 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -20,9 +20,9 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -54,14 +54,14 @@
cls.client.wait_for_server_status(cls.server_initial['id'], 'ACTIVE')
resp, cls.server = cls.client.get_server(cls.server_initial['id'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_server_response(self):
# Check that the required fields are returned with values
self.assertEqual(202, self.resp.status)
self.assertTrue(self.server_initial['id'] is not None)
self.assertTrue(self.server_initial['adminPass'] is not None)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_verify_server_details(self):
# Verify the specified server attributes are set correctly
self.assertEqual(self.accessIPv4, self.server['accessIPv4'])
@@ -74,7 +74,7 @@
self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
self.assertEqual(self.meta, self.server['metadata'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_servers(self):
# The created server should be in the list of all servers
resp, body = self.client.list_servers()
@@ -82,7 +82,7 @@
found = any([i for i in servers if i['id'] == self.server['id']])
self.assertTrue(found)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_servers_with_detail(self):
# The created server should be in the detailed list of all servers
resp, body = self.client.list_servers_with_detail()
@@ -91,19 +91,21 @@
self.assertTrue(found)
@testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_verify_created_server_vcpus(self):
# Verify that the number of vcpus reported by the instance matches
# the amount stated by the flavor
resp, flavor = self.flavors_client.get_flavor_details(self.flavor_ref)
- linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(self.server, self.ssh_user,
+ self.password)
self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
@testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_host_name_is_same_as_server_name(self):
# Verify the instance host name is the same as the server name
- linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(self.server, self.ssh_user,
+ self.password)
self.assertTrue(linux_client.hostname_equals_servername(self.name))
@@ -136,7 +138,7 @@
resp, cls.server = cls.client.get_server(cls.server_initial['id'])
@testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_verify_created_server_ephemeral_disk(self):
# Verify that the ephemeral disk is created when creating server
@@ -196,12 +198,12 @@
adminPass=admin_pass,
flavor=flavor_with_eph_disk_id))
# Get partition number of server without extra specs.
- linux_client = RemoteClient(server_no_eph_disk,
- self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server_no_eph_disk,
+ self.ssh_user, self.password)
partition_num = len(linux_client.get_partitions())
- linux_client = RemoteClient(server_with_eph_disk,
- self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server_with_eph_disk,
+ self.ssh_user, self.password)
self.assertEqual(partition_num + 1, linux_client.get_partitions())
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
new file mode 100644
index 0000000..ec40ce0
--- /dev/null
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -0,0 +1,121 @@
+# Copyright 2012 OpenStack Foundation
+# 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.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class DeleteServersTestJSON(base.BaseV2ComputeTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances"
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersTestJSON, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_building_state(self):
+ # Delete a server while it's VM state is Building
+ resp, server = self.create_test_server(wait_until='BUILD')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_active_server(self):
+ # Delete a server while it's VM state is Active
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shutoff_state(self):
+ # Delete a server while it's VM state is Shutoff
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.stop(server['id'])
+ self.client.wait_for_server_status(server['id'], 'SHUTOFF')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_pause_state(self):
+ # Delete a server while it's VM state is Pause
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.pause_server(server['id'])
+ self.client.wait_for_server_status(server['id'], 'PAUSED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shelved_state(self):
+ # Delete a server while it's VM state is Shelved
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.shelve_server(server['id'])
+ self.assertEqual(202, resp.status)
+
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED',
+ extra_timeout=offload_time)
+ else:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+
+class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances".
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersAdminTestJSON, cls).setUpClass()
+ cls.non_admin_client = cls.servers_client
+ cls.admin_client = cls.os_adm.servers_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_error_state(self):
+ # Delete a server while it's VM state is error
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.admin_client.reset_state(server['id'], state='error')
+ self.assertEqual(202, resp.status)
+ # Verify server's state
+ resp, server = self.non_admin_client.get_server(server['id'])
+ self.assertEqual(server['status'], 'ERROR')
+ resp, _ = self.non_admin_client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_admin_delete_servers_of_others(self):
+ # Administrator can delete servers of others
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.admin_client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'])
+
+
+class DeleteServersTestXML(DeleteServersTestJSON):
+ _interface = 'xml'
+
+
+class DeleteServersAdminTestXML(DeleteServersAdminTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 15b7b9e..fc0bb9f 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -18,8 +18,7 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -74,7 +73,7 @@
cls.fixed_network_name = CONF.compute.fixed_network_name
@utils.skip_unless_attr('multiple_images', 'Only one image found')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_image(self):
# Filter the list of servers by image
params = {'image': self.image_ref}
@@ -85,7 +84,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_flavor(self):
# Filter the list of servers by flavor
params = {'flavor': self.flavor_ref_alt}
@@ -96,7 +95,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_server_name(self):
# Filter the list of servers by server name
params = {'name': self.s1_name}
@@ -107,7 +106,7 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_server_status(self):
# Filter the list of servers by server status
params = {'status': 'active'}
@@ -118,7 +117,7 @@
self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_shutoff_status(self):
# Filter the list of servers by server shutoff status
params = {'status': 'shutoff'}
@@ -135,7 +134,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertNotIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 1}
@@ -143,14 +142,14 @@
# when _interface='xml', one element for servers_links in servers
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_zero_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 0}
resp, servers = self.client.list_servers(params)
self.assertEqual(0, len(servers['servers']))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_exceed_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 100000}
@@ -160,7 +159,7 @@
len([x for x in servers['servers'] if 'id' in x]))
@utils.skip_unless_attr('multiple_images', 'Only one image found')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_image(self):
# Filter the detailed list of servers by image
params = {'image': self.image_ref}
@@ -171,7 +170,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_flavor(self):
# Filter the detailed list of servers by flavor
params = {'flavor': self.flavor_ref_alt}
@@ -182,7 +181,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_server_name(self):
# Filter the detailed list of servers by server name
params = {'name': self.s1_name}
@@ -193,7 +192,7 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_server_status(self):
# Filter the detailed list of servers by server status
params = {'status': 'active'}
@@ -205,7 +204,7 @@
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filtered_by_name_wildcard(self):
# List all servers that contains '-instance' in name
params = {'name': '-instance'}
@@ -227,8 +226,8 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @skip_because(bug="1170718")
- @attr(type='gate')
+ @test.skip_because(bug="1170718")
+ @test.attr(type='gate')
def test_list_servers_filtered_by_ip(self):
# Filter servers by ip
# Here should be listed 1 server
@@ -242,9 +241,9 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @skip_because(bug="1182883",
- condition=CONF.service_available.neutron)
- @attr(type='gate')
+ @test.skip_because(bug="1182883",
+ condition=CONF.service_available.neutron)
+ @test.attr(type='gate')
def test_list_servers_filtered_by_ip_regex(self):
# Filter servers by regex ip
# List all servers filtered by part of ip address.
@@ -259,7 +258,7 @@
self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_limit_results(self):
# Verify only the expected number of detailed results are returned
params = {'limit': 1}
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f113047..adf522b 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -20,11 +20,10 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -53,7 +52,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.change_password,
'Change password not available.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_change_server_password(self):
# The server's password should be set to the provided password
new_password = 'Newpass1234'
@@ -64,16 +63,18 @@
if self.run_ssh:
# Verify that the user can authenticate with the new password
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, new_password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ new_password)
linux_client.validate_authentication()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_reboot_server_hard(self):
# The server should be power cycled
if self.run_ssh:
# Get the time the server was last rebooted,
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
boot_time = linux_client.get_boot_time()
resp, body = self.client.reboot(self.server_id, 'HARD')
@@ -82,19 +83,21 @@
if self.run_ssh:
# Log in and verify the boot time has changed
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
new_boot_time = linux_client.get_boot_time()
self.assertTrue(new_boot_time > boot_time,
'%s > %s' % (new_boot_time, boot_time))
- @skip_because(bug="1014647")
- @attr(type='smoke')
+ @test.skip_because(bug="1014647")
+ @test.attr(type='smoke')
def test_reboot_server_soft(self):
# The server should be signaled to reboot gracefully
if self.run_ssh:
# Get the time the server was last rebooted,
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
boot_time = linux_client.get_boot_time()
resp, body = self.client.reboot(self.server_id, 'SOFT')
@@ -103,12 +106,13 @@
if self.run_ssh:
# Log in and verify the boot time has changed
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
new_boot_time = linux_client.get_boot_time()
self.assertTrue(new_boot_time > boot_time,
'%s > %s' % (new_boot_time, boot_time))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_rebuild_server(self):
# The server should be rebuilt using the provided image and data
meta = {'rebuild': 'server'}
@@ -140,10 +144,11 @@
if self.run_ssh:
# Verify that the user can authenticate with the provided password
- linux_client = RemoteClient(server, self.ssh_user, password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ password)
linux_client.validate_authentication()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_rebuild_server_in_stop_state(self):
# The server in stop state should be rebuilt using the provided
# image and remain in SHUTOFF state
@@ -181,7 +186,7 @@
return current_flavor, new_flavor_ref
@testtools.skipIf(not resize_available, 'Resize not available.')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_resize_server_confirm(self):
# The server's RAM and disk space should be modified to that of
# the provided flavor
@@ -200,7 +205,7 @@
self.assertEqual(new_flavor_ref, server['flavor']['id'])
@testtools.skipIf(not resize_available, 'Resize not available.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_resize_server_revert(self):
# The server's RAM and disk space should return to its original
# values after a resize is reverted
@@ -228,7 +233,7 @@
required time (%s s).' % (self.server_id, self.build_timeout)
raise exceptions.TimeoutException(message)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_backup(self):
# Positive test:create backup successfully and rotate backups correctly
# create the first and the second backup
@@ -313,7 +318,7 @@
lines = len(output.split('\n'))
self.assertEqual(lines, 10)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_console_output(self):
# Positive test:Should be able to GET the console output
# for a given server_id and number of lines
@@ -329,7 +334,7 @@
self.wait_for(self._get_output)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_console_output_server_id_in_shutoff_status(self):
# Positive test:Should be able to GET the console output
# for a given server_id in SHUTOFF status
@@ -346,7 +351,7 @@
self.wait_for(self._get_output)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_pause_unpause_server(self):
resp, server = self.client.pause_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -355,7 +360,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_suspend_resume_server(self):
resp, server = self.client.suspend_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -364,7 +369,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_shelve_unshelve_server(self):
resp, server = self.client.shelve_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -389,7 +394,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_stop_start_server(self):
resp, server = self.servers_client.stop(self.server_id)
self.assertEqual(202, resp.status)
@@ -398,7 +403,7 @@
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_lock_unlock_server(self):
# Lock the server,try server stop(exceptions throw),unlock it and retry
resp, server = self.servers_client.lock_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 8e432c4..d5528c4 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -14,8 +14,11 @@
# under the License.
from tempest.api.compute import base
+from tempest import config
from tempest import test
+CONF = config.CONF
+
class ServerAddressesTestJSON(base.BaseV2ComputeTest):
_interface = 'json'
@@ -29,6 +32,8 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
+ @test.skip_because(bug="1210483",
+ condition=CONF.service_available.neutron)
@test.attr(type='smoke')
def test_list_server_addresses(self):
# All public and private addresses for
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 203832e..7167a8b 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -104,38 +104,6 @@
self.assertEqual('::babe:202:202', server['accessIPv6'])
@attr(type='gate')
- def test_delete_server_while_in_shutoff_state(self):
- # Delete a server while it's VM state is Shutoff
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.stop(server['id'])
- self.client.wait_for_server_status(server['id'], 'SHUTOFF')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_server_while_in_pause_state(self):
- # Delete a server while it's VM state is Pause
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.pause_server(server['id'])
- self.client.wait_for_server_status(server['id'], 'PAUSED')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_server_while_in_building_state(self):
- # Delete a server while it's VM state is Building
- resp, server = self.create_test_server(wait_until='BUILD')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @attr(type='gate')
- def test_delete_active_server(self):
- # Delete a server while it's VM state is Active
- resp, server = self.create_test_server(wait_until='ACTIVE')
- 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_test_server(accessIPv6='2001:2001::3')
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index fcd055b..1df4159 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -13,14 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-import random
-import string
import testtools
from tempest.api.compute import base
from tempest import config
-from tempest import exceptions
from tempest.test import attr
CONF = config.CONF
@@ -65,14 +62,6 @@
if host != target_host:
return target_host
- def _get_non_existing_host_name(self):
- random_name = ''.join(
- random.choice(string.ascii_uppercase) for x in range(20))
-
- self.assertNotIn(random_name, self._get_compute_hostnames())
-
- return random_name
-
def _get_server_status(self, server_id):
return self._get_server_details(server_id)['status']
@@ -110,18 +99,6 @@
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
- @testtools.skipIf(not CONF.compute_feature_enabled.live_migration,
- 'Live migration not available')
- @attr(type='gate')
- def test_invalid_host_for_migration(self):
- # Migrating to an invalid host should not change the status
- server_id = self._get_an_active_server()
- target_host = self._get_non_existing_host_name()
-
- self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
- server_id, target_host)
- self.assertEqual('ACTIVE', self._get_server_status(server_id))
-
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
CONF.compute_feature_enabled.
block_migration_for_live_migration,
@@ -155,13 +132,6 @@
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
- @classmethod
- def tearDownClass(cls):
- for server_id in cls.created_server_ids:
- cls.servers_client.delete_server(server_id)
-
- super(LiveBlockMigrationTestJSON, cls).tearDownClass()
-
class LiveBlockMigrationTestXML(LiveBlockMigrationTestJSON):
_host_key = (
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
new file mode 100644
index 0000000..da0e4c4
--- /dev/null
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -0,0 +1,60 @@
+# Copyright 2012 OpenStack Foundation
+# 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.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+from tempest import test
+
+CONF = config.CONF
+
+
+class LiveBlockMigrationNegativeTestJSON(base.BaseV2ComputeAdminTest):
+ _host_key = 'OS-EXT-SRV-ATTR:host'
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(LiveBlockMigrationNegativeTestJSON, cls).setUpClass()
+ if not CONF.compute_feature_enabled.live_migration:
+ raise cls.skipException("Live migration is not enabled")
+ cls.admin_hosts_client = cls.os_adm.hosts_client
+ cls.admin_servers_client = cls.os_adm.servers_client
+
+ def _migrate_server_to(self, server_id, dest_host):
+ _resp, body = self.admin_servers_client.live_migrate_server(
+ server_id, dest_host,
+ self.config.compute_feature_enabled.
+ block_migration_for_live_migration)
+ return body
+
+ @test.attr(type=['negative', 'gate'])
+ def test_invalid_host_for_migration(self):
+ # Migrating to an invalid host should not change the status
+ target_host = data_utils.rand_name('host-')
+ _, server = self.create_test_server(wait_until="ACTIVE")
+ server_id = server['id']
+
+ self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
+ server_id, target_host)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+
+class LiveBlockMigrationNegativeTestXML(LiveBlockMigrationNegativeTestJSON):
+ _host_key = (
+ '{http://docs.openstack.org/compute/ext/extended_status/api/v1.1}host')
+ _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_aggregates.py b/tempest/api/compute/v3/admin/test_aggregates.py
index b8b478d..20093e4 100644
--- a/tempest/api/compute/v3/admin/test_aggregates.py
+++ b/tempest/api/compute/v3/admin/test_aggregates.py
@@ -32,7 +32,6 @@
def setUpClass(cls):
super(AggregatesAdminV3Test, cls).setUpClass()
cls.client = cls.aggregates_admin_client
- cls.user_client = cls.aggregates_client
cls.aggregate_name_prefix = 'test_aggregate_'
cls.az_name_prefix = 'test_az_'
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index 57ac869..176751f 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -29,7 +29,6 @@
def setUpClass(cls):
super(AZAdminV3Test, cls).setUpClass()
cls.client = cls.availability_zone_admin_client
- cls.non_adm_client = cls.availability_zone_client
@attr(type='gate')
def test_get_availability_zone_list(self):
@@ -45,11 +44,3 @@
self.client.get_availability_zone_list_detail()
self.assertEqual(200, resp.status)
self.assertTrue(len(availability_zone) > 0)
-
- @attr(type='gate')
- def test_get_availability_zone_list_with_non_admin_user(self):
- # List of availability zone with non-administrator user
- resp, availability_zone = \
- self.non_adm_client.get_availability_zone_list()
- self.assertEqual(200, resp.status)
- self.assertTrue(len(availability_zone) > 0)
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index ccb9d8e..b388b70 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -16,7 +16,6 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
from tempest import test
CONF = config.CONF
@@ -29,10 +28,8 @@
@classmethod
def setUpClass(cls):
super(QuotasAdminV3Test, cls).setUpClass()
- cls.auth_url = CONF.identity.uri
cls.client = cls.quotas_client
cls.adm_client = cls.quotas_admin_client
- cls.identity_admin_client = cls._get_identity_admin_client()
# 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
@@ -49,17 +46,33 @@
def test_get_default_quotas(self):
# Admin can get the default resource quota set for a tenant
expected_quota_set = self.default_quota_set | set(['id'])
- resp, quota_set = self.client.get_default_quota_set(
+ resp, quota_set = self.adm_client.get_default_quota_set(
self.demo_tenant_id)
self.assertEqual(200, resp.status)
self.assertEqual(sorted(expected_quota_set),
sorted(quota_set.keys()))
self.assertEqual(quota_set['id'], self.demo_tenant_id)
+ @test.attr(type='smoke')
+ def test_get_quota_set_detail(self):
+ # Admin can get the detail of resource quota set for a tenant
+ expected_quota_set = self.default_quota_set | set(['id'])
+ expected_detail = {'reserved', 'limit', 'in_use'}
+ resp, quota_set = self.adm_client.get_quota_set_detail(
+ self.demo_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(sorted(expected_quota_set), sorted(quota_set.keys()))
+ self.assertEqual(quota_set['id'], self.demo_tenant_id)
+ for quota in quota_set:
+ if quota == 'id':
+ continue
+ self.assertEqual(sorted(expected_detail),
+ sorted(quota_set[quota].keys()))
+
@test.attr(type='gate')
def test_update_all_quota_resources_for_tenant(self):
# Admin can update all the resource quota limits for a tenant
- resp, default_quota_set = self.client.get_default_quota_set(
+ resp, default_quota_set = self.adm_client.get_default_quota_set(
self.demo_tenant_id)
new_quota_set = {'metadata_items': 256,
'ram': 10240, 'floating_ips': 20, 'fixed_ips': 10,
@@ -97,56 +110,3 @@
resp, quota_set = self.adm_client.get_quota_set(tenant_id)
self.assertEqual(200, resp.status)
self.assertEqual(quota_set['ram'], 5120)
-
- # TODO(afazekas): Add dedicated tenant to the skiped quota tests
- # it can be moved into the setUpClass as well
- @test.attr(type='gate')
- def test_create_server_when_cpu_quota_is_full(self):
- # Disallow server creation when tenant's vcpu quota is full
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
- default_vcpu_quota = quota_set['cores']
- vcpu_quota = 0 # Set the quota to zero to conserve resources
-
- resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
- force=True,
- cores=vcpu_quota)
-
- self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
- cores=default_vcpu_quota)
- self.assertRaises(exceptions.OverLimit, self.create_test_server)
-
- @test.attr(type='gate')
- def test_create_server_when_memory_quota_is_full(self):
- # Disallow server creation when tenant's memory quota is full
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
- default_mem_quota = quota_set['ram']
- mem_quota = 0 # Set the quota to zero to conserve resources
-
- self.adm_client.update_quota_set(self.demo_tenant_id,
- force=True,
- ram=mem_quota)
-
- self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
- ram=default_mem_quota)
- self.assertRaises(exceptions.OverLimit, self.create_test_server)
-
- @test.attr(type='gate')
- def test_update_quota_normal_user(self):
- self.assertRaises(exceptions.Unauthorized,
- self.client.update_quota_set,
- self.demo_tenant_id,
- ram=0)
-
- @test.attr(type=['negative', 'gate'])
- def test_create_server_when_instances_quota_is_full(self):
- # Once instances quota limit is reached, disallow server creation
- resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
- default_instances_quota = quota_set['instances']
- instances_quota = 0 # Set quota to zero to disallow server creation
-
- self.adm_client.update_quota_set(self.demo_tenant_id,
- force=True,
- instances=instances_quota)
- self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
- instances=default_instances_quota)
- self.assertRaises(exceptions.OverLimit, self.create_test_server)
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
new file mode 100644
index 0000000..c9f14f8
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -0,0 +1,88 @@
+# Copyright 2013 OpenStack Foundation
+# Copyright 2014 NEC Corporation
+# 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.compute import base
+from tempest import exceptions
+from tempest import test
+
+
+class QuotasAdminNegativeV3Test(base.BaseV3ComputeAdminTest):
+ _interface = 'json'
+ force_tenant_isolation = True
+
+ @classmethod
+ def setUpClass(cls):
+ super(QuotasAdminNegativeV3Test, cls).setUpClass()
+ cls.client = cls.quotas_client
+ cls.adm_client = cls.quotas_admin_client
+
+ # 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
+ cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
+ 'tenantId')
+
+ # TODO(afazekas): Add dedicated tenant to the skiped quota tests
+ # it can be moved into the setUpClass as well
+ @test.attr(type=['negative', 'gate'])
+ def test_create_server_when_cpu_quota_is_full(self):
+ # Disallow server creation when tenant's vcpu quota is full
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+ default_vcpu_quota = quota_set['cores']
+ vcpu_quota = 0 # Set the quota to zero to conserve resources
+
+ resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
+ force=True,
+ cores=vcpu_quota)
+
+ self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+ cores=default_vcpu_quota)
+ self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_server_when_memory_quota_is_full(self):
+ # Disallow server creation when tenant's memory quota is full
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+ default_mem_quota = quota_set['ram']
+ mem_quota = 0 # Set the quota to zero to conserve resources
+
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ force=True,
+ ram=mem_quota)
+
+ self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+ ram=default_mem_quota)
+ self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_update_quota_normal_user(self):
+ self.assertRaises(exceptions.Unauthorized,
+ self.client.update_quota_set,
+ self.demo_tenant_id,
+ ram=0)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_server_when_instances_quota_is_full(self):
+ # Once instances quota limit is reached, disallow server creation
+ resp, quota_set = self.adm_client.get_quota_set(self.demo_tenant_id)
+ default_instances_quota = quota_set['instances']
+ instances_quota = 0 # Set quota to zero to disallow server creation
+
+ self.adm_client.update_quota_set(self.demo_tenant_id,
+ force=True,
+ instances=instances_quota)
+ self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+ instances=default_instances_quota)
+ self.assertRaises(exceptions.OverLimit, self.create_test_server)
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 653eaf0..0dc3dbc 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -103,26 +103,6 @@
map(lambda x: x['id'], nonexistent_servers))
@test.attr(type='gate')
- def test_admin_delete_servers_of_others(self):
- # Administrator can delete servers of others
- _, server = self.create_test_server()
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
- self.servers_client.wait_for_server_termination(server['id'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_error_state(self):
- # Delete a server while it's VM state is error
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.reset_state(server['id'], state='error')
- self.assertEqual(202, resp.status)
- # Verify server's state
- resp, server = self.client.get_server(server['id'])
- self.assertEqual(server['status'], 'ERROR')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
def test_reset_state_server(self):
# Reset server's state to 'error'
resp, server = self.client.reset_state(self.s1_id)
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index bbb84fb..b045630 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -13,11 +13,10 @@
# under the License.
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -34,18 +33,6 @@
cls.client = cls.images_client
cls.servers_client = cls.servers_client
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
def __create_image__(self, server_id, name, meta=None):
resp, body = self.servers_client.create_image(server_id, name, meta)
image_id = data_utils.parse_image_id(resp['location'])
@@ -53,7 +40,7 @@
self.client.wait_for_image_status(image_id, 'ACTIVE')
return resp, body
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_deleted_server(self):
# An image should not be created if the server instance is removed
resp, server = self.create_test_server(wait_until='ACTIVE')
@@ -68,7 +55,7 @@
self.__create_image__,
server['id'], name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_invalid_server(self):
# An image should not be created with invalid server id
# Create a new image with invalid server id
@@ -79,7 +66,7 @@
self.assertRaises(exceptions.NotFound, self.__create_image__,
'!@#$%^&*()', name, meta)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_from_stopped_server(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
self.servers_client.stop(server['id'])
@@ -93,7 +80,7 @@
self.addCleanup(self.client.delete_image, image['id'])
self.assertEqual(snapshot_name, image['name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_queued_image(self):
snapshot_name = data_utils.rand_name('test-snap-')
resp, server = self.create_test_server(wait_until='ACTIVE')
@@ -104,7 +91,7 @@
resp, body = self.client.delete_image(image['id'])
self.assertEqual('200', resp['status'])
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_uuid_35_characters_or_less(self):
# Return an error if Image ID passed is 35 characters or less
snapshot_name = data_utils.rand_name('test-snap-')
@@ -113,7 +100,7 @@
self.servers_client.create_image,
test_uuid, snapshot_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_image_specify_uuid_37_characters_or_more(self):
# Return an error if Image ID passed is 37 characters or more
snapshot_name = data_utils.rand_name('test-snap-')
diff --git a/tempest/api/compute/v3/images/test_images_oneserver.py b/tempest/api/compute/v3/images/test_images_oneserver.py
index cd40948..1ded4e4 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver.py
@@ -16,7 +16,6 @@
import testtools
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
@@ -29,13 +28,6 @@
class ImagesOneServerV3Test(base.BaseV3ComputeTest):
_interface = 'json'
- def tearDown(self):
- """Terminate test instances created after a test is executed."""
- for image_id in self.image_ids:
- self.client.delete_image(image_id)
- self.image_ids.remove(image_id)
- super(ImagesOneServerV3Test, self).tearDown()
-
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
# but if it has an issue, we build a new one
@@ -66,20 +58,6 @@
cls.tearDownClass()
raise
- cls.image_ids = []
-
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
def _get_default_flavor_disk_size(self, flavor_id):
resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
return flavor['disk']
diff --git a/tempest/api/compute/v3/images/test_images_oneserver_negative.py b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
index f2f2375..8d2517e 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
@@ -15,7 +15,6 @@
# under the License.
from tempest.api.compute import base
-from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -72,18 +71,6 @@
cls.image_ids = []
- if cls.multi_user:
- if CONF.compute.allow_tenant_isolation:
- creds = cls.isolated_creds.get_alt_creds()
- username, tenant_name, password = creds
- cls.alt_manager = clients.Manager(username=username,
- password=password,
- tenant_name=tenant_name)
- else:
- # Use the alt_XXX credentials in the config file
- cls.alt_manager = clients.AltManager()
- cls.alt_client = cls.alt_manager.images_client
-
@test.skip_because(bug="1006725")
@test.attr(type=['negative', 'gate'])
def test_create_image_specify_multibyte_character_image_name(self):
diff --git a/tempest/api/compute/v3/servers/test_attach_volume.py b/tempest/api/compute/v3/servers/test_attach_volume.py
index d693be5..2edf934 100644
--- a/tempest/api/compute/v3/servers/test_attach_volume.py
+++ b/tempest/api/compute/v3/servers/test_attach_volume.py
@@ -16,9 +16,9 @@
import testtools
from tempest.api.compute import base
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -78,7 +78,7 @@
self.addCleanup(self._detach, server['id'], volume['id'])
@testtools.skipIf(not run_ssh, 'SSH required for this test')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
@@ -92,9 +92,8 @@
self.servers_client.start(server['id'])
self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
- linux_client = RemoteClient(server,
- self.image_ssh_user,
- server['admin_password'])
+ linux_client = remote_client.RemoteClient(server, self.image_ssh_user,
+ server['admin_password'])
partitions = linux_client.get_partitions()
self.assertIn(self.device, partitions)
@@ -107,8 +106,7 @@
self.servers_client.start(server['id'])
self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
- linux_client = RemoteClient(server,
- self.image_ssh_user,
- server['admin_password'])
+ linux_client = remote_client.RemoteClient(server, self.image_ssh_user,
+ server['admin_password'])
partitions = linux_client.get_partitions()
self.assertNotIn(self.device, partitions)
diff --git a/tempest/api/compute/v3/servers/test_availability_zone.py b/tempest/api/compute/v3/servers/test_availability_zone.py
new file mode 100644
index 0000000..feac9a1
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_availability_zone.py
@@ -0,0 +1,38 @@
+# Copyright 2014 NEC Corporation
+# 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.compute import base
+from tempest import test
+
+
+class AZV3Test(base.BaseV3ComputeTest):
+
+ """
+ Tests Availability Zone API List
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(AZV3Test, cls).setUpClass()
+ cls.client = cls.availability_zone_client
+
+ @test.attr(type='gate')
+ def test_get_availability_zone_list_with_non_admin_user(self):
+ # List of availability zone with non-administrator user
+ resp, availability_zone = self.client.get_availability_zone_list()
+ self.assertEqual(200, resp.status)
+ self.assertTrue(len(availability_zone) > 0)
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
index 7a4c877..0825381 100644
--- a/tempest/api/compute/v3/servers/test_create_server.py
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -20,7 +20,7 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import test
@@ -95,7 +95,8 @@
@test.attr(type='gate')
def test_can_log_into_created_server(self):
# Check that the user can authenticate with the generated password
- linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(self.server,
+ self.ssh_user, self.password)
self.assertTrue(linux_client.can_authenticate())
@testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
@@ -104,14 +105,16 @@
# Verify that the number of vcpus reported by the instance matches
# the amount stated by the flavor
resp, flavor = self.flavors_client.get_flavor_details(self.flavor_ref)
- linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(self.server,
+ self.ssh_user, self.password)
self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
@testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
@test.attr(type='gate')
def test_host_name_is_same_as_server_name(self):
# Verify the instance host name is the same as the server name
- linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(self.server,
+ self.ssh_user, self.password)
self.assertTrue(linux_client.hostname_equals_servername(self.name))
@@ -204,12 +207,12 @@
adminPass=admin_pass,
flavor=flavor_with_eph_disk_id))
# Get partition number of server without extra specs.
- linux_client = RemoteClient(server_no_eph_disk,
- self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server_no_eph_disk,
+ self.ssh_user, self.password)
partition_num = len(linux_client.get_partitions())
- linux_client = RemoteClient(server_with_eph_disk,
- self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server_with_eph_disk,
+ self.ssh_user, self.password)
self.assertEqual(partition_num + 1, linux_client.get_partitions())
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
new file mode 100644
index 0000000..f53ab6e
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -0,0 +1,113 @@
+# Copyright 2012 OpenStack Foundation
+#
+# 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 import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class DeleteServersV3Test(base.BaseV3ComputeTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances".
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersV3Test, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_building_state(self):
+ # Delete a server while it's VM state is Building
+ resp, server = self.create_test_server(wait_until='BUILD')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_active_server(self):
+ # Delete a server while it's VM state is Active
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shutoff_state(self):
+ # Delete a server while it's VM state is Shutoff
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.stop(server['id'])
+ self.client.wait_for_server_status(server['id'], 'SHUTOFF')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_pause_state(self):
+ # Delete a server while it's VM state is Pause
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.pause_server(server['id'])
+ self.client.wait_for_server_status(server['id'], 'PAUSED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_shelved_state(self):
+ # Delete a server while it's VM state is Shelved
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.shelve_server(server['id'])
+ self.assertEqual(202, resp.status)
+
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED',
+ extra_timeout=offload_time)
+ else:
+ self.client.wait_for_server_status(server['id'],
+ 'SHELVED')
+
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+
+class DeleteServersAdminV3Test(base.BaseV3ComputeAdminTest):
+ # NOTE: Server creations of each test class should be under 10
+ # for preventing "Quota exceeded for instances".
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(DeleteServersAdminV3Test, cls).setUpClass()
+ cls.non_admin_client = cls.servers_client
+ cls.admin_client = cls.servers_admin_client
+
+ @test.attr(type='gate')
+ def test_delete_server_while_in_error_state(self):
+ # Delete a server while it's VM state is error
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.admin_client.reset_state(server['id'], state='error')
+ self.assertEqual(202, resp.status)
+ # Verify server's state
+ resp, server = self.non_admin_client.get_server(server['id'])
+ self.assertEqual(server['status'], 'ERROR')
+ resp, _ = self.non_admin_client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+
+ @test.attr(type='gate')
+ def test_admin_delete_servers_of_others(self):
+ # Administrator can delete servers of others
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, _ = self.admin_client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'])
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index d536871..c4f6e14 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -14,8 +14,7 @@
# under the License.
from tempest.api.compute import base
-from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class InstanceActionsV3Test(base.BaseV3ComputeTest):
@@ -29,7 +28,7 @@
cls.request_id = resp['x-compute-request-id']
cls.server_id = server['id']
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_instance_actions(self):
# List actions of the provided server
resp, body = self.client.reboot(self.server_id, 'HARD')
@@ -41,7 +40,7 @@
self.assertTrue(any([i for i in body if i['action'] == 'create']))
self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_instance_action(self):
# Get the action details of the provided server
resp, body = self.client.get_instance_action(self.server_id,
@@ -49,15 +48,3 @@
self.assertEqual(200, resp.status)
self.assertEqual(self.server_id, body['instance_uuid'])
self.assertEqual('create', body['action'])
-
- @attr(type=['negative', 'gate'])
- def test_list_instance_actions_invalid_server(self):
- # List actions of the invalid server id
- self.assertRaises(exceptions.NotFound,
- self.client.list_instance_actions, 'server-999')
-
- @attr(type=['negative', 'gate'])
- def test_get_instance_action_invalid_request(self):
- # Get the action details of the provided server with invalid request
- self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
- self.server_id, '999')
diff --git a/tempest/api/compute/v3/servers/test_instance_actions_negative.py b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
new file mode 100644
index 0000000..bd741e0
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
@@ -0,0 +1,44 @@
+# Copyright 2014 NEC Corporation
+# 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.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class InstanceActionsNegativeV3Test(base.BaseV3ComputeTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(InstanceActionsNegativeV3Test, cls).setUpClass()
+ cls.client = cls.servers_client
+ resp, server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_instance_actions_invalid_server(self):
+ # List actions of the invalid server id
+ invalid_server_id = data_utils.rand_uuid()
+ self.assertRaises(exceptions.NotFound,
+ self.client.list_instance_actions, invalid_server_id)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_get_instance_action_invalid_request(self):
+ # Get the action details of the provided server with invalid request
+ invalid_request_id = 'req-' + data_utils.rand_uuid()
+ self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
+ self.server_id, invalid_request_id)
diff --git a/tempest/api/compute/v3/servers/test_list_server_filters.py b/tempest/api/compute/v3/servers/test_list_server_filters.py
index 9082eda..e08125b 100644
--- a/tempest/api/compute/v3/servers/test_list_server_filters.py
+++ b/tempest/api/compute/v3/servers/test_list_server_filters.py
@@ -18,8 +18,7 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -74,7 +73,7 @@
cls.fixed_network_name = CONF.compute.fixed_network_name
@utils.skip_unless_attr('multiple_images', 'Only one image found')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_image(self):
# Filter the list of servers by image
params = {'image': self.image_ref}
@@ -85,7 +84,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_flavor(self):
# Filter the list of servers by flavor
params = {'flavor': self.flavor_ref_alt}
@@ -96,7 +95,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_server_name(self):
# Filter the list of servers by server name
params = {'name': self.s1_name}
@@ -107,7 +106,7 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_server_status(self):
# Filter the list of servers by server status
params = {'status': 'active'}
@@ -118,21 +117,21 @@
self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 1}
resp, servers = self.client.list_servers(params)
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_zero_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 0}
resp, servers = self.client.list_servers(params)
self.assertEqual(0, len(servers['servers']))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_exceed_limit(self):
# Verify only the expected number of servers are returned
params = {'limit': 100000}
@@ -142,7 +141,7 @@
len([x for x in servers['servers'] if 'id' in x]))
@utils.skip_unless_attr('multiple_images', 'Only one image found')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_image(self):
# Filter the detailed list of servers by image
params = {'image': self.image_ref}
@@ -153,7 +152,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_flavor(self):
# Filter the detailed list of servers by flavor
params = {'flavor': self.flavor_ref_alt}
@@ -164,7 +163,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_server_name(self):
# Filter the detailed list of servers by server name
params = {'name': self.s1_name}
@@ -175,7 +174,7 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_filter_by_server_status(self):
# Filter the detailed list of servers by server status
params = {'status': 'active'}
@@ -188,7 +187,7 @@
self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filter_by_shutoff_status(self):
# Filter the list of servers by server shutoff status
params = {'status': 'shutoff'}
@@ -205,7 +204,7 @@
self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers))
self.assertNotIn(self.s3['id'], map(lambda x: x['id'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_filtered_by_name_wildcard(self):
# List all servers that contains '-instance' in name
params = {'name': '-instance'}
@@ -227,8 +226,8 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @skip_because(bug="1170718")
- @attr(type='gate')
+ @test.skip_because(bug="1170718")
+ @test.attr(type='gate')
def test_list_servers_filtered_by_ip(self):
# Filter servers by ip
# Here should be listed 1 server
@@ -242,9 +241,9 @@
self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
- @skip_because(bug="1182883",
- condition=CONF.service_available.neutron)
- @attr(type='gate')
+ @test.skip_because(bug="1182883",
+ condition=CONF.service_available.neutron)
+ @test.attr(type='gate')
def test_list_servers_filtered_by_ip_regex(self):
# Filter servers by regex ip
# List all servers filtered by part of ip address.
@@ -259,7 +258,7 @@
self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_servers_detailed_limit_results(self):
# Verify only the expected number of detailed results are returned
params = {'limit': 1}
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
index f1ae5f8..dee4407 100644
--- a/tempest/api/compute/v3/servers/test_multiple_create.py
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -15,7 +15,6 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest import exceptions
from tempest import test
@@ -47,38 +46,6 @@
self.assertEqual('202', resp['status'])
self.assertNotIn('reservation_id', body)
- @test.attr(type=['negative', 'gate'])
- def test_min_count_less_than_one(self):
- invalid_min_count = 0
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=invalid_min_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_min_count_non_integer(self):
- invalid_min_count = 2.5
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=invalid_min_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_less_than_one(self):
- invalid_max_count = 0
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- max_count=invalid_max_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_non_integer(self):
- invalid_max_count = 2.5
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- max_count=invalid_max_count)
-
- @test.attr(type=['negative', 'gate'])
- def test_max_count_less_than_min_count(self):
- min_count = 3
- max_count = 2
- self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
- min_count=min_count,
- max_count=max_count)
-
@test.attr(type='gate')
def test_multiple_create_with_reservation_return(self):
resp, body = self._create_multiple_servers(wait_until='ACTIVE',
diff --git a/tempest/api/compute/v3/servers/test_multiple_create_negative.py b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
new file mode 100644
index 0000000..57bb807
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
@@ -0,0 +1,69 @@
+# Copyright 2013 IBM Corp
+# 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.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class MultipleCreateV3NegativeTest(base.BaseV3ComputeTest):
+ _interface = 'json'
+ _name = 'multiple-create-negative-test'
+
+ def _generate_name(self):
+ return data_utils.rand_name(self._name)
+
+ def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
+ """
+ This is the right way to create_multiple servers and manage to get the
+ created servers into the servers list to be cleaned up after all.
+ """
+ kwargs['name'] = kwargs.get('name', self._generate_name())
+ resp, body = self.create_test_server(**kwargs)
+
+ return resp, body
+
+ @test.attr(type=['negative', 'gate'])
+ def test_min_count_less_than_one(self):
+ invalid_min_count = 0
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=invalid_min_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_min_count_non_integer(self):
+ invalid_min_count = 2.5
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=invalid_min_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_less_than_one(self):
+ invalid_max_count = 0
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ max_count=invalid_max_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_non_integer(self):
+ invalid_max_count = 2.5
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ max_count=invalid_max_count)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_max_count_less_than_min_count(self):
+ min_count = 3
+ max_count = 2
+ self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+ min_count=min_count,
+ max_count=max_count)
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 0dae796..6584b93 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -19,11 +19,10 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -52,7 +51,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.change_password,
'Change password not available.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_change_server_password(self):
# The server's password should be set to the provided password
new_password = 'Newpass1234'
@@ -63,16 +62,18 @@
if self.run_ssh:
# Verify that the user can authenticate with the new password
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, new_password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ new_password)
linux_client.validate_authentication()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_reboot_server_hard(self):
# The server should be power cycled
if self.run_ssh:
# Get the time the server was last rebooted,
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
boot_time = linux_client.get_boot_time()
resp, body = self.client.reboot(self.server_id, 'HARD')
@@ -81,18 +82,20 @@
if self.run_ssh:
# Log in and verify the boot time has changed
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
new_boot_time = linux_client.get_boot_time()
self.assertGreater(new_boot_time, boot_time)
- @skip_because(bug="1014647")
- @attr(type='smoke')
+ @test.skip_because(bug="1014647")
+ @test.attr(type='smoke')
def test_reboot_server_soft(self):
# The server should be signaled to reboot gracefully
if self.run_ssh:
# Get the time the server was last rebooted,
resp, server = self.client.get_server(self.server_id)
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
boot_time = linux_client.get_boot_time()
resp, body = self.client.reboot(self.server_id, 'SOFT')
@@ -101,11 +104,12 @@
if self.run_ssh:
# Log in and verify the boot time has changed
- linux_client = RemoteClient(server, self.ssh_user, self.password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ self.password)
new_boot_time = linux_client.get_boot_time()
self.assertGreater(new_boot_time, boot_time)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_rebuild_server(self):
# The server should be rebuilt using the provided image and data
meta = {'rebuild': 'server'}
@@ -133,10 +137,11 @@
if self.run_ssh:
# Verify that the user can authenticate with the provided password
- linux_client = RemoteClient(server, self.ssh_user, password)
+ linux_client = remote_client.RemoteClient(server, self.ssh_user,
+ password)
linux_client.validate_authentication()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_rebuild_server_in_stop_state(self):
# The server in stop state should be rebuilt using the provided
# image and remain in SHUTOFF state
@@ -174,7 +179,7 @@
return current_flavor, new_flavor_ref
@testtools.skipIf(not resize_available, 'Resize not available.')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_resize_server_confirm(self):
# The server's RAM and disk space should be modified to that of
# the provided flavor
@@ -193,7 +198,7 @@
self.assertEqual(new_flavor_ref, server['flavor']['id'])
@testtools.skipIf(not resize_available, 'Resize not available.')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_resize_server_revert(self):
# The server's RAM and disk space should return to its original
# values after a resize is reverted
@@ -221,7 +226,7 @@
required time (%s s).' % (self.server_id, self.build_timeout)
raise exceptions.TimeoutException(message)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_backup(self):
# Positive test:create backup successfully and rotate backups correctly
# create the first and the second backup
@@ -303,7 +308,7 @@
lines = len(output.split('\n'))
self.assertEqual(lines, 10)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_console_output(self):
# Positive test:Should be able to GET the console output
# for a given server_id and number of lines
@@ -319,7 +324,7 @@
self.wait_for(self._get_output)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_console_output_server_id_in_shutoff_status(self):
# Positive test:Should be able to GET the console output
# for a given server_id in SHUTOFF status
@@ -336,7 +341,7 @@
self.wait_for(self._get_output)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_pause_unpause_server(self):
resp, server = self.client.pause_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -345,7 +350,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_suspend_resume_server(self):
resp, server = self.client.suspend_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -354,7 +359,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_shelve_unshelve_server(self):
resp, server = self.client.shelve_server(self.server_id)
self.assertEqual(202, resp.status)
@@ -378,7 +383,7 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_stop_start_server(self):
resp, server = self.servers_client.stop(self.server_id)
self.assertEqual(202, resp.status)
@@ -387,7 +392,7 @@
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_lock_unlock_server(self):
# Lock the server,try server stop(exceptions throw),unlock it and retry
resp, server = self.servers_client.lock_server(self.server_id)
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index bffa7c4..038e254 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -14,8 +14,11 @@
# under the License.
from tempest.api.compute import base
+from tempest import config
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
+
+CONF = config.CONF
class ServerAddressesV3Test(base.BaseV3ComputeTest):
@@ -30,20 +33,22 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_list_server_addresses_invalid_server_id(self):
# List addresses request should fail if server id not in system
self.assertRaises(exceptions.NotFound, self.client.list_addresses,
'999')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_list_server_addresses_by_network_neg(self):
# List addresses by network should fail if network name not valid
self.assertRaises(exceptions.NotFound,
self.client.list_addresses_by_network,
self.server['id'], 'invalid')
- @attr(type='smoke')
+ @test.skip_because(bug="1210483",
+ condition=CONF.service_available.neutron)
+ @test.attr(type='smoke')
def test_list_server_addresses(self):
# All public and private addresses for
# a server should be returned
@@ -60,7 +65,7 @@
self.assertTrue(address['addr'])
self.assertTrue(address['version'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_server_addresses_by_network(self):
# Providing a network type should filter
# the addresses return by that type
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
index dc64c40..5480e31 100644
--- a/tempest/api/compute/v3/servers/test_servers.py
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -105,38 +105,6 @@
server['os-access-ips:access_ip_v6'])
@test.attr(type='gate')
- def test_delete_server_while_in_shutoff_state(self):
- # Delete a server while it's VM state is Shutoff
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.stop(server['id'])
- self.client.wait_for_server_status(server['id'], 'SHUTOFF')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_pause_state(self):
- # Delete a server while it's VM state is Pause
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, body = self.client.pause_server(server['id'])
- self.client.wait_for_server_status(server['id'], 'PAUSED')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_server_while_in_building_state(self):
- # Delete a server while it's VM state is Building
- resp, server = self.create_test_server(wait_until='BUILD')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.attr(type='gate')
- def test_delete_active_server(self):
- # Delete a server while it's VM state is Active
- resp, server = self.create_test_server(wait_until='ACTIVE')
- resp, _ = self.client.delete_server(server['id'])
- self.assertEqual('204', resp['status'])
-
- @test.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_test_server(access_ip_v6='2001:2001::3')
diff --git a/tempest/api/compute/v3/test_live_block_migration.py b/tempest/api/compute/v3/test_live_block_migration.py
index 144cadb..43b4e2b 100644
--- a/tempest/api/compute/v3/test_live_block_migration.py
+++ b/tempest/api/compute/v3/test_live_block_migration.py
@@ -13,14 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import random
-import string
-
import testtools
from tempest.api.compute import base
from tempest import config
-from tempest import exceptions
from tempest.test import attr
CONF = config.CONF
@@ -66,14 +62,6 @@
if host != target_host:
return target_host
- def _get_non_existing_host_name(self):
- random_name = ''.join(
- random.choice(string.ascii_uppercase) for x in range(20))
-
- self.assertNotIn(random_name, self._get_compute_hostnames())
-
- return random_name
-
def _get_server_status(self, server_id):
return self._get_server_details(server_id)['status']
@@ -111,18 +99,6 @@
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
- @testtools.skipIf(not CONF.compute_feature_enabled.live_migration,
- 'Live migration not available')
- @attr(type='gate')
- def test_invalid_host_for_migration(self):
- # Migrating to an invalid host should not change the status
- server_id = self._get_an_active_server()
- target_host = self._get_non_existing_host_name()
-
- self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
- server_id, target_host)
- self.assertEqual('ACTIVE', self._get_server_status(server_id))
-
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
CONF.compute_feature_enabled.
block_migration_for_live_migration,
@@ -155,10 +131,3 @@
self._migrate_server_to(server_id, target_host)
self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
-
- @classmethod
- def tearDownClass(cls):
- for server_id in cls.created_server_ids:
- cls.servers_client.delete_server(server_id)
-
- super(LiveBlockMigrationV3Test, cls).tearDownClass()
diff --git a/tempest/api/compute/v3/test_live_block_migration_negative.py b/tempest/api/compute/v3/test_live_block_migration_negative.py
new file mode 100644
index 0000000..4d820d8
--- /dev/null
+++ b/tempest/api/compute/v3/test_live_block_migration_negative.py
@@ -0,0 +1,54 @@
+# Copyright 2012 OpenStack Foundation
+# 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.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+from tempest import test
+
+CONF = config.CONF
+
+
+class LiveBlockMigrationV3NegativeTest(base.BaseV3ComputeAdminTest):
+ _host_key = 'os-extended-server-attributes:host'
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(LiveBlockMigrationV3NegativeTest, cls).setUpClass()
+ if not CONF.compute_feature_enabled.live_migration:
+ raise cls.skipException("Live migration is not enabled")
+
+ cls.admin_hosts_client = cls.hosts_admin_client
+ cls.admin_servers_client = cls.servers_admin_client
+
+ def _migrate_server_to(self, server_id, dest_host):
+ _resp, body = self.admin_servers_client.live_migrate_server(
+ server_id, dest_host,
+ self.config.compute_feature_enabled.
+ block_migration_for_live_migration)
+ return body
+
+ @test.attr(type=['negative', 'gate'])
+ def test_invalid_host_for_migration(self):
+ # Migrating to an invalid host should not change the status
+ target_host = data_utils.rand_name('host-')
+ _, server = self.create_test_server(wait_until="ACTIVE")
+ server_id = server['id']
+ self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
+ server_id, target_host)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 8d8e3ec..7a60196 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -16,9 +16,9 @@
import testtools
from tempest.api.compute import base
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -78,7 +78,7 @@
self.addCleanup(self._detach, server['id'], volume['id'])
@testtools.skipIf(not run_ssh, 'SSH required for this test')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
# the volume remains attached.
@@ -92,8 +92,8 @@
self.servers_client.start(server['id'])
self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
- linux_client = RemoteClient(server,
- self.image_ssh_user, server['adminPass'])
+ linux_client = remote_client.RemoteClient(server, self.image_ssh_user,
+ server['adminPass'])
partitions = linux_client.get_partitions()
self.assertIn(self.device, partitions)
@@ -106,8 +106,8 @@
self.servers_client.start(server['id'])
self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
- linux_client = RemoteClient(server,
- self.image_ssh_user, server['adminPass'])
+ linux_client = remote_client.RemoteClient(server, self.image_ssh_user,
+ server['adminPass'])
partitions = linux_client.get_partitions()
self.assertNotIn(self.device, partitions)
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index bcab891..73e3b3a 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -16,8 +16,8 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from testtools.matchers import ContainsAll
+from tempest import test
+from testtools import matchers
CONF = config.CONF
@@ -34,7 +34,7 @@
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_create_get_delete(self):
# CREATE, GET, DELETE Volume
volume = None
@@ -68,7 +68,7 @@
'The fetched Volume is different '
'from the created Volume')
self.assertThat(fetched_volume['metadata'].items(),
- ContainsAll(metadata.items()),
+ matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
'from the created Volume')
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index 898cccc..a4e6c17 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testtools.matchers import Contains
+from testtools import matchers
from tempest.api.identity import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class UsersTestJSON(base.BaseIdentityV2AdminTest):
@@ -30,7 +30,7 @@
cls.alt_password = data_utils.rand_name('pass_')
cls.alt_email = cls.alt_user + '@testmail.tm'
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_user(self):
# Create a user
self.data.setup_test_tenant()
@@ -41,7 +41,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual(self.alt_user, user['name'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_user_with_enabled(self):
# Create a user with enabled : False
self.data.setup_test_tenant()
@@ -55,7 +55,7 @@
self.assertEqual('false', str(user['enabled']).lower())
self.assertEqual(self.alt_email, user['email'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_user(self):
# Test case to check if updating of user attributes is successful.
test_user = data_utils.rand_name('test_user_')
@@ -83,7 +83,7 @@
self.assertEqual(u_email2, updated_user['email'])
self.assertEqual('false', str(updated_user['enabled']).lower())
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_delete_user(self):
# Delete a user
test_user = data_utils.rand_name('test_user_')
@@ -95,7 +95,7 @@
resp, body = self.client.delete_user(user['id'])
self.assertEqual('204', resp['status'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_user_authentication(self):
# Valid user's token is authenticated
self.data.setup_test_user()
@@ -108,7 +108,7 @@
self.data.test_tenant)
self.assertEqual('200', resp['status'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_authentication_request_without_token(self):
# Request for token authentication with a valid token in header
self.data.setup_test_user()
@@ -125,16 +125,16 @@
self.assertEqual('200', resp['status'])
self.client.auth_provider.clear_auth()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_users(self):
# Get a list of users and find the test user
self.data.setup_test_user()
resp, users = self.client.get_users()
self.assertThat([u['name'] for u in users],
- Contains(self.data.test_user),
+ matchers.Contains(self.data.test_user),
"Could not find %s" % self.data.test_user)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_users_for_tenant(self):
# Return a list of all users for a tenant
self.data.setup_test_tenant()
@@ -167,7 +167,7 @@
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_users_with_roles_for_tenant(self):
# Return list of users on tenant when roles are assigned to users
self.data.setup_test_user()
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index f309897..be03a03 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -16,7 +16,7 @@
from tempest.api.identity import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
@@ -28,7 +28,7 @@
self.assertRaises(
exceptions.NotFound, self.client.get_project, project_id)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_list_delete(self):
# Create several projects and delete them
for _ in xrange(3):
@@ -42,7 +42,7 @@
resp, get_project = self.client.get_project(project['id'])
self.assertIn(get_project, list_projects)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_with_description(self):
# Create project with a description
project_name = data_utils.rand_name('project-')
@@ -61,7 +61,7 @@
self.assertEqual(desc2, project_desc, 'Description does not appear'
'to be set')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_enabled(self):
# Create a project that is enabled
project_name = data_utils.rand_name('project-')
@@ -77,7 +77,7 @@
en2 = body['enabled']
self.assertTrue(en2, 'Enable should be True in lookup')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_create_not_enabled(self):
# Create a project that is not enabled
project_name = data_utils.rand_name('project-')
@@ -94,7 +94,7 @@
self.assertEqual('false', str(en2).lower(),
'Enable should be False in lookup')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_name(self):
# Update name attribute of a project
p_name1 = data_utils.rand_name('project-')
@@ -117,7 +117,7 @@
self.assertEqual(p_name1, resp1_name)
self.assertEqual(resp2_name, resp3_name)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_desc(self):
# Update description attribute of a project
p_name = data_utils.rand_name('project-')
@@ -142,7 +142,7 @@
self.assertEqual(p_desc, resp1_desc)
self.assertEqual(resp2_desc, resp3_desc)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_project_update_enable(self):
# Update the enabled attribute of a project
p_name = data_utils.rand_name('project-')
@@ -167,7 +167,7 @@
self.assertEqual('false', str(resp1_en).lower())
self.assertEqual(resp2_en, resp3_en)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_associate_user_to_project(self):
#Associate a user to a project
#Create a Project
@@ -196,59 +196,6 @@
new_user_get['project_id'])
self.assertEqual(u_email, new_user_get['email'])
- @attr(type=['negative', 'gate'])
- def test_list_projects_by_unauthorized_user(self):
- # Non-admin user should not be able to list projects
- self.assertRaises(exceptions.Unauthorized,
- self.non_admin_client.list_projects)
-
- @attr(type=['negative', 'gate'])
- def test_project_create_duplicate(self):
- # Project names should be unique
- project_name = data_utils.rand_name('project-dup-')
- resp, project = self.client.create_project(project_name)
- self.data.projects.append(project)
-
- self.assertRaises(
- exceptions.Conflict, self.client.create_project, project_name)
-
- @attr(type=['negative', 'gate'])
- def test_create_project_by_unauthorized_user(self):
- # Non-admin user should not be authorized to create a project
- project_name = data_utils.rand_name('project-')
- self.assertRaises(
- exceptions.Unauthorized, self.non_admin_client.create_project,
- project_name)
-
- @attr(type=['negative', 'gate'])
- def test_create_project_with_empty_name(self):
- # Project name should not be empty
- self.assertRaises(exceptions.BadRequest, self.client.create_project,
- name='')
-
- @attr(type=['negative', 'gate'])
- def test_create_projects_name_length_over_64(self):
- # Project name length should not be greater than 64 characters
- project_name = 'a' * 65
- self.assertRaises(exceptions.BadRequest, self.client.create_project,
- project_name)
-
- @attr(type=['negative', 'gate'])
- def test_project_delete_by_unauthorized_user(self):
- # Non-admin user should not be able to delete a project
- project_name = data_utils.rand_name('project-')
- resp, project = self.client.create_project(project_name)
- self.data.projects.append(project)
- self.assertRaises(
- exceptions.Unauthorized, self.non_admin_client.delete_project,
- project['id'])
-
- @attr(type=['negative', 'gate'])
- def test_delete_non_existent_project(self):
- # Attempt to delete a non existent project should fail
- self.assertRaises(exceptions.NotFound, self.client.delete_project,
- 'junk_Project_123456abc')
-
class ProjectsTestXML(ProjectsTestJSON):
_interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
new file mode 100644
index 0000000..6b60d04
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -0,0 +1,80 @@
+# Copyright 2013 OpenStack, LLC
+# 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.identity import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ _interface = 'json'
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_projects_by_unauthorized_user(self):
+ # Non-admin user should not be able to list projects
+ self.assertRaises(exceptions.Unauthorized,
+ self.non_admin_client.list_projects)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_project_create_duplicate(self):
+ # Project names should be unique
+ project_name = data_utils.rand_name('project-dup-')
+ resp, project = self.client.create_project(project_name)
+ self.data.projects.append(project)
+
+ self.assertRaises(
+ exceptions.Conflict, self.client.create_project, project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_project_by_unauthorized_user(self):
+ # Non-admin user should not be authorized to create a project
+ project_name = data_utils.rand_name('project-')
+ self.assertRaises(
+ exceptions.Unauthorized, self.non_admin_client.create_project,
+ project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_project_with_empty_name(self):
+ # Project name should not be empty
+ self.assertRaises(exceptions.BadRequest, self.client.create_project,
+ name='')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_projects_name_length_over_64(self):
+ # Project name length should not be greater than 64 characters
+ project_name = 'a' * 65
+ self.assertRaises(exceptions.BadRequest, self.client.create_project,
+ project_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_project_delete_by_unauthorized_user(self):
+ # Non-admin user should not be able to delete a project
+ project_name = data_utils.rand_name('project-')
+ resp, project = self.client.create_project(project_name)
+ self.data.projects.append(project)
+ self.assertRaises(
+ exceptions.Unauthorized, self.non_admin_client.delete_project,
+ project['id'])
+
+ @test.attr(type=['negative', 'gate'])
+ def test_delete_non_existent_project(self):
+ # Attempt to delete a non existent project should fail
+ self.assertRaises(exceptions.NotFound, self.client.delete_project,
+ data_utils.rand_uuid_hex())
+
+
+class ProjectsNegativeTestXML(ProjectsNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 802113a..9629213 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -19,7 +19,7 @@
from tempest.test import attr
-class UsersTestJSON(base.BaseIdentityV3AdminTest):
+class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
_interface = 'json'
@attr(type='smoke')
@@ -51,5 +51,5 @@
subject_token)
-class UsersTestXML(UsersTestJSON):
+class TokensV3TestXML(TokensV3TestJSON):
_interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index c2eef36..cae20ad 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -14,11 +14,11 @@
import re
from tempest.api.identity import base
from tempest import clients
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
from tempest.openstack.common import timeutils
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -49,10 +49,10 @@
self.assertIsNotNone(self.trustor_project_id)
# Create a trustor User
- self.trustor_username = rand_name('user-')
+ self.trustor_username = data_utils.rand_name('user-')
u_desc = self.trustor_username + 'description'
u_email = self.trustor_username + '@testmail.xx'
- self.trustor_password = rand_name('pass-')
+ self.trustor_password = data_utils.rand_name('pass-')
resp, user = self.client.create_user(
self.trustor_username,
description=u_desc,
@@ -63,8 +63,8 @@
self.trustor_user_id = user['id']
# And two roles, one we'll delegate and one we won't
- self.delegated_role = rand_name('DelegatedRole-')
- self.not_delegated_role = rand_name('NotDelegatedRole-')
+ self.delegated_role = data_utils.rand_name('DelegatedRole-')
+ self.not_delegated_role = data_utils.rand_name('NotDelegatedRole-')
resp, role = self.client.create_role(self.delegated_role)
self.assertEqual(resp['status'], '201')
@@ -196,7 +196,7 @@
self.create_trustor_and_roles()
self.addCleanup(self.cleanup_user_and_roles)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_trust_impersonate(self):
# Test case to check we can create, get and delete a trust
# updates are not supported for trusts
@@ -208,7 +208,7 @@
self.check_trust_roles()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_trust_noimpersonate(self):
# Test case to check we can create, get and delete a trust
# with impersonation=False
@@ -220,7 +220,7 @@
self.check_trust_roles()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_trust_expire(self):
# Test case to check we can create, get and delete a trust
# with an expiry specified
@@ -236,7 +236,7 @@
self.check_trust_roles()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_trust_expire_invalid(self):
# Test case to check we can check an invlaid expiry time
# is rejected with the correct error
@@ -246,7 +246,7 @@
self.create_trust,
expires=expires_str)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_trusts_query(self):
self.create_trust()
resp, trusts_get = self.trustor_client.get_trusts(
@@ -255,7 +255,7 @@
self.assertEqual(1, len(trusts_get))
self.validate_trust(trusts_get[0], summary=True)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_trusts_all(self):
self.create_trust()
resp, trusts_get = self.client.get_trusts()
diff --git a/tempest/api/network/admin/test_lbaas_agent_scheduler.py b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
new file mode 100644
index 0000000..a5ba90f
--- /dev/null
+++ b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
@@ -0,0 +1,78 @@
+# Copyright 2013 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.
+
+from tempest.api.network import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class LBaaSAgentSchedulerTestJSON(base.BaseAdminNetworkTest):
+ _interface = 'json'
+
+ """
+ Tests the following operations in the Neutron API using the REST client for
+ Neutron:
+
+ List pools the given LBaaS agent is hosting.
+ Show a LBaaS agent hosting the given pool.
+
+ v2.0 of the Neutron API is assumed. It is also assumed that the following
+ options are defined in the [networki-feature-enabled] section of
+ etc/tempest.conf:
+
+ api_extensions
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(LBaaSAgentSchedulerTestJSON, cls).setUpClass()
+ if not test.is_extension_enabled('lbaas_agent_scheduler', 'network'):
+ msg = "LBaaS Agent Scheduler Extension not enabled."
+ raise cls.skipException(msg)
+ cls.network = cls.create_network()
+ cls.subnet = cls.create_subnet(cls.network)
+ pool_name = data_utils.rand_name('pool-')
+ cls.pool = cls.create_pool(pool_name, "ROUND_ROBIN",
+ "HTTP", cls.subnet)
+
+ @test.attr(type='smoke')
+ def test_list_pools_on_lbaas_agent(self):
+ found = False
+ resp, body = self.admin_client.list_agents(
+ agent_type="Loadbalancer agent")
+ self.assertEqual('200', resp['status'])
+ agents = body['agents']
+ for a in agents:
+ msg = 'Load Balancer agent expected'
+ self.assertEqual(a['agent_type'], 'Loadbalancer agent', msg)
+ resp, body = (
+ self.admin_client.list_pools_hosted_by_one_lbaas_agent(
+ a['id']))
+ self.assertEqual('200', resp['status'])
+ pools = body['pools']
+ if self.pool['id'] in [p['id'] for p in pools]:
+ found = True
+ msg = 'Unable to find Load Balancer agent hosting pool'
+ self.assertTrue(found, msg)
+
+ @test.attr(type='smoke')
+ def test_show_lbaas_agent_hosting_pool(self):
+ resp, body = self.admin_client.show_lbaas_agent_hosting_pool(
+ self.pool['id'])
+ self.assertEqual('200', resp['status'])
+ self.assertEqual('Loadbalancer agent', body['agent']['agent_type'])
+
+
+class LBaaSAgentSchedulerTestXML(LBaaSAgentSchedulerTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py
index 38ae4ac..90be454 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -26,7 +26,7 @@
def _create_security_group(self):
# Create a security group
name = data_utils.rand_name('secgroup-')
- resp, group_create_body = self.client.create_security_group(name)
+ resp, group_create_body = self.client.create_security_group(name=name)
self.assertEqual('201', resp['status'])
self.addCleanup(self._delete_security_group,
group_create_body['security_group']['id'])
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
new file mode 100644
index 0000000..ed86d75
--- /dev/null
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -0,0 +1,99 @@
+# Copyright 2013 OpenStack Foundation
+# 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.network import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class ExtraDHCPOptionsTestJSON(base.BaseNetworkTest):
+ _interface = 'json'
+
+ """
+ Tests the following operations with the Extra DHCP Options Neutron API
+ extension:
+
+ port create
+ port list
+ port show
+ port update
+
+ v2.0 of the Neutron API is assumed. It is also assumed that the Extra
+ DHCP Options extension is enabled in the [network-feature-enabled]
+ section of etc/tempest.conf
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(ExtraDHCPOptionsTestJSON, cls).setUpClass()
+ if not test.is_extension_enabled('extra_dhcp_opt', 'network'):
+ msg = "Extra DHCP Options extension not enabled."
+ raise cls.skipException(msg)
+ cls.network = cls.create_network()
+ cls.subnet = cls.create_subnet(cls.network)
+ cls.port = cls.create_port(cls.network)
+
+ @test.attr(type='smoke')
+ def test_create_list_port_with_extra_dhcp_options(self):
+ # Create a port with Extra DHCP Options
+ extra_dhcp_opts = [
+ {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
+ {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
+ {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
+ ]
+ resp, body = self.client.create_port(
+ network_id=self.network['id'],
+ extra_dhcp_opts=extra_dhcp_opts)
+ self.assertEqual('201', resp['status'])
+ port_id = body['port']['id']
+ self.addCleanup(self.client.delete_port, port_id)
+
+ # Confirm port created has Extra DHCP Options
+ resp, body = self.client.list_ports()
+ self.assertEqual('200', resp['status'])
+ ports = body['ports']
+ port = [p for p in ports if p['id'] == port_id]
+ self.assertTrue(port)
+ self._confirm_extra_dhcp_options(port[0], extra_dhcp_opts)
+
+ @test.attr(type='smoke')
+ def test_update_show_port_with_extra_dhcp_options(self):
+ # Update port with extra dhcp options
+ extra_dhcp_opts = [
+ {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
+ {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
+ {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
+ ]
+ name = data_utils.rand_name('new-port-name')
+ resp, body = self.client.update_port(
+ self.port['id'], name=name, extra_dhcp_opts=extra_dhcp_opts)
+ self.assertEqual('200', resp['status'])
+
+ # Confirm extra dhcp options were added to the port
+ resp, body = self.client.show_port(self.port['id'])
+ self.assertEqual('200', resp['status'])
+ self._confirm_extra_dhcp_options(body['port'], extra_dhcp_opts)
+
+ def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts):
+ retrieved = port['extra_dhcp_opts']
+ self.assertEqual(len(retrieved), len(extra_dhcp_opts))
+ for retrieved_option in retrieved:
+ for option in extra_dhcp_opts:
+ if (retrieved_option['opt_value'] == option['opt_value'] and
+ retrieved_option['opt_name'] == option['opt_name']):
+ break
+ else:
+ self.fail('Extra DHCP option not found in port %s' %
+ str(retrieved_option))
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index 53541ed..03e095d 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -221,6 +221,17 @@
(self.health_monitor['id'], self.pool['id']))
self.assertEqual('204', resp['status'])
+ @test.attr(type='smoke')
+ def test_get_lb_pool_stats(self):
+ # Verify the details of pool stats
+ resp, body = self.client.list_lb_pool_stats(self.pool['id'])
+ self.assertEqual('200', resp['status'])
+ stats = body['stats']
+ self.assertIn("bytes_in", stats)
+ self.assertIn("total_connections", stats)
+ self.assertIn("active_connections", stats)
+ self.assertIn("bytes_out", stats)
+
class LoadBalancerTestXML(LoadBalancerTestJSON):
_interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 4cc007f..aba2c8e 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -266,6 +266,28 @@
self.assertIsNotNone(found, "Port list doesn't contain created port")
@attr(type='smoke')
+ def test_port_list_filter_by_router_id(self):
+ # Create a router
+ network = self.create_network()
+ self.create_subnet(network)
+ router = self.create_router(data_utils.rand_name('router-'))
+ resp, port = self.client.create_port(
+ network_id=network['id'])
+ # Add router interface to port created above
+ resp, interface = self.client.add_router_interface_with_port_id(
+ router['id'], port['port']['id'])
+ self.addCleanup(self.client.remove_router_interface_with_port_id,
+ router['id'], port['port']['id'])
+ # list ports filtered by router_id
+ resp, port_list = self.client.list_ports(
+ device_id=router['id'])
+ self.assertEqual('200', resp['status'])
+ # Verify if only corresponding port is listed and assert router_id
+ self.assertEqual(len(port_list['ports']), 1)
+ self.assertEqual(port['port']['id'], port_list['ports'][0]['id'])
+ self.assertEqual(router['id'], port_list['ports'][0]['device_id'])
+
+ @attr(type='smoke')
def test_list_ports_fields(self):
# Verify listing some fields of the ports
resp, body = self.client.list_ports(fields='id')
@@ -445,6 +467,14 @@
_tenant_network_cidr = CONF.network.tenant_network_v6_cidr
_tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
+ @classmethod
+ def setUpClass(cls):
+ super(NetworksIpV6TestJSON, cls).setUpClass()
+ if not CONF.network.ipv6_enabled:
+ cls.tearDownClass()
+ skip_msg = "IPv6 Tests are disabled."
+ raise cls.skipException(skip_msg)
+
class NetworksIpV6TestXML(NetworksIpV6TestJSON):
_interface = 'xml'
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d552c70..0ff91ab 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -16,6 +16,7 @@
import netaddr
from tempest.api.network import base_routers as base
+from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -32,6 +33,8 @@
if not test.is_extension_enabled('router', 'network'):
msg = "router extension not enabled."
raise cls.skipException(msg)
+ admin_manager = clients.AdminManager()
+ cls.identity_admin_client = admin_manager.identity_client
@test.attr(type='smoke')
def test_create_show_list_update_delete_router(self):
@@ -77,6 +80,25 @@
self.assertEqual(show_body['router']['name'], updated_name)
@test.attr(type='smoke')
+ def test_create_router_setting_tenant_id(self):
+ # Test creating router from admin user setting tenant_id.
+ test_tenant = data_utils.rand_name('test_tenant_')
+ test_description = data_utils.rand_name('desc_')
+ _, tenant = self.identity_admin_client.create_tenant(
+ name=test_tenant,
+ description=test_description)
+ tenant_id = tenant['id']
+ self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+
+ name = data_utils.rand_name('router-')
+ resp, create_body = self.admin_client.create_router(
+ name, tenant_id=tenant_id)
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self.admin_client.delete_router,
+ create_body['router']['id'])
+ self.assertEqual(tenant_id, create_body['router']['tenant_id'])
+
+ @test.attr(type='smoke')
def test_add_remove_router_interface_with_subnet_id(self):
network = self.create_network()
subnet = self.create_subnet(network)
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 6eebf5b..1d41cc9 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -66,8 +66,9 @@
protocols = ['tcp', 'udp', 'icmp']
for protocol in protocols:
resp, rule_create_body = self.client.create_security_group_rule(
- group_create_body['security_group']['id'],
- protocol=protocol
+ security_group_id=group_create_body['security_group']['id'],
+ protocol=protocol,
+ direction='ingress'
)
self.assertEqual('201', resp['status'])
self.addCleanup(self._delete_security_group_rule,
@@ -99,7 +100,7 @@
port_range_min = 77
port_range_max = 77
resp, rule_create_body = self.client.create_security_group_rule(
- group_create_body['security_group']['id'],
+ security_group_id=group_create_body['security_group']['id'],
direction=direction,
protocol=protocol,
port_range_min=port_range_min,
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index e1f4055..0b86398 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -57,10 +57,10 @@
#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)
+ self.assertRaises(
+ exceptions.BadRequest, self.client.create_security_group_rule,
+ security_group_id=group_create_body['security_group']['id'],
+ protocol=pname, direction='ingress')
@test.attr(type=['negative', 'gate'])
def test_create_security_group_rule_with_invalid_ports(self):
@@ -72,12 +72,11 @@
(80, 65536, 'Invalid value for port 65536'),
(-16, 65536, 'Invalid value for port')]
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)
+ ex = self.assertRaises(
+ exceptions.BadRequest, self.client.create_security_group_rule,
+ security_group_id=group_create_body['security_group']['id'],
+ protocol='tcp', port_range_min=pmin, port_range_max=pmax,
+ direction='ingress')
self.assertIn(msg, str(ex))
@test.attr(type=['negative', 'smoke'])
@@ -86,7 +85,7 @@
name = 'default'
self.assertRaises(exceptions.Conflict,
self.client.create_security_group,
- name)
+ name=name)
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_non_existent_security_group(self):
@@ -94,7 +93,8 @@
non_existent_sg = str(uuid.uuid4())
self.assertRaises(exceptions.NotFound,
self.client.create_security_group_rule,
- non_existent_sg)
+ security_group_id=non_existent_sg,
+ direction='ingress')
class NegativeSecGroupTestXML(NegativeSecGroupTest):
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index ef36c3d..45c895b 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -14,7 +14,7 @@
# under the License.
-from tempest.api.identity.base import DataGenerator
+from tempest.api.identity import base
from tempest import clients
from tempest.common import custom_matchers
from tempest.common import isolated_creds
@@ -83,7 +83,7 @@
cls.object_client_alt.auth_provider.clear_auth()
cls.container_client_alt.auth_provider.clear_auth()
- cls.data = DataGenerator(cls.identity_admin_client)
+ cls.data = base.DataGenerator(cls.identity_admin_client)
@classmethod
def tearDownClass(cls):
@@ -130,7 +130,10 @@
objlist = container_client.list_all_container_objects(cont)
# delete every object in the container
for obj in objlist:
- object_client.delete_object(cont, obj['name'])
+ try:
+ object_client.delete_object(cont, obj['name'])
+ except exceptions.NotFound:
+ pass
container_client.delete_container(cont)
except exceptions.NotFound:
pass
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 5fde76a..a94c883 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -1,5 +1,3 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
# Copyright 2013 NTT Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 79fd99d..5456768 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -18,8 +18,7 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class AccountTest(base.BaseObjectTest):
@@ -38,7 +37,7 @@
cls.delete_containers(cls.containers)
super(AccountTest, cls).tearDownClass()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_containers(self):
# list of all containers should not be empty
params = {'format': 'json'}
@@ -51,14 +50,14 @@
for container_name in self.containers:
self.assertIn(container_name, container_names)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_extensions(self):
resp, extensions = self.account_client.list_extensions()
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_containers_with_limit(self):
# list containers one of them, half of them then all of them
for limit in (1, self.containers_count / 2, self.containers_count):
@@ -69,7 +68,7 @@
self.assertEqual(len(container_list), limit)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_containers_with_marker(self):
# list containers using marker param
# first expect to get 0 container as we specified last
@@ -89,7 +88,7 @@
self.assertEqual(len(container_list), self.containers_count / 2 - 1)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_containers_with_end_marker(self):
# list containers using end_marker param
# first expect to get 0 container as we specified first container as
@@ -107,7 +106,7 @@
self.assertHeaders(resp, 'Account', 'GET')
self.assertEqual(len(container_list), self.containers_count / 2)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_containers_with_limit_and_marker(self):
# list containers combining marker and limit param
# result are always limitated by the limit whatever the marker
@@ -121,21 +120,21 @@
self.assertTrue(len(container_list) <= limit, str(container_list))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_account_metadata(self):
# list all account metadata
resp, metadata = self.account_client.list_account_metadata()
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'HEAD')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_and_delete_account_metadata(self):
header = 'test-account-meta'
data = 'Meta!'
# add metadata to account
resp, _ = self.account_client.create_account_metadata(
metadata={header: data})
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
@@ -147,7 +146,7 @@
# delete metadata from account
resp, _ = \
self.account_client.delete_account_metadata(metadata=[header])
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index aae6b4d..085ef51 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -16,8 +16,7 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class ObjectTestACLs(base.BaseObjectTest):
@@ -44,7 +43,7 @@
self.delete_containers([self.container_name])
super(ObjectTestACLs, self).tearDown()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_read_object_with_rights(self):
# attempt to read object using authorized user
# update X-Container-Read metadata ACL
@@ -53,7 +52,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@@ -68,10 +67,10 @@
)
resp, _ = self.custom_object_client.get_object(
self.container_name, object_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_write_object_with_rights(self):
# attempt to write object using authorized user
# update X-Container-Write metadata ACL
@@ -80,7 +79,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object with rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -91,5 +90,5 @@
resp, _ = self.custom_object_client.create_object(
self.container_name,
object_name, 'data')
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 1dc9bb5..a5a0950 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -18,8 +18,7 @@
from tempest import clients
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class ObjectACLsNegativeTest(base.BaseObjectTest):
@@ -46,7 +45,7 @@
self.delete_containers([self.container_name])
super(ObjectACLsNegativeTest, self).tearDown()
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_write_object_without_using_creds(self):
# trying to create object with empty headers
# X-Auth-Token is not provided
@@ -59,7 +58,7 @@
self.custom_object_client.create_object,
self.container_name, object_name, 'data')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_object_without_using_creds(self):
# create object
object_name = data_utils.rand_name(name='Object')
@@ -75,7 +74,7 @@
self.custom_object_client.delete_object,
self.container_name, object_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_write_object_with_non_authorized_user(self):
# attempt to upload another file using non-authorized user
# User provided token is forbidden. ACL are not set
@@ -89,7 +88,7 @@
self.custom_object_client.create_object,
self.container_name, object_name, 'data')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_read_object_with_non_authorized_user(self):
# attempt to read object using non-authorized user
# User provided token is forbidden. ACL are not set
@@ -107,7 +106,7 @@
self.custom_object_client.get_object,
self.container_name, object_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_object_with_non_authorized_user(self):
# attempt to delete object using non-authorized user
# User provided token is forbidden. ACL are not set
@@ -125,7 +124,7 @@
self.custom_object_client.delete_object,
self.container_name, object_name)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_read_object_without_rights(self):
# attempt to read object using non-authorized user
# update X-Container-Read metadata ACL
@@ -133,7 +132,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@@ -150,7 +149,7 @@
self.custom_object_client.get_object,
self.container_name, object_name)
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_write_object_without_rights(self):
# attempt to write object using non-authorized user
# update X-Container-Write metadata ACL
@@ -158,7 +157,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -171,7 +170,7 @@
self.container_name,
object_name, 'data')
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_write_object_without_write_rights(self):
# attempt to write object using non-authorized user
# update X-Container-Read and X-Container-Write metadata ACL
@@ -181,7 +180,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without write rights
self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -194,7 +193,7 @@
self.container_name,
object_name, 'data')
- @attr(type=['negative', 'smoke'])
+ @test.attr(type=['negative', 'smoke'])
def test_delete_object_without_write_rights(self):
# attempt to delete object using non-authorized user
# update X-Container-Read and X-Container-Write metadata ACL
@@ -204,7 +203,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 84cc91e..8689d10 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -15,8 +15,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class ContainerTest(base.BaseObjectTest):
@@ -47,7 +46,7 @@
return object_name
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container(self):
container_name = data_utils.rand_name(name='TestContainer')
resp, body = self.container_client.create_container(container_name)
@@ -55,7 +54,7 @@
self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container_overwrite(self):
# overwrite container with the same name
container_name = data_utils.rand_name(name='TestContainer')
@@ -66,7 +65,7 @@
self.assertIn(resp['status'], ('202', '201'))
self.assertHeaders(resp, 'Container', 'PUT')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container_with_metadata_key(self):
# create container with the blank value of metadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -84,7 +83,7 @@
# in the server
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container_with_metadata_value(self):
# create container with metadata value
container_name = data_utils.rand_name(name='TestContainer')
@@ -103,7 +102,7 @@
self.assertEqual(resp['x-container-meta-test-container-meta'],
metadata['test-container-meta'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container_with_remove_metadata_key(self):
# create container with the blank value of remove metadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -124,7 +123,7 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_container_with_remove_metadata_value(self):
# create container with remove metadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -143,18 +142,18 @@
container_name)
self.assertNotIn('x-container-meta-test-container-meta', resp)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_delete_container(self):
# create a container
container_name = self._create_container()
# delete container
resp, _ = self.container_client.delete_container(container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'DELETE')
self.containers.remove(container_name)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents(self):
# get container contents list
container_name = self._create_container()
@@ -162,22 +161,22 @@
resp, object_list = self.container_client.list_container_contents(
container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_no_object(self):
# get empty container contents list
container_name = self._create_container()
resp, object_list = self.container_client.list_container_contents(
container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual('', object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_delimiter(self):
# get container contents list using delimiter param
container_name = self._create_container()
@@ -188,11 +187,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_end_marker(self):
# get container contents list using end_marker param
container_name = self._create_container()
@@ -202,11 +201,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_format_json(self):
# get container contents list using format_json param
container_name = self._create_container()
@@ -216,7 +215,7 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertIsNotNone(object_list)
@@ -226,7 +225,7 @@
self.assertTrue([c['content_type'] for c in object_list])
self.assertTrue([c['last_modified'] for c in object_list])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_format_xml(self):
# get container contents list using format_xml param
container_name = self._create_container()
@@ -236,7 +235,7 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertIsNotNone(object_list)
@@ -251,7 +250,7 @@
self.assertEqual(object_list.find(".//last_modified").tag,
'last_modified')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_limit(self):
# get container contents list using limit param
container_name = self._create_container()
@@ -261,11 +260,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_marker(self):
# get container contents list using marker param
container_name = self._create_container()
@@ -275,11 +274,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_path(self):
# get container contents list using path param
container_name = self._create_container()
@@ -290,11 +289,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_contents_with_prefix(self):
# get container contents list using prefix param
container_name = self._create_container()
@@ -305,11 +304,11 @@
resp, object_list = self.container_client.list_container_contents(
container_name,
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'GET')
self.assertEqual(object_name, object_list.strip('\n'))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_container_metadata(self):
# List container metadata
container_name = self._create_container()
@@ -321,23 +320,23 @@
resp, _ = self.container_client.list_container_metadata(
container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertIn('x-container-meta-name', resp)
self.assertEqual(resp['x-container-meta-name'], metadata['name'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_list_no_container_metadata(self):
# HEAD container without metadata
container_name = self._create_container()
resp, _ = self.container_client.list_container_metadata(
container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertNotIn('x-container-meta-', str(resp))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_container_metadata_with_create_and_delete_matadata(self):
# Send one request of adding and deleting metadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -351,7 +350,7 @@
container_name,
metadata=metadata_2,
remove_metadata=metadata_1)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -361,7 +360,7 @@
self.assertEqual(resp['x-container-meta-test-container-meta2'],
metadata_2['test-container-meta2'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_container_metadata_with_create_metadata(self):
# update container metadata using add metadata
container_name = self._create_container()
@@ -370,7 +369,7 @@
resp, _ = self.container_client.update_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@@ -379,7 +378,7 @@
self.assertEqual(resp['x-container-meta-test-container-meta1'],
metadata['test-container-meta1'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_container_metadata_with_delete_metadata(self):
# update container metadata using delete metadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -391,14 +390,14 @@
resp, _ = self.container_client.delete_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
container_name)
self.assertNotIn('x-container-meta-test-container-meta1', resp)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_container_metadata_with_create_matadata_key(self):
# update container metadata with a blenk value of metadata
container_name = self._create_container()
@@ -407,14 +406,14 @@
resp, _ = self.container_client.update_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
container_name)
self.assertNotIn('x-container-meta-test-container-meta1', resp)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_update_container_metadata_with_delete_metadata_key(self):
# update container metadata with a blank value of matadata
container_name = data_utils.rand_name(name='TestContainer')
@@ -427,7 +426,7 @@
resp, _ = self.container_client.delete_container_metadata(
container_name,
metadata=metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(container_name)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 197e7fa..6c71340 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -49,6 +49,7 @@
cls.data.teardown_all()
super(StaticWebTest, cls).tearDownClass()
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_index(self):
headers = {'web-index': self.object_name}
@@ -79,6 +80,7 @@
self.container_name)
self.assertNotIn('x-container-meta-web-index', body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_listing(self):
headers = {'web-listings': 'true'}
@@ -110,6 +112,7 @@
self.container_name)
self.assertNotIn('x-container-meta-web-listings', body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_listing_css(self):
headers = {'web-listings': 'true',
@@ -133,6 +136,7 @@
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
self.assertIn(css, body)
+ @test.requires_ext(extension='staticweb', service='object')
@test.attr('gate')
def test_web_error(self):
headers = {'web-listings': 'true',
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 207fced..9bd986f 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -19,8 +19,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
CONF = config.CONF
@@ -66,7 +65,7 @@
cls.delete_containers(cls.containers, client[0], client[1])
super(ContainerSyncTest, cls).tearDownClass()
- @attr(type='slow')
+ @test.attr(type='slow')
def test_container_synchronization(self):
# container to container synchronization
# to allow/accept sync requests to/from other accounts
@@ -86,12 +85,12 @@
(client_base_url, str(cont[1]))}
resp, body = \
cont_client[0].put(str(cont[0]), body=None, headers=headers)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# create object in container
object_name = data_utils.rand_name(name='TestSyncObject')
data = object_name[::-1] # data_utils.arbitrary_string()
resp, _ = obj_client[0].create_object(cont[0], object_name, data)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.objects.append(object_name)
# wait until container contents list is not empty
@@ -104,7 +103,7 @@
cont_client[client_index].\
list_container_contents(self.containers[client_index],
params=params)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
object_lists.append(dict(
(obj['name'], obj) for obj in object_list))
# check that containers are not empty and have equal keys()
@@ -124,5 +123,5 @@
for obj_client, cont in obj_clients:
for obj_name in object_lists[0]:
resp, object_content = obj_client.get_object(cont, obj_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertEqual(object_content, obj_name[::-1])
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index 35aee2a..e27c7ef 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -17,8 +17,7 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class HealthcheckTest(base.BaseObjectTest):
@@ -32,13 +31,13 @@
# Turning http://.../v1/foobar into http://.../
self.account_client.skip_path()
- @attr('gate')
+ @test.attr('gate')
def test_get_healthcheck(self):
resp, _ = self.account_client.get("healthcheck", {})
# The status is expected to be 200
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
# The target of the request is not any Swift resource. Therefore, the
# existence of response header is checked without a custom matcher.
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 3aae0a1..53ca20d 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -18,7 +18,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ObjectExpiryTest(base.BaseObjectTest):
@@ -67,12 +67,12 @@
self.assertRaises(exceptions.NotFound, self.object_client.get_object,
self.container_name, self.object_name)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_object_after_expiry_time(self):
metadata = {'X-Delete-After': '3'}
self._test_object_expiry(metadata)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_object_at_expiry_time(self):
metadata = {'X-Delete-At': str(int(time.time()) + 3)}
self._test_object_expiry(metadata)
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 6f46ec9..e0d15ac 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -21,8 +21,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class ObjectFormPostTest(base.BaseObjectTest):
@@ -93,7 +92,8 @@
content_type = 'multipart/form-data; boundary=%s' % boundary
return body, content_type
- @attr(type='gate')
+ @test.requires_ext(extension='formpost', service='object')
+ @test.attr(type='gate')
def test_post_object_using_form(self):
body, content_type = self.get_multipart_form()
@@ -107,12 +107,12 @@
# Use a raw request, otherwise authentication headers are used
resp, body = self.object_client.http_obj.request(url, "POST",
body, headers=headers)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, "Object", "POST")
# Ensure object is available
resp, body = self.object_client.get("%s/%s%s" % (
self.container_name, self.object_name, "testfile"))
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, "Object", "GET")
self.assertEqual(body, "hello world")
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index e02a058..a52c248 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -20,7 +20,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class ObjectFormPostNegativeTest(base.BaseObjectTest):
@@ -91,7 +91,8 @@
content_type = 'multipart/form-data; boundary=%s' % boundary
return body, content_type
- @attr(type=['gate', 'negative'])
+ @test.requires_ext(extension='formpost', service='object')
+ @test.attr(type=['gate', 'negative'])
def test_post_object_using_form_expired(self):
body, content_type = self.get_multipart_form(expires=1)
time.sleep(2)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 6f349b6..33f3299 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -18,8 +18,7 @@
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import HTTP_SUCCESS
+from tempest import test
class ObjectTest(base.BaseObjectTest):
@@ -35,7 +34,7 @@
cls.delete_containers(cls.containers)
super(ObjectTest, cls).tearDownClass()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
@@ -50,7 +49,7 @@
self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'PUT')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_delete_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
@@ -60,10 +59,10 @@
# delete object
resp, _ = self.object_client.delete_object(self.container_name,
object_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'DELETE')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_object_metadata(self):
# add metadata to storage object, test if metadata is retrievable
@@ -78,20 +77,20 @@
orig_metadata = {meta_key: meta_value}
resp, _ = self.object_client.update_object_metadata(
self.container_name, object_name, orig_metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
# get object metadata
resp, resp_metadata = self.object_client.list_object_metadata(
self.container_name, object_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'HEAD')
actual_meta_key = 'x-object-meta-' + meta_key
self.assertIn(actual_meta_key, resp)
self.assertEqual(resp[actual_meta_key], meta_value)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_object(self):
# retrieve object's data (in response body)
@@ -103,12 +102,12 @@
# get object
resp, body = self.object_client.get_object(self.container_name,
object_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
self.assertEqual(body, data)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_copy_object_in_same_container(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
@@ -135,7 +134,7 @@
dst_object_name)
self.assertEqual(body, src_data)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_copy_object_to_itself(self):
# change the content type of an existing object
@@ -160,7 +159,7 @@
object_name)
self.assertEqual(resp['content-type'], metadata['content-type'])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_copy_object_2d_way(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
@@ -195,7 +194,7 @@
dst_object_name)
self.assertEqual(body, src_data)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_copy_object_across_containers(self):
# create a container to use as asource container
src_container_name = data_utils.rand_name(name='TestSourceContainer')
@@ -219,7 +218,7 @@
resp, _ = self.object_client.update_object_metadata(src_container_name,
object_name,
orig_metadata)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'POST')
# copy object from source container to destination container
@@ -237,7 +236,7 @@
self.assertIn(actual_meta_key, resp)
self.assertEqual(resp[actual_meta_key], meta_value)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_object_upload_in_segments(self):
# create object
object_name = data_utils.rand_name(name='LObject')
@@ -280,7 +279,7 @@
self.container_name, object_name)
self.assertEqual(''.join(data_segments), body)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_object_if_different(self):
# http://en.wikipedia.org/wiki/HTTP_ETag
# Make a conditional request for an object using the If-None-Match
@@ -312,7 +311,7 @@
md5 = hashlib.md5(local_data).hexdigest()
headers = {'If-None-Match': md5}
resp, body = self.object_client.get(url, headers=headers)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Object', 'GET')
@@ -326,7 +325,7 @@
self.delete_containers([self.container_name])
super(PublicObjectTest, self).tearDown()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_access_public_container_object_without_using_creds(self):
# make container public-readable and access an object in it object
# anonymously, without using credentials
@@ -335,7 +334,7 @@
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers, metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
@@ -350,7 +349,7 @@
# list container metadata
resp_meta, _ = self.container_client.list_container_metadata(
self.container_name)
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'HEAD')
self.assertIn('x-container-read', resp_meta)
@@ -367,7 +366,7 @@
self.assertEqual(body, data)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_access_public_object_with_another_user_creds(self):
# make container public-readable and access an object in it using
# another user's credentials
@@ -375,7 +374,7 @@
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
- self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
@@ -390,7 +389,7 @@
# list container metadata
resp, _ = self.container_client.list_container_metadata(
self.container_name)
- self.assertIn(int(resp['status']), HTTP_SUCCESS)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Container', 'HEAD')
self.assertIn('x-container-read', resp)
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 75293d2..8d2ff9b 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -15,7 +15,7 @@
from tempest.api.object_storage import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class ContainerTest(base.BaseObjectTest):
@@ -40,7 +40,7 @@
header_value = resp.get('x-versions-location', 'Missing Header')
self.assertEqual(header_value, versioned)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_versioned_container(self):
# create container
vers_container_name = data_utils.rand_name(name='TestVersionContainer')
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 243c3ce..3e621f4 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -17,6 +17,7 @@
from tempest import clients
from tempest.common.utils import data_utils
from tempest import config
+from tempest import exceptions
from tempest.test import attr
CONF = config.CONF
@@ -28,25 +29,28 @@
_interface = 'json'
template = """
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
+heat_template_version: '2013-05-23'
+description: |
Template which creates single EC2 instance
-Parameters:
+parameters:
KeyName:
- Type: String
+ type: string
InstanceType:
- Type: String
+ type: string
ImageId:
- Type: String
+ type: string
ExternalRouterId:
- Type: String
-Resources:
+ type: string
+ ExternalNetworkId:
+ type: string
+resources:
Network:
- Type: OS::Quantum::Net
- Properties: {name: NewNetwork}
+ type: OS::Neutron::Net
+ properties:
+ name: NewNetwork
Subnet:
- Type: OS::Quantum::Subnet
- Properties:
+ type: OS::Neutron::Subnet
+ properties:
network_id: {Ref: Network}
name: NewSubnet
ip_version: 4
@@ -54,39 +58,44 @@
dns_nameservers: ["8.8.8.8"]
allocation_pools:
- {end: 10.0.3.150, start: 10.0.3.20}
+ Router:
+ type: OS::Neutron::Router
+ properties:
+ name: NewRouter
+ admin_state_up: false
+ external_gateway_info:
+ network: {get_param: ExternalNetworkId}
+ enable_snat: false
RouterInterface:
- Type: OS::Quantum::RouterInterface
- Properties:
- router_id: {Ref: ExternalRouterId}
- subnet_id: {Ref: Subnet}
+ type: OS::Neutron::RouterInterface
+ properties:
+ router_id: {get_param: ExternalRouterId}
+ subnet_id: {get_resource: Subnet}
Server:
- Type: AWS::EC2::Instance
+ type: AWS::EC2::Instance
Metadata:
- Name: SmokeServer
- Properties:
- ImageId: {Ref: ImageId}
- InstanceType: {Ref: InstanceType}
- KeyName: {Ref: KeyName}
- SubnetId: {Ref: Subnet}
+ Name: SmokeServerNeutron
+ properties:
+ ImageId: {get_param: ImageId}
+ InstanceType: {get_param: InstanceType}
+ KeyName: {get_param: KeyName}
+ SubnetId: {get_resource: Subnet}
UserData:
- Fn::Base64:
- Fn::Join:
- - ''
- - - '#!/bin/bash -v
+ str_replace:
+ template: |
+ #!/bin/bash -v
- '
- - /opt/aws/bin/cfn-signal -e 0 -r "SmokeServer created" '
- - {Ref: WaitHandle}
- - '''
-
- '
- WaitHandle:
- Type: AWS::CloudFormation::WaitConditionHandle
+ /opt/aws/bin/cfn-signal -e 0 -r "SmokeServerNeutron created" \
+ 'wait_handle'
+ params:
+ wait_handle: {get_resource: WaitHandleNeutron}
+ WaitHandleNeutron:
+ type: AWS::CloudFormation::WaitConditionHandle
WaitCondition:
- Type: AWS::CloudFormation::WaitCondition
+ type: AWS::CloudFormation::WaitCondition
DependsOn: Server
- Properties:
- Handle: {Ref: WaitHandle}
+ properties:
+ Handle: {get_resource: WaitHandleNeutron}
Timeout: '600'
"""
@@ -104,6 +113,7 @@
cls.keypair_name = (CONF.orchestration.keypair_name or
cls._create_keypair()['name'])
cls.external_router_id = cls._get_external_router_id()
+ cls.external_network_id = CONF.network.public_network_id
# create the stack
cls.stack_identifier = cls.create_stack(
@@ -113,11 +123,26 @@
'KeyName': cls.keypair_name,
'InstanceType': CONF.orchestration.instance_type,
'ImageId': CONF.orchestration.image_ref,
- 'ExternalRouterId': cls.external_router_id
+ 'ExternalRouterId': cls.external_router_id,
+ 'ExternalNetworkId': cls.external_network_id
})
cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- _, resources = cls.client.list_resources(cls.stack_identifier)
+ try:
+ cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
+ _, resources = cls.client.list_resources(cls.stack_identifier)
+ except exceptions.TimeoutException as e:
+ # attempt to log the server console to help with debugging
+ # the cause of the server not signalling the waitcondition
+ # to heat.
+ resp, body = cls.client.get_resource(cls.stack_identifier,
+ 'SmokeServerNeutron')
+ server_id = body['physical_resource_id']
+ LOG.debug('Console output for %s', server_id)
+ resp, output = cls.servers_client.get_console_output(
+ server_id, None)
+ LOG.debug(output)
+ raise e
+
cls.test_resources = {}
for resource in resources:
cls.test_resources[resource['logical_resource_id']] = resource
@@ -133,9 +158,9 @@
@attr(type='slow')
def test_created_resources(self):
"""Verifies created neutron resources."""
- resources = [('Network', 'OS::Quantum::Net'),
- ('Subnet', 'OS::Quantum::Subnet'),
- ('RouterInterface', 'OS::Quantum::RouterInterface'),
+ resources = [('Network', 'OS::Neutron::Net'),
+ ('Subnet', 'OS::Neutron::Subnet'),
+ ('RouterInterface', 'OS::Neutron::RouterInterface'),
('Server', 'AWS::EC2::Instance')]
for resource_name, resource_type in resources:
resource = self.test_resources.get(resource_name, None)
@@ -173,6 +198,20 @@
self.assertEqual('10.0.3.0/24', subnet['cidr'])
@attr(type='slow')
+ def test_created_router(self):
+ """Verifies created router."""
+ router_id = self.test_resources.get('Router')['physical_resource_id']
+ resp, body = self.network_client.show_router(router_id)
+ self.assertEqual('200', resp['status'])
+ router = body['router']
+ self.assertEqual('NewRouter', router['name'])
+ self.assertEqual(self.external_network_id,
+ router['external_gateway_info']['network_id'])
+ self.assertEqual(False,
+ router['external_gateway_info']['enable_snat'])
+ self.assertEqual(False, router['admin_state_up'])
+
+ @attr(type='slow')
def test_created_router_interface(self):
"""Verifies created router interface."""
network_id = self.test_resources.get('Network')['physical_resource_id']
diff --git a/tempest/api/orchestration/stacks/test_server_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
index 4267c1d..5130f87 100644
--- a/tempest/api/orchestration/stacks/test_server_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -15,10 +15,10 @@
from tempest.api.orchestration import base
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -147,7 +147,7 @@
'network': cls._get_default_network()['id']
})
- @attr(type='slow')
+ @test.attr(type='slow')
@testtools.skipIf(existing_keypair, 'Server ssh tests are disabled.')
def test_can_log_into_created_server(self):
@@ -166,11 +166,12 @@
body['physical_resource_id'])
# Check that the user can authenticate with the generated password
- linux_client = RemoteClient(server, 'ec2-user',
- pkey=self.keypair['private_key'])
+ linux_client = remote_client.RemoteClient(server, 'ec2-user',
+ pkey=self.keypair[
+ 'private_key'])
linux_client.validate_authentication()
- @attr(type='slow')
+ @test.attr(type='slow')
def test_stack_wait_condition_data(self):
sid = self.stack_identifier
diff --git a/tempest/api/utils.py b/tempest/api/utils.py
index c62dc8d..00c93b7 100644
--- a/tempest/api/utils.py
+++ b/tempest/api/utils.py
@@ -15,7 +15,7 @@
"""Common utilities used in testing."""
-from tempest.test import BaseTestCase
+from tempest import test
class skip_unless_attr(object):
@@ -30,7 +30,7 @@
"""Wrapped skipper function."""
testobj = args[0]
if not getattr(testobj, self.attr, False):
- raise BaseTestCase.skipException(self.message)
+ raise test.BaseTestCase.skipException(self.message)
func(*args, **kw)
_skipper.__name__ = func.__name__
_skipper.__doc__ = func.__doc__
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
new file mode 100644
index 0000000..47094f0
--- /dev/null
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -0,0 +1,67 @@
+# Copyright 2014 OpenStack Foundation
+# 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.volume.base import BaseVolumeV1AdminTest
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest.openstack.common import log as logging
+from tempest import test
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class VolumesBackupsTest(BaseVolumeV1AdminTest):
+ _interface = "json"
+
+ @classmethod
+ def setUpClass(cls):
+ super(VolumesBackupsTest, cls).setUpClass()
+
+ if not CONF.volume_feature_enabled.backup:
+ raise cls.skipException("Cinder backup feature disabled")
+
+ cls.volumes_adm_client = cls.os_adm.volumes_client
+ cls.backups_adm_client = cls.os_adm.backups_client
+ cls.volume = cls.create_volume()
+
+ @test.attr(type='smoke')
+ def test_volume_backup_create_get_restore_delete(self):
+ backup_name = data_utils.rand_name('Backup')
+ create_backup = self.backups_adm_client.create_backup
+ resp, backup = create_backup(self.volume['id'],
+ name=backup_name)
+ self.assertEqual(202, resp.status)
+ self.addCleanup(self.backups_adm_client.delete_backup,
+ backup['id'])
+ self.assertEqual(backup['name'], backup_name)
+ self.volumes_adm_client.wait_for_volume_status(self.volume['id'],
+ 'available')
+ self.backups_adm_client.wait_for_backup_status(backup['id'],
+ 'available')
+
+ resp, backup = self.backups_adm_client.get_backup(backup['id'])
+ self.assertEqual(200, resp.status)
+ self.assertEqual(backup['name'], backup_name)
+
+ resp, restore = self.backups_adm_client.restore_backup(backup['id'])
+ self.assertEqual(202, resp.status)
+ self.addCleanup(self.volumes_adm_client.delete_volume,
+ restore['volume_id'])
+ self.assertEqual(restore['backup_id'], backup['id'])
+ self.backups_adm_client.wait_for_backup_status(backup['id'],
+ 'available')
+ self.volumes_adm_client.wait_for_volume_status(restore['volume_id'],
+ 'available')
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 6b6f638..8824977 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -106,6 +106,7 @@
super(BaseVolumeV1Test, cls).setUpClass()
cls.snapshots_client = cls.os.snapshots_client
cls.volumes_client = cls.os.volumes_client
+ cls.backups_client = cls.os.backups_client
cls.volumes_extension_client = cls.os.volumes_extension_client
@classmethod
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index ec732d1..e94c700 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testtools.matchers import ContainsAll
+from testtools import matchers
from tempest.api.volume import base
from tempest import test
@@ -43,7 +43,8 @@
# Create metadata for the volume
metadata = {"key1": "value1",
"key2": "value2",
- "key3": "value3"}
+ "key3": "value3",
+ "key4": "<value&special_chars>"}
rsp, body = self.volumes_client.create_volume_metadata(self.volume_id,
metadata)
@@ -51,7 +52,7 @@
# Get the metadata of the volume
resp, body = self.volumes_client.get_volume_metadata(self.volume_id)
self.assertEqual(200, resp.status)
- self.assertThat(body.items(), ContainsAll(metadata.items()))
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Delete one item metadata of the volume
rsp, body = self.volumes_client.delete_volume_metadata_item(
self.volume_id,
@@ -59,6 +60,8 @@
self.assertEqual(200, rsp.status)
resp, body = self.volumes_client.get_volume_metadata(self.volume_id)
self.assertNotIn("key1", body)
+ del metadata["key1"]
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
@test.attr(type='gate')
def test_update_volume_metadata(self):
@@ -78,7 +81,7 @@
# Get the metadata of the volume
resp, body = self.volumes_client.get_volume_metadata(self.volume_id)
self.assertEqual(200, resp.status)
- self.assertThat(body.items(), ContainsAll(metadata.items()))
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Update metadata
resp, body = self.volumes_client.update_volume_metadata(
self.volume_id,
@@ -87,7 +90,7 @@
# Get the metadata of the volume
resp, body = self.volumes_client.get_volume_metadata(self.volume_id)
self.assertEqual(200, resp.status)
- self.assertThat(body.items(), ContainsAll(update.items()))
+ self.assertThat(body.items(), matchers.ContainsAll(update.items()))
@test.attr(type='gate')
def test_update_volume_metadata_item(self):
@@ -104,7 +107,7 @@
self.volume_id,
metadata)
self.assertEqual(200, resp.status)
- self.assertThat(body.items(), ContainsAll(metadata.items()))
+ self.assertThat(body.items(), matchers.ContainsAll(metadata.items()))
# Update metadata item
resp, body = self.volumes_client.update_volume_metadata_item(
self.volume_id,
@@ -114,7 +117,7 @@
# Get the metadata of the volume
resp, body = self.volumes_client.get_volume_metadata(self.volume_id)
self.assertEqual(200, resp.status)
- self.assertThat(body.items(), ContainsAll(expect.items()))
+ self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
class VolumeMetadataTestXML(VolumeMetadataTest):
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 5924c7e..a22ad32 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -16,9 +16,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from tempest.test import services
-from tempest.test import stresstest
+from tempest import test
CONF = config.CONF
@@ -50,9 +48,9 @@
super(VolumesActionsTest, cls).tearDownClass()
- @stresstest(class_setup_per='process')
- @attr(type='smoke')
- @services('compute')
+ @test.stresstest(class_setup_per='process')
+ @test.attr(type='smoke')
+ @test.services('compute')
def test_attach_detach_volume_to_instance(self):
# Volume is attached and detached successfully from an instance
mountpoint = '/dev/vdc'
@@ -65,9 +63,9 @@
self.assertEqual(202, resp.status)
self.client.wait_for_volume_status(self.volume['id'], 'available')
- @stresstest(class_setup_per='process')
- @attr(type='gate')
- @services('compute')
+ @test.stresstest(class_setup_per='process')
+ @test.attr(type='gate')
+ @test.services('compute')
def test_get_volume_attachment(self):
# Verify that a volume's attachment information is retrieved
mountpoint = '/dev/vdc'
@@ -91,8 +89,8 @@
self.assertEqual(self.volume['id'], attachment['id'])
self.assertEqual(self.volume['id'], attachment['volume_id'])
- @attr(type='gate')
- @services('image')
+ @test.attr(type='gate')
+ @test.services('image')
def test_volume_upload(self):
# NOTE(gfidente): the volume uploaded in Glance comes from setUpClass,
# it is shared with the other tests. After it is uploaded in Glance,
@@ -108,7 +106,7 @@
self.image_client.wait_for_image_status(image_id, 'active')
self.client.wait_for_volume_status(self.volume['id'], 'available')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_extend(self):
# Extend Volume Test.
extend_size = int(self.volume['size']) + 1
@@ -119,7 +117,7 @@
self.assertEqual(200, resp.status)
self.assertEqual(int(volume['size']), extend_size)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_reserve_unreserve_volume(self):
# Mark volume as reserved.
resp, body = self.client.reserve_volume(self.volume['id'])
@@ -139,7 +137,7 @@
def _is_true(self, val):
return val in ['true', 'True', True]
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_readonly_update(self):
# Update volume readonly true
readonly = True
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index ce29b82..175da01 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -13,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testtools.matchers import ContainsAll
+from testtools import matchers
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -78,7 +77,7 @@
'The fetched Volume id is different '
'from the created Volume')
self.assertThat(fetched_volume['metadata'].items(),
- ContainsAll(metadata.items()),
+ matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
'from the created Volume')
@@ -114,7 +113,7 @@
self.assertEqual(new_v_name, updated_volume['display_name'])
self.assertEqual(new_desc, updated_volume['display_description'])
self.assertThat(updated_volume['metadata'].items(),
- ContainsAll(metadata.items()),
+ matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
'from the created Volume')
# Test volume create when display_name is none and display_description
@@ -146,16 +145,16 @@
if 'imageRef' not in kwargs:
self.assertEqual(boot_flag, False)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_create_get_update_delete(self):
self._volume_create_get_update_delete()
- @attr(type='smoke')
- @services('image')
+ @test.attr(type='smoke')
+ @test.services('image')
def test_volume_create_get_update_delete_from_image(self):
self._volume_create_get_update_delete(imageRef=CONF.compute.image_ref)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_create_get_update_delete_as_clone(self):
origin = self.create_volume()
self._volume_create_get_update_delete(source_volid=origin['id'])
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 049544d..c356342 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -18,8 +18,8 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from testtools.matchers import ContainsAll
+from tempest import test
+from testtools import matchers
LOG = logging.getLogger(__name__)
@@ -111,12 +111,12 @@
('details' if with_detail else '', key)
if key == 'metadata':
self.assertThat(volume[key].items(),
- ContainsAll(params[key].items()),
+ matchers.ContainsAll(params[key].items()),
msg)
else:
self.assertEqual(params[key], volume[key], msg)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_list(self):
# Get a list of Volumes
# Fetch all volumes
@@ -125,7 +125,7 @@
self.assertVolumesIn(fetched_list, self.volume_list,
fields=VOLUME_FIELDS)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_details(self):
# Get a list of Volumes with details
# Fetch all Volumes
@@ -133,7 +133,7 @@
self.assertEqual(200, resp.status)
self.assertVolumesIn(fetched_list, self.volume_list)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
params = {'display_name': volume['display_name']}
@@ -143,7 +143,7 @@
self.assertEqual(fetched_vol[0]['display_name'],
volume['display_name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_details_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
params = {'display_name': volume['display_name']}
@@ -153,7 +153,7 @@
self.assertEqual(fetched_vol[0]['display_name'],
volume['display_name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_by_status(self):
params = {'status': 'available'}
resp, fetched_list = self.client.list_volumes(params)
@@ -163,7 +163,7 @@
self.assertVolumesIn(fetched_list, self.volume_list,
fields=VOLUME_FIELDS)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_details_by_status(self):
params = {'status': 'available'}
resp, fetched_list = self.client.list_volumes_with_detail(params)
@@ -172,7 +172,7 @@
self.assertEqual('available', volume['status'])
self.assertVolumesIn(fetched_list, self.volume_list)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_by_availability_zone(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
zone = volume['availability_zone']
@@ -184,7 +184,7 @@
self.assertVolumesIn(fetched_list, self.volume_list,
fields=VOLUME_FIELDS)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_details_by_availability_zone(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
zone = volume['availability_zone']
@@ -195,19 +195,19 @@
self.assertEqual(zone, volume['availability_zone'])
self.assertVolumesIn(fetched_list, self.volume_list)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_param_metadata(self):
# Test to list volumes when metadata param is given
params = {'metadata': self.metadata}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_detail_param_metadata(self):
# Test to list volumes details when metadata param is given
params = {'metadata': self.metadata}
self._list_by_param_value_and_assert(params, with_detail=True)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_param_display_name_and_status(self):
# Test to list volume when display name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
@@ -215,7 +215,7 @@
'status': 'available'}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_detail_param_display_name_and_status(self):
# Test to list volume when name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
diff --git a/tempest/auth.py b/tempest/auth.py
index 582cfdd..e1ba13b 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -177,7 +177,7 @@
base_url = self.base_url(filters=filters, auth_data=auth_data)
# build authenticated request
# returns new request, it does not touch the original values
- _headers = copy.deepcopy(headers)
+ _headers = copy.deepcopy(headers) if headers is not None else {}
_headers['X-Auth-Token'] = token
if url is None or url == "":
_url = base_url
@@ -371,7 +371,7 @@
ep['region'] == region]
if len(filtered_catalog) == 0:
# No matching region, take the first endpoint
- filtered_catalog = [filtered_catalog[0]]
+ filtered_catalog = [service_catalog[0]]
# There should be only one match. If not take the first.
_base_url = filtered_catalog[0].get('url', None)
if _base_url is None:
diff --git a/tempest/clients.py b/tempest/clients.py
index d0eb1cc..8db399a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,10 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import auth
+# Default client libs
+import cinderclient.client
+import glanceclient
+import heatclient.client
+import keystoneclient.exceptions
+import keystoneclient.v2_0.client
+import neutronclient.v2_0.client
+import novaclient.client
+import swiftclient
+
from tempest.common.rest_client import NegativeRestClient
from tempest import config
from tempest import exceptions
+from tempest import manager
from tempest.openstack.common import log as logging
from tempest.services.baremetal.v1.client_json import BaremetalClientJSON
from tempest.services import botoclients
@@ -148,6 +158,7 @@
VolumeHostsClientJSON
from tempest.services.volume.json.admin.volume_types_client import \
VolumeTypesClientJSON
+from tempest.services.volume.json.backups_client import BackupsClientJSON
from tempest.services.volume.json.extensions_client import \
ExtensionsClientJSON as VolumeExtensionClientJSON
from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
@@ -158,6 +169,7 @@
VolumeHostsClientXML
from tempest.services.volume.xml.admin.volume_types_client import \
VolumeTypesClientXML
+from tempest.services.volume.xml.backups_client import BackupsClientXML
from tempest.services.volume.xml.extensions_client import \
ExtensionsClientXML as VolumeExtensionClientXML
from tempest.services.volume.xml.snapshots_client import SnapshotsClientXML
@@ -167,10 +179,10 @@
LOG = logging.getLogger(__name__)
-class Manager(object):
+class Manager(manager.Manager):
"""
- Top level manager for OpenStack Compute clients
+ Top level manager for OpenStack tempest clients
"""
def __init__(self, username=None, password=None, tenant_name=None,
@@ -185,151 +197,145 @@
:param tenant_name: Override of the tenant name
"""
self.interface = interface
- self.auth_version = CONF.identity.auth_version
- # FIXME(andreaf) Change Manager __init__ to accept a credentials dict
- if username is None or password is None:
- # Tenant None is a valid use case
- self.credentials = self.get_default_credentials()
- else:
- self.credentials = dict(username=username, password=password,
- tenant_name=tenant_name)
- if self.auth_version == 'v3':
- self.credentials['domain_name'] = 'Default'
- # Setup an auth provider
- auth_provider = self.get_auth_provider(self.credentials)
+ self.client_type = 'tempest'
+ # super cares for credentials validation
+ super(Manager, self).__init__(
+ username=username, password=password, tenant_name=tenant_name)
if self.interface == 'xml':
self.certificates_client = CertificatesClientXML(
- auth_provider)
- self.servers_client = ServersClientXML(auth_provider)
- self.limits_client = LimitsClientXML(auth_provider)
- self.images_client = ImagesClientXML(auth_provider)
- self.keypairs_client = KeyPairsClientXML(auth_provider)
- self.quotas_client = QuotasClientXML(auth_provider)
- self.flavors_client = FlavorsClientXML(auth_provider)
- self.extensions_client = ExtensionsClientXML(auth_provider)
+ self.auth_provider)
+ self.servers_client = ServersClientXML(self.auth_provider)
+ self.limits_client = LimitsClientXML(self.auth_provider)
+ self.images_client = ImagesClientXML(self.auth_provider)
+ self.keypairs_client = KeyPairsClientXML(self.auth_provider)
+ self.quotas_client = QuotasClientXML(self.auth_provider)
+ self.flavors_client = FlavorsClientXML(self.auth_provider)
+ self.extensions_client = ExtensionsClientXML(self.auth_provider)
self.volumes_extensions_client = VolumesExtensionsClientXML(
- auth_provider)
+ self.auth_provider)
self.floating_ips_client = FloatingIPsClientXML(
- auth_provider)
- self.snapshots_client = SnapshotsClientXML(auth_provider)
- self.volumes_client = VolumesClientXML(auth_provider)
- self.volumes_v2_client = VolumesV2ClientXML(auth_provider)
+ self.auth_provider)
+ self.backups_client = BackupsClientXML(self.auth_provider)
+ self.snapshots_client = SnapshotsClientXML(self.auth_provider)
+ self.volumes_client = VolumesClientXML(self.auth_provider)
+ self.volumes_v2_client = VolumesV2ClientXML(self.auth_provider)
self.volume_types_client = VolumeTypesClientXML(
- auth_provider)
- self.identity_client = IdentityClientXML(auth_provider)
+ self.auth_provider)
+ self.identity_client = IdentityClientXML(self.auth_provider)
self.identity_v3_client = IdentityV3ClientXML(
- auth_provider)
+ self.auth_provider)
self.security_groups_client = SecurityGroupsClientXML(
- auth_provider)
- self.interfaces_client = InterfacesClientXML(auth_provider)
- self.endpoints_client = EndPointClientXML(auth_provider)
- self.fixed_ips_client = FixedIPsClientXML(auth_provider)
+ self.auth_provider)
+ self.interfaces_client = InterfacesClientXML(self.auth_provider)
+ self.endpoints_client = EndPointClientXML(self.auth_provider)
+ self.fixed_ips_client = FixedIPsClientXML(self.auth_provider)
self.availability_zone_client = AvailabilityZoneClientXML(
- auth_provider)
- self.service_client = ServiceClientXML(auth_provider)
- self.aggregates_client = AggregatesClientXML(auth_provider)
- self.services_client = ServicesClientXML(auth_provider)
+ self.auth_provider)
+ self.service_client = ServiceClientXML(self.auth_provider)
+ self.aggregates_client = AggregatesClientXML(self.auth_provider)
+ self.services_client = ServicesClientXML(self.auth_provider)
self.tenant_usages_client = TenantUsagesClientXML(
- auth_provider)
- self.policy_client = PolicyClientXML(auth_provider)
- self.hosts_client = HostsClientXML(auth_provider)
- self.hypervisor_client = HypervisorClientXML(auth_provider)
- self.network_client = NetworkClientXML(auth_provider)
+ self.auth_provider)
+ self.policy_client = PolicyClientXML(self.auth_provider)
+ self.hosts_client = HostsClientXML(self.auth_provider)
+ self.hypervisor_client = HypervisorClientXML(self.auth_provider)
+ self.network_client = NetworkClientXML(self.auth_provider)
self.credentials_client = CredentialsClientXML(
- auth_provider)
+ self.auth_provider)
self.instance_usages_audit_log_client = \
- InstanceUsagesAuditLogClientXML(auth_provider)
+ InstanceUsagesAuditLogClientXML(self.auth_provider)
self.volume_hosts_client = VolumeHostsClientXML(
- auth_provider)
+ self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientXML(
- auth_provider)
+ self.auth_provider)
if CONF.service_available.ceilometer:
self.telemetry_client = TelemetryClientXML(
- auth_provider)
+ self.auth_provider)
self.token_client = TokenClientXML()
self.token_v3_client = V3TokenClientXML()
elif self.interface == 'json':
self.certificates_client = CertificatesClientJSON(
- auth_provider)
+ self.auth_provider)
self.certificates_v3_client = CertificatesV3ClientJSON(
- auth_provider)
- self.baremetal_client = BaremetalClientJSON(auth_provider)
- self.servers_client = ServersClientJSON(auth_provider)
- self.servers_v3_client = ServersV3ClientJSON(auth_provider)
- self.limits_client = LimitsClientJSON(auth_provider)
- self.images_client = ImagesClientJSON(auth_provider)
+ self.auth_provider)
+ self.baremetal_client = BaremetalClientJSON(self.auth_provider)
+ self.servers_client = ServersClientJSON(self.auth_provider)
+ self.servers_v3_client = ServersV3ClientJSON(self.auth_provider)
+ self.limits_client = LimitsClientJSON(self.auth_provider)
+ self.images_client = ImagesClientJSON(self.auth_provider)
self.keypairs_v3_client = KeyPairsV3ClientJSON(
- auth_provider)
- self.keypairs_client = KeyPairsClientJSON(auth_provider)
+ self.auth_provider)
+ self.keypairs_client = KeyPairsClientJSON(self.auth_provider)
self.keypairs_v3_client = KeyPairsV3ClientJSON(
- auth_provider)
- self.quotas_client = QuotasClientJSON(auth_provider)
- self.quotas_v3_client = QuotasV3ClientJSON(auth_provider)
- self.flavors_client = FlavorsClientJSON(auth_provider)
- self.flavors_v3_client = FlavorsV3ClientJSON(auth_provider)
+ self.auth_provider)
+ self.quotas_client = QuotasClientJSON(self.auth_provider)
+ self.quotas_v3_client = QuotasV3ClientJSON(self.auth_provider)
+ self.flavors_client = FlavorsClientJSON(self.auth_provider)
+ self.flavors_v3_client = FlavorsV3ClientJSON(self.auth_provider)
self.extensions_v3_client = ExtensionsV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.extensions_client = ExtensionsClientJSON(
- auth_provider)
+ self.auth_provider)
self.volumes_extensions_client = VolumesExtensionsClientJSON(
- auth_provider)
+ self.auth_provider)
self.floating_ips_client = FloatingIPsClientJSON(
- auth_provider)
- self.snapshots_client = SnapshotsClientJSON(auth_provider)
- self.volumes_client = VolumesClientJSON(auth_provider)
- self.volumes_v2_client = VolumesV2ClientJSON(auth_provider)
+ self.auth_provider)
+ self.backups_client = BackupsClientJSON(self.auth_provider)
+ self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
+ self.volumes_client = VolumesClientJSON(self.auth_provider)
+ self.volumes_v2_client = VolumesV2ClientJSON(self.auth_provider)
self.volume_types_client = VolumeTypesClientJSON(
- auth_provider)
- self.identity_client = IdentityClientJSON(auth_provider)
+ self.auth_provider)
+ self.identity_client = IdentityClientJSON(self.auth_provider)
self.identity_v3_client = IdentityV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.security_groups_client = SecurityGroupsClientJSON(
- auth_provider)
+ self.auth_provider)
self.interfaces_v3_client = InterfacesV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.interfaces_client = InterfacesClientJSON(
- auth_provider)
- self.endpoints_client = EndPointClientJSON(auth_provider)
- self.fixed_ips_client = FixedIPsClientJSON(auth_provider)
+ self.auth_provider)
+ self.endpoints_client = EndPointClientJSON(self.auth_provider)
+ self.fixed_ips_client = FixedIPsClientJSON(self.auth_provider)
self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.availability_zone_client = AvailabilityZoneClientJSON(
- auth_provider)
+ self.auth_provider)
self.services_v3_client = ServicesV3ClientJSON(
- auth_provider)
- self.service_client = ServiceClientJSON(auth_provider)
+ self.auth_provider)
+ self.service_client = ServiceClientJSON(self.auth_provider)
self.aggregates_v3_client = AggregatesV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.aggregates_client = AggregatesClientJSON(
- auth_provider)
- self.services_client = ServicesClientJSON(auth_provider)
+ self.auth_provider)
+ self.services_client = ServicesClientJSON(self.auth_provider)
self.tenant_usages_client = TenantUsagesClientJSON(
- auth_provider)
- self.version_v3_client = VersionV3ClientJSON(auth_provider)
- self.policy_client = PolicyClientJSON(auth_provider)
- self.hosts_client = HostsClientJSON(auth_provider)
+ self.auth_provider)
+ self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
+ self.policy_client = PolicyClientJSON(self.auth_provider)
+ self.hosts_client = HostsClientJSON(self.auth_provider)
self.hypervisor_v3_client = HypervisorV3ClientJSON(
- auth_provider)
+ self.auth_provider)
self.hypervisor_client = HypervisorClientJSON(
- auth_provider)
- self.network_client = NetworkClientJSON(auth_provider)
+ self.auth_provider)
+ self.network_client = NetworkClientJSON(self.auth_provider)
self.credentials_client = CredentialsClientJSON(
- auth_provider)
+ self.auth_provider)
self.instance_usages_audit_log_client = \
- InstanceUsagesAuditLogClientJSON(auth_provider)
+ InstanceUsagesAuditLogClientJSON(self.auth_provider)
self.volume_hosts_client = VolumeHostsClientJSON(
- auth_provider)
+ self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientJSON(
- auth_provider)
- self.hosts_v3_client = HostsV3ClientJSON(auth_provider)
+ self.auth_provider)
+ self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
if CONF.service_available.ceilometer:
self.telemetry_client = TelemetryClientJSON(
- auth_provider)
+ self.auth_provider)
self.token_client = TokenClientJSON()
self.token_v3_client = V3TokenClientJSON()
- self.negative_client = NegativeRestClient(auth_provider)
+ self.negative_client = NegativeRestClient(self.auth_provider)
self.negative_client.service = service
else:
@@ -343,47 +349,22 @@
self.credentials.get('tenant_name'))
# common clients
- self.account_client = AccountClient(auth_provider)
+ self.account_client = AccountClient(self.auth_provider)
if CONF.service_available.glance:
- self.image_client = ImageClientJSON(auth_provider)
- self.image_client_v2 = ImageClientV2JSON(auth_provider)
- self.container_client = ContainerClient(auth_provider)
- self.object_client = ObjectClient(auth_provider)
+ self.image_client = ImageClientJSON(self.auth_provider)
+ self.image_client_v2 = ImageClientV2JSON(self.auth_provider)
+ self.container_client = ContainerClient(self.auth_provider)
+ self.object_client = ObjectClient(self.auth_provider)
self.orchestration_client = OrchestrationClient(
- auth_provider)
+ self.auth_provider)
self.ec2api_client = botoclients.APIClientEC2(*ec2_client_args)
self.s3_client = botoclients.ObjectClientS3(*ec2_client_args)
self.custom_object_client = ObjectClientCustomizedHeader(
- auth_provider)
+ self.auth_provider)
self.custom_account_client = \
- AccountClientCustomizedHeader(auth_provider)
+ AccountClientCustomizedHeader(self.auth_provider)
self.data_processing_client = DataProcessingClient(
- auth_provider)
-
- @classmethod
- def get_auth_provider_class(cls, auth_version):
- if auth_version == 'v2':
- return auth.KeystoneV2AuthProvider
- else:
- return auth.KeystoneV3AuthProvider
-
- def get_default_credentials(self):
- return dict(
- username=CONF.identity.username,
- password=CONF.identity.password,
- tenant_name=CONF.identity.tenant_name
- )
-
- def get_auth_provider(self, credentials=None):
- auth_params = dict(client_type='tempest',
- interface=self.interface)
- auth_provider_class = self.get_auth_provider_class(self.auth_version)
- # If invalid / incomplete credentials are provided, use default ones
- if credentials is None or \
- not auth_provider_class.check_credentials(credentials):
- credentials = self.credentials
- auth_params['credentials'] = credentials
- return auth_provider_class(**auth_params)
+ self.auth_provider)
class AltManager(Manager):
@@ -448,3 +429,187 @@
CONF.identity.tenant_name,
interface=interface,
service=service)
+
+
+class OfficialClientManager(manager.Manager):
+ """
+ Manager that provides access to the official python clients for
+ calling various OpenStack APIs.
+ """
+
+ NOVACLIENT_VERSION = '2'
+ CINDERCLIENT_VERSION = '1'
+ HEATCLIENT_VERSION = '1'
+
+ def __init__(self, username, password, tenant_name):
+ # FIXME(andreaf) Auth provider for client_type 'official' is
+ # not implemented yet, setting to 'tempest' for now.
+ self.client_type = 'tempest'
+ self.interface = None
+ # super cares for credentials validation
+ super(OfficialClientManager, self).__init__(
+ username=username, password=password, tenant_name=tenant_name)
+ self.compute_client = self._get_compute_client(username,
+ password,
+ tenant_name)
+ self.identity_client = self._get_identity_client(username,
+ password,
+ tenant_name)
+ self.image_client = self._get_image_client()
+ self.network_client = self._get_network_client()
+ self.volume_client = self._get_volume_client(username,
+ password,
+ tenant_name)
+ self.object_storage_client = self._get_object_storage_client(
+ username,
+ password,
+ tenant_name)
+ self.orchestration_client = self._get_orchestration_client(
+ username,
+ password,
+ tenant_name)
+
+ def _get_compute_client(self, username, password, tenant_name):
+ # Novaclient will not execute operations for anyone but the
+ # identified user, so a new client needs to be created for
+ # each user that operations need to be performed for.
+ self._validate_credentials(username, password, tenant_name)
+
+ auth_url = CONF.identity.uri
+ dscv = CONF.identity.disable_ssl_certificate_validation
+ region = CONF.identity.region
+
+ client_args = (username, password, tenant_name, auth_url)
+
+ # Create our default Nova client to use in testing
+ service_type = CONF.compute.catalog_type
+ endpoint_type = CONF.compute.endpoint_type
+ return novaclient.client.Client(self.NOVACLIENT_VERSION,
+ *client_args,
+ service_type=service_type,
+ endpoint_type=endpoint_type,
+ region_name=region,
+ no_cache=True,
+ insecure=dscv,
+ http_log_debug=True)
+
+ def _get_image_client(self):
+ token = self.identity_client.auth_token
+ region = CONF.identity.region
+ endpoint_type = CONF.image.endpoint_type
+ endpoint = self.identity_client.service_catalog.url_for(
+ attr='region', filter_value=region,
+ service_type=CONF.image.catalog_type, endpoint_type=endpoint_type)
+ dscv = CONF.identity.disable_ssl_certificate_validation
+ return glanceclient.Client('1', endpoint=endpoint, token=token,
+ insecure=dscv)
+
+ def _get_volume_client(self, username, password, tenant_name):
+ auth_url = CONF.identity.uri
+ region = CONF.identity.region
+ endpoint_type = CONF.volume.endpoint_type
+ return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
+ username,
+ password,
+ tenant_name,
+ auth_url,
+ region_name=region,
+ endpoint_type=endpoint_type,
+ http_log_debug=True)
+
+ def _get_object_storage_client(self, username, password, tenant_name):
+ auth_url = CONF.identity.uri
+ # add current tenant to swift operator role group.
+ keystone_admin = self._get_identity_client(
+ CONF.identity.admin_username,
+ CONF.identity.admin_password,
+ CONF.identity.admin_tenant_name)
+
+ # enable test user to operate swift by adding operator role to him.
+ roles = keystone_admin.roles.list()
+ operator_role = CONF.object_storage.operator_role
+ member_role = [role for role in roles if role.name == operator_role][0]
+ # NOTE(maurosr): This is surrounded in the try-except block cause
+ # neutron tests doesn't have tenant isolation.
+ try:
+ keystone_admin.roles.add_user_role(self.identity_client.user_id,
+ member_role.id,
+ self.identity_client.tenant_id)
+ except keystoneclient.exceptions.Conflict:
+ pass
+
+ endpoint_type = CONF.object_storage.endpoint_type
+ os_options = {'endpoint_type': endpoint_type}
+ return swiftclient.Connection(auth_url, username, password,
+ tenant_name=tenant_name,
+ auth_version='2',
+ os_options=os_options)
+
+ def _get_orchestration_client(self, username=None, password=None,
+ tenant_name=None):
+ if not username:
+ username = CONF.identity.admin_username
+ if not password:
+ password = CONF.identity.admin_password
+ if not tenant_name:
+ tenant_name = CONF.identity.tenant_name
+
+ self._validate_credentials(username, password, tenant_name)
+
+ keystone = self._get_identity_client(username, password, tenant_name)
+ region = CONF.identity.region
+ endpoint_type = CONF.orchestration.endpoint_type
+ token = keystone.auth_token
+ service_type = CONF.orchestration.catalog_type
+ try:
+ endpoint = keystone.service_catalog.url_for(
+ attr='region',
+ filter_value=region,
+ service_type=service_type,
+ endpoint_type=endpoint_type)
+ except keystoneclient.exceptions.EndpointNotFound:
+ return None
+ else:
+ return heatclient.client.Client(self.HEATCLIENT_VERSION,
+ endpoint,
+ token=token,
+ username=username,
+ password=password)
+
+ def _get_identity_client(self, username, password, tenant_name):
+ # This identity client is not intended to check the security
+ # of the identity service, so use admin credentials by default.
+ self._validate_credentials(username, password, tenant_name)
+
+ auth_url = CONF.identity.uri
+ dscv = CONF.identity.disable_ssl_certificate_validation
+
+ return keystoneclient.v2_0.client.Client(username=username,
+ password=password,
+ tenant_name=tenant_name,
+ auth_url=auth_url,
+ insecure=dscv)
+
+ def _get_network_client(self):
+ # The intended configuration is for the network client to have
+ # admin privileges and indicate for whom resources are being
+ # created via a 'tenant_id' parameter. This will often be
+ # preferable to authenticating as a specific user because
+ # working with certain resources (public routers and networks)
+ # often requires admin privileges anyway.
+ username = CONF.identity.admin_username
+ password = CONF.identity.admin_password
+ tenant_name = CONF.identity.admin_tenant_name
+
+ self._validate_credentials(username, password, tenant_name)
+
+ auth_url = CONF.identity.uri
+ dscv = CONF.identity.disable_ssl_certificate_validation
+ endpoint_type = CONF.network.endpoint_type
+
+ return neutronclient.v2_0.client.Client(username=username,
+ password=password,
+ tenant_name=tenant_name,
+ endpoint_type=endpoint_type,
+ auth_url=auth_url,
+ insecure=dscv)
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 6d08d2d..03dccd4 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -58,7 +58,7 @@
def __init__(self, auth_provider):
self.auth_provider = auth_provider
- self.endpoint_url = 'publicURL'
+ self.endpoint_url = None
self.service = None
# The version of the API this client implements
self.api_version = None
@@ -114,6 +114,28 @@
service_region = CONF.identity.region
return service_region
+ def _get_endpoint_type(self, service):
+ """
+ Returns the endpoint type for a specific service
+ """
+ # If the client requests a specific endpoint type, then be it
+ if self.endpoint_url:
+ return self.endpoint_url
+ endpoint_type = None
+ for cfgname in dir(CONF._config):
+ # Find all config.FOO.catalog_type and assume FOO is a service.
+ cfg = getattr(CONF, cfgname)
+ catalog_type = getattr(cfg, 'catalog_type', None)
+ if catalog_type == service:
+ endpoint_type = getattr(cfg, 'endpoint_type', 'publicURL')
+ break
+ # Special case for compute v3 service which hasn't its own
+ # configuration group
+ else:
+ if service == CONF.compute.catalog_v3_type:
+ endpoint_type = CONF.compute.endpoint_type
+ return endpoint_type
+
@property
def user(self):
return self.auth_provider.credentials.get('username', None)
@@ -138,7 +160,7 @@
def filters(self):
_filters = dict(
service=self.service,
- endpoint_type=self.endpoint_url,
+ endpoint_type=self._get_endpoint_type(self.service),
region=self._get_region(self.service)
)
if self.api_version is not None:
@@ -197,7 +219,6 @@
def get_versions(self):
resp, body = self.get('')
body = self._parse_resp(body)
- body = body['versions']
versions = map(lambda x: x['id'], body)
return resp, versions
@@ -225,10 +246,10 @@
headers = resp.copy()
del headers['status']
if headers.get('x-compute-request-id'):
- self.LOG.info("Nova request id: %s" %
+ self.LOG.info("Nova/Cinder request id: %s" %
headers.pop('x-compute-request-id'))
elif headers.get('x-openstack-request-id'):
- self.LOG.info("Glance request id %s" %
+ self.LOG.info("OpenStack request id %s" %
headers.pop('x-openstack-request-id'))
if len(headers):
self.LOG.debug('Response Headers: ' + str(headers))
@@ -481,24 +502,6 @@
raise NotImplementedError(message)
-class RestClientXML(RestClient):
-
- # NOTE(vponomaryov): This is deprecated class
- # and should be removed after excluding it
- # from all service clients
-
- TYPE = "xml"
-
- def _parse_resp(self, body):
- return xml_to_json(etree.fromstring(body))
-
- def is_absolute_limit(self, resp, resp_body):
- if (not isinstance(resp_body, collections.Mapping) or
- 'retry-after' not in resp):
- return True
- return 'exceed' in resp_body.get('message', 'blabla')
-
-
class NegativeRestClient(RestClient):
"""
Version of RestClient that does not raise exceptions.
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index bb2fcfb..94fc23c 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -13,9 +13,9 @@
import re
import time
-from tempest.common.ssh import Client
+from tempest.common import ssh
from tempest import config
-from tempest.exceptions import ServerUnreachable
+from tempest import exceptions
CONF = config.CONF
@@ -37,10 +37,10 @@
ip_address = address['addr']
break
else:
- raise ServerUnreachable()
- self.ssh_client = Client(ip_address, username, password, ssh_timeout,
- pkey=pkey,
- channel_timeout=ssh_channel_timeout)
+ raise exceptions.ServerUnreachable()
+ self.ssh_client = ssh.Client(ip_address, username, password,
+ ssh_timeout, pkey=pkey,
+ channel_timeout=ssh_channel_timeout)
def validate_authentication(self):
"""Validate ssh connection and authentication
diff --git a/tempest/common/utils/test_utils.py b/tempest/common/utils/test_utils.py
index 2e23782..cc0d831 100644
--- a/tempest/common/utils/test_utils.py
+++ b/tempest/common/utils/test_utils.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import clients
from tempest.common.utils import misc
from tempest import config
-from tempest.scenario import manager
import json
import re
@@ -35,7 +35,7 @@
self.non_ssh_image_pattern = \
CONF.input_scenario.non_ssh_image_regex
# Setup clients
- ocm = manager.OfficialClientManager(CONF.identity.username,
+ ocm = clients.OfficialClientManager(CONF.identity.username,
CONF.identity.password,
CONF.identity.tenant_name)
self.client = ocm.compute_client
@@ -95,7 +95,7 @@
digit=string.digits)
def __init__(self):
- ocm = manager.OfficialClientManager(CONF.identity.username,
+ ocm = clients.OfficialClientManager(CONF.identity.username,
CONF.identity.password,
CONF.identity.tenant_name)
self.client = ocm.compute_client
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index dbeba8f..8e6b9fb 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -42,7 +42,7 @@
timeout = client.build_timeout + extra_timeout
while True:
# NOTE(afazekas): Now the BUILD status only reached
- # between the UNKOWN->ACTIVE transition.
+ # between the UNKNOWN->ACTIVE transition.
# TODO(afazekas): enumerate and validate the stable status set
if status == 'BUILD' and server_status != 'UNKNOWN':
return
diff --git a/tempest/config.py b/tempest/config.py
index 210c857..4380608 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -15,6 +15,7 @@
from __future__ import print_function
+import logging as std_logging
import os
from oslo.config import cfg
@@ -53,6 +54,11 @@
"services' region name unless they are set explicitly. "
"If no such region is found in the service catalog, the "
"first found one is used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the identity service."),
cfg.StrOpt('username',
default='demo',
help="Username to use for Nova API requests."),
@@ -193,6 +199,11 @@
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the compute service."),
cfg.StrOpt('catalog_v3_type',
default='computev3',
help="Catalog type of the Compute v3 service."),
@@ -225,8 +236,8 @@
help="If false, skip disk config tests"),
cfg.ListOpt('api_extensions',
default=['all'],
- help='A list of enabled extensions with a special entry all '
- 'which indicates every extension is enabled'),
+ help='A list of enabled compute extensions with a special '
+ 'entry all which indicates every extension is enabled'),
cfg.ListOpt('api_v3_extensions',
default=['all'],
help='A list of enabled v3 extensions with a special entry all'
@@ -286,6 +297,11 @@
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the image service."),
cfg.StrOpt('http_image',
default='http://download.cirros-cloud.net/0.3.1/'
'cirros-0.3.1-x86_64-uec.tar.gz',
@@ -317,12 +333,20 @@
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the network service."),
cfg.StrOpt('tenant_network_cidr',
default="10.100.0.0/16",
help="The cidr block to allocate tenant ipv4 subnets from"),
cfg.IntOpt('tenant_network_mask_bits',
default=28,
help="The mask bits for tenant ipv4 subnets"),
+ cfg.BoolOpt('ipv6_enabled',
+ default=True,
+ help="Allow the execution of IPv6 tests"),
cfg.StrOpt('tenant_network_v6_cidr',
default="2003::/64",
help="The cidr block to allocate tenant ipv6 subnets from"),
@@ -349,8 +373,8 @@
NetworkFeaturesGroup = [
cfg.ListOpt('api_extensions',
default=['all'],
- help='A list of enabled extensions with a special entry all '
- 'which indicates every extension is enabled'),
+ help='A list of enabled network extensions with a special '
+ 'entry all which indicates every extension is enabled'),
]
volume_group = cfg.OptGroup(name='volume',
@@ -373,6 +397,11 @@
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the volume service."),
cfg.StrOpt('backend1_name',
default='BACKEND_1',
help="Name of the backend1 (must be declared in cinder.conf)"),
@@ -397,10 +426,13 @@
cfg.BoolOpt('multi_backend',
default=False,
help="Runs Cinder multi-backend test (requires 2 backends)"),
+ cfg.BoolOpt('backup',
+ default=True,
+ help='Runs Cinder volumes backup test'),
cfg.ListOpt('api_extensions',
default=['all'],
- help='A list of enabled extensions with a special entry all '
- 'which indicates every extension is enabled'),
+ help='A list of enabled volume extensions with a special '
+ 'entry all which indicates every extension is enabled'),
cfg.BoolOpt('api_v1',
default=True,
help="Is the v1 volume API enabled"),
@@ -423,6 +455,11 @@
"value of identity.region is used instead. If no such "
"region is found in the service catalog, the first found "
"one is used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the object-store service."),
cfg.IntOpt('container_sync_timeout',
default=120,
help="Number of seconds to time on waiting for a container "
@@ -463,6 +500,11 @@
"value of identity.region is used instead. If no such "
"region is found in the service catalog, the first found "
"one is used."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the orchestration service."),
cfg.BoolOpt('allow_tenant_isolation',
default=False,
help="Allows test cases to create/destroy tenants and "
@@ -606,7 +648,12 @@
default=False,
help='Prevent the cleaning (tearDownClass()) between'
' each stress test run if an exception occurs'
- ' during this run.')
+ ' during this run.'),
+ cfg.BoolOpt('full_clean_stack',
+ default=False,
+ help='Allows a full cleaning process after a stress test.'
+ ' Caution : this cleanup will remove every objects of'
+ ' every tenant.')
]
@@ -617,6 +664,9 @@
default='/opt/stack/new/devstack/files/images/'
'cirros-0.3.1-x86_64-uec',
help='Directory containing image files'),
+ cfg.StrOpt('qcow2_img_file',
+ default='cirros-0.3.1-x86_64-disk.img',
+ help='QCOW2 image file name'),
cfg.StrOpt('ami_img_file',
default='cirros-0.3.1-x86_64-blank.img',
help='AMI image file name'),
@@ -827,6 +877,9 @@
self.compute_admin.password = self.identity.admin_password
self.compute_admin.tenant_name = self.identity.admin_tenant_name
+ if parse_conf:
+ cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
+
class TempestConfigProxy(object):
_config = None
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 3b3f3eb..ac88faa 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -100,6 +100,10 @@
message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
+class VolumeBackupException(TempestException):
+ message = "Volume backup %(backup_id)s failed and is in ERROR status"
+
+
class StackBuildErrorException(TempestException):
message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
"due to '%(stack_status_reason)s'")
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 2e499a2..55be60a 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -21,6 +21,7 @@
TEST_DEFINITION = re.compile(r'^\s*def test.*')
SETUPCLASS_DEFINITION = re.compile(r'^\s*def setUpClass')
SCENARIO_DECORATOR = re.compile(r'\s*@.*services\(')
+VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
def import_no_clients_in_api(physical_line, filename):
@@ -58,7 +59,22 @@
"T105: setUpClass can not be used with unit tests")
+def no_vi_headers(physical_line, line_number, lines):
+ """Check for vi editor configuration in source files.
+
+ By default vi modelines can only appear in the first or
+ last 5 lines of a source file.
+
+ T106
+ """
+ # NOTE(gilliard): line_number is 1-indexed
+ if line_number <= 5 or line_number > len(lines) - 5:
+ if VI_HEADER_RE.match(physical_line):
+ return 0, "T106: Don't put vi configuration in source files"
+
+
def factory(register):
register(import_no_clients_in_api)
register(scenario_tests_need_service_tags)
register(no_setupclass_for_unit_tests)
+ register(no_vi_headers)
diff --git a/tempest/manager.py b/tempest/manager.py
index 93ff10f..708447e 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -13,8 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import auth
+from tempest import config
from tempest import exceptions
+CONF = config.CONF
+
class Manager(object):
@@ -25,7 +29,27 @@
and a client object for a test case to use in performing actions.
"""
- def __init__(self):
+ def __init__(self, username=None, password=None, tenant_name=None):
+ """
+ We allow overriding of the credentials used within the various
+ client classes managed by the Manager object. Left as None, the
+ standard username/password/tenant_name[/domain_name] is used.
+
+ :param credentials: Override of the credentials
+ """
+ self.auth_version = CONF.identity.auth_version
+ # FIXME(andreaf) Change Manager __init__ to accept a credentials dict
+ if username is None or password is None:
+ # Tenant None is a valid use case
+ self.credentials = self.get_default_credentials()
+ else:
+ self.credentials = dict(username=username, password=password,
+ tenant_name=tenant_name)
+ if self.auth_version == 'v3':
+ self.credentials['domain_name'] = 'Default'
+ # Creates an auth provider for the credentials
+ self.auth_provider = self.get_auth_provider(self.credentials)
+ # FIXME(andreaf) unused
self.client_attr_names = []
# we do this everywhere, have it be part of the super class
@@ -36,3 +60,28 @@
"tenant_name: %(t)s" %
{'u': username, 'p': password, 't': tenant_name})
raise exceptions.InvalidConfiguration(msg)
+
+ @classmethod
+ def get_auth_provider_class(cls, auth_version):
+ if auth_version == 'v2':
+ return auth.KeystoneV2AuthProvider
+ else:
+ return auth.KeystoneV3AuthProvider
+
+ def get_default_credentials(self):
+ return dict(
+ username=CONF.identity.username,
+ password=CONF.identity.password,
+ tenant_name=CONF.identity.tenant_name
+ )
+
+ def get_auth_provider(self, credentials=None):
+ auth_params = dict(client_type=getattr(self, 'client_type', None),
+ interface=getattr(self, 'interface', None))
+ auth_provider_class = self.get_auth_provider_class(self.auth_version)
+ # If invalid / incomplete credentials are provided, use default ones
+ if credentials is None or \
+ not auth_provider_class.check_credentials(credentials):
+ credentials = self.credentials
+ auth_params['credentials'] = credentials
+ return auth_provider_class(**auth_params)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 0fc304a..56fdcc8 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -18,26 +18,17 @@
import os
import subprocess
-# Default client libs
-import cinderclient.client
-import glanceclient
-import heatclient.client
-import keystoneclient.exceptions
-import keystoneclient.v2_0.client
import netaddr
from neutronclient.common import exceptions as exc
-import neutronclient.v2_0.client
-import novaclient.client
from novaclient import exceptions as nova_exceptions
-import swiftclient
from tempest.api.network import common as net_common
+from tempest import clients
from tempest.common import isolated_creds
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
-import tempest.manager
from tempest.openstack.common import log
import tempest.test
@@ -53,173 +44,6 @@
LOG_cinder_client.addHandler(log.NullHandler())
-class OfficialClientManager(tempest.manager.Manager):
- """
- Manager that provides access to the official python clients for
- calling various OpenStack APIs.
- """
-
- NOVACLIENT_VERSION = '2'
- CINDERCLIENT_VERSION = '1'
- HEATCLIENT_VERSION = '1'
-
- def __init__(self, username, password, tenant_name):
- super(OfficialClientManager, self).__init__()
- self.compute_client = self._get_compute_client(username,
- password,
- tenant_name)
- self.identity_client = self._get_identity_client(username,
- password,
- tenant_name)
- self.image_client = self._get_image_client()
- self.network_client = self._get_network_client()
- self.volume_client = self._get_volume_client(username,
- password,
- tenant_name)
- self.object_storage_client = self._get_object_storage_client(
- username,
- password,
- tenant_name)
- self.orchestration_client = self._get_orchestration_client(
- username,
- password,
- tenant_name)
-
- def _get_compute_client(self, username, password, tenant_name):
- # Novaclient will not execute operations for anyone but the
- # identified user, so a new client needs to be created for
- # each user that operations need to be performed for.
- self._validate_credentials(username, password, tenant_name)
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
- region = CONF.identity.region
-
- client_args = (username, password, tenant_name, auth_url)
-
- # Create our default Nova client to use in testing
- service_type = CONF.compute.catalog_type
- return novaclient.client.Client(self.NOVACLIENT_VERSION,
- *client_args,
- service_type=service_type,
- region_name=region,
- no_cache=True,
- insecure=dscv,
- http_log_debug=True)
-
- def _get_image_client(self):
- token = self.identity_client.auth_token
- region = CONF.identity.region
- endpoint = self.identity_client.service_catalog.url_for(
- attr='region', filter_value=region,
- service_type=CONF.image.catalog_type, endpoint_type='publicURL')
- dscv = CONF.identity.disable_ssl_certificate_validation
- return glanceclient.Client('1', endpoint=endpoint, token=token,
- insecure=dscv)
-
- def _get_volume_client(self, username, password, tenant_name):
- auth_url = CONF.identity.uri
- region = CONF.identity.region
- return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
- username,
- password,
- tenant_name,
- auth_url,
- region_name=region,
- http_log_debug=True)
-
- def _get_object_storage_client(self, username, password, tenant_name):
- auth_url = CONF.identity.uri
- # add current tenant to swift operator role group.
- keystone_admin = self._get_identity_client(
- CONF.identity.admin_username,
- CONF.identity.admin_password,
- CONF.identity.admin_tenant_name)
-
- # enable test user to operate swift by adding operator role to him.
- roles = keystone_admin.roles.list()
- operator_role = CONF.object_storage.operator_role
- member_role = [role for role in roles if role.name == operator_role][0]
- # NOTE(maurosr): This is surrounded in the try-except block cause
- # neutron tests doesn't have tenant isolation.
- try:
- keystone_admin.roles.add_user_role(self.identity_client.user_id,
- member_role.id,
- self.identity_client.tenant_id)
- except keystoneclient.exceptions.Conflict:
- pass
-
- return swiftclient.Connection(auth_url, username, password,
- tenant_name=tenant_name,
- auth_version='2')
-
- def _get_orchestration_client(self, username=None, password=None,
- tenant_name=None):
- if not username:
- username = CONF.identity.admin_username
- if not password:
- password = CONF.identity.admin_password
- if not tenant_name:
- tenant_name = CONF.identity.tenant_name
-
- self._validate_credentials(username, password, tenant_name)
-
- keystone = self._get_identity_client(username, password, tenant_name)
- region = CONF.identity.region
- token = keystone.auth_token
- service_type = CONF.orchestration.catalog_type
- try:
- endpoint = keystone.service_catalog.url_for(
- attr='region',
- filter_value=region,
- service_type=service_type,
- endpoint_type='publicURL')
- except keystoneclient.exceptions.EndpointNotFound:
- return None
- else:
- return heatclient.client.Client(self.HEATCLIENT_VERSION,
- endpoint,
- token=token,
- username=username,
- password=password)
-
- def _get_identity_client(self, username, password, tenant_name):
- # This identity client is not intended to check the security
- # of the identity service, so use admin credentials by default.
- self._validate_credentials(username, password, tenant_name)
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
-
- return keystoneclient.v2_0.client.Client(username=username,
- password=password,
- tenant_name=tenant_name,
- auth_url=auth_url,
- insecure=dscv)
-
- def _get_network_client(self):
- # The intended configuration is for the network client to have
- # admin privileges and indicate for whom resources are being
- # created via a 'tenant_id' parameter. This will often be
- # preferable to authenticating as a specific user because
- # working with certain resources (public routers and networks)
- # often requires admin privileges anyway.
- username = CONF.identity.admin_username
- password = CONF.identity.admin_password
- tenant_name = CONF.identity.admin_tenant_name
-
- self._validate_credentials(username, password, tenant_name)
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
-
- return neutronclient.v2_0.client.Client(username=username,
- password=password,
- tenant_name=tenant_name,
- auth_url=auth_url,
- insecure=dscv)
-
-
class OfficialClientTest(tempest.test.BaseTestCase):
"""
Official Client test base class for scenario testing.
@@ -242,7 +66,8 @@
username, password, tenant_name = cls.credentials()
- cls.manager = OfficialClientManager(username, password, tenant_name)
+ cls.manager = clients.OfficialClientManager(
+ username, password, tenant_name)
cls.compute_client = cls.manager.compute_client
cls.image_client = cls.manager.image_client
cls.identity_client = cls.manager.identity_client
@@ -276,6 +101,41 @@
return cls._get_credentials(cls.isolated_creds.get_admin_creds,
'admin_')
+ @staticmethod
+ def cleanup_resource(resource, test_name):
+
+ LOG.debug("Deleting %r from shared resources of %s" %
+ (resource, test_name))
+ try:
+ # OpenStack resources are assumed to have a delete()
+ # method which destroys the resource...
+ resource.delete()
+ except Exception as e:
+ # If the resource is already missing, mission accomplished.
+ # add status code as workaround for bug 1247568
+ if (e.__class__.__name__ == 'NotFound' or
+ (hasattr(e, 'status_code') and e.status_code == 404)):
+ return
+ raise
+
+ def is_deletion_complete():
+ # Deletion testing is only required for objects whose
+ # existence cannot be checked via retrieval.
+ if isinstance(resource, dict):
+ return True
+ try:
+ resource.get()
+ except Exception as e:
+ # Clients are expected to return an exception
+ # called 'NotFound' if retrieval fails.
+ if e.__class__.__name__ == 'NotFound':
+ return True
+ raise
+ return False
+
+ # Block until resource deletion has completed or timed-out
+ tempest.test.call_until_true(is_deletion_complete, 10, 1)
+
@classmethod
def tearDownClass(cls):
# NOTE(jaypipes): Because scenario tests are typically run in a
@@ -285,38 +145,7 @@
# the scenario test class object
while cls.os_resources:
thing = cls.os_resources.pop()
- LOG.debug("Deleting %r from shared resources of %s" %
- (thing, cls.__name__))
-
- try:
- # OpenStack resources are assumed to have a delete()
- # method which destroys the resource...
- thing.delete()
- except Exception as e:
- # If the resource is already missing, mission accomplished.
- # add status code as workaround for bug 1247568
- if (e.__class__.__name__ == 'NotFound' or
- hasattr(e, 'status_code') and e.status_code == 404):
- continue
- raise
-
- def is_deletion_complete():
- # Deletion testing is only required for objects whose
- # existence cannot be checked via retrieval.
- if isinstance(thing, dict):
- return True
- try:
- thing.get()
- except Exception as e:
- # Clients are expected to return an exception
- # called 'NotFound' if retrieval fails.
- if e.__class__.__name__ == 'NotFound':
- return True
- raise
- return False
-
- # Block until resource deletion has completed or timed-out
- tempest.test.call_until_true(is_deletion_complete, 10, 1)
+ cls.cleanup_resource(thing, cls.__name__)
cls.isolated_creds.clear_isolated_creds()
super(OfficialClientTest, cls).tearDownClass()
@@ -461,6 +290,27 @@
image = CONF.compute.image_ref
if flavor is None:
flavor = CONF.compute.flavor_ref
+
+ fixed_network_name = CONF.compute.fixed_network_name
+ if 'nics' not in create_kwargs and fixed_network_name:
+ networks = client.networks.list()
+ # If several networks found, set the NetID on which to connect the
+ # server to avoid the following error "Multiple possible networks
+ # found, use a Network ID to be more specific."
+ # See Tempest #1250866
+ if len(networks) > 1:
+ for network in networks:
+ if network.label == fixed_network_name:
+ create_kwargs['nics'] = [{'net-id': network.id}]
+ break
+ # If we didn't find the network we were looking for :
+ else:
+ msg = ("The network on which the NIC of the server must "
+ "be connected can not be found : "
+ "fixed_network_name=%s. Starting instance without "
+ "specifying a network.") % fixed_network_name
+ LOG.info(msg)
+
LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
name, image, flavor)
server = client.servers.create(name, image, flavor, **create_kwargs)
@@ -529,7 +379,7 @@
username = CONF.scenario.ssh_user
if private_key is None:
private_key = self.keypair.private_key
- return RemoteClient(ip, username, pkey=private_key)
+ return remote_client.RemoteClient(ip, username, pkey=private_key)
def _log_console_output(self, servers=None):
if not servers:
@@ -538,6 +388,54 @@
LOG.debug('Console output for %s', server.id)
LOG.debug(server.get_console_output())
+ def wait_for_volume_status(self, status):
+ volume_id = self.volume.id
+ self.status_timeout(
+ self.volume_client.volumes, volume_id, status)
+
+ def _image_create(self, name, fmt, path, properties={}):
+ name = data_utils.rand_name('%s-' % name)
+ image_file = open(path, 'rb')
+ self.addCleanup(image_file.close)
+ params = {
+ 'name': name,
+ 'container_format': fmt,
+ 'disk_format': fmt,
+ 'is_public': 'True',
+ }
+ params.update(properties)
+ image = self.image_client.images.create(**params)
+ self.addCleanup(self.image_client.images.delete, image)
+ self.assertEqual("queued", image.status)
+ image.update(data=image_file)
+ return image.id
+
+ def glance_image_create(self):
+ qcow2_img_path = (CONF.scenario.img_dir + "/" +
+ CONF.scenario.qcow2_img_file)
+ aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
+ ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
+ ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
+ LOG.debug("paths: img: %s, ami: %s, ari: %s, aki: %s"
+ % (qcow2_img_path, ami_img_path, ari_img_path, aki_img_path))
+ try:
+ self.image = self._image_create('scenario-img',
+ 'bare',
+ qcow2_img_path,
+ properties={'disk_format':
+ 'qcow2'})
+ except IOError:
+ LOG.debug("A qcow2 image was not found. Try to get a uec image.")
+ kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
+ ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
+ properties = {
+ 'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
+ }
+ self.image = self._image_create('scenario-ami', 'ami',
+ path=ami_img_path,
+ properties=properties)
+ LOG.debug("image:%s" % self.image)
+
class NetworkScenarioTest(OfficialClientTest):
"""
@@ -585,56 +483,65 @@
self.set_resource(name, network)
return network
- def _list_networks(self):
- nets = self.network_client.list_networks()
+ def _list_networks(self, **kwargs):
+ nets = self.network_client.list_networks(**kwargs)
return nets['networks']
- def _list_subnets(self):
- subnets = self.network_client.list_subnets()
+ def _list_subnets(self, **kwargs):
+ subnets = self.network_client.list_subnets(**kwargs)
return subnets['subnets']
- def _list_routers(self):
- routers = self.network_client.list_routers()
+ def _list_routers(self, **kwargs):
+ routers = self.network_client.list_routers(**kwargs)
return routers['routers']
- def _list_ports(self):
- ports = self.network_client.list_ports()
+ def _list_ports(self, **kwargs):
+ ports = self.network_client.list_ports(**kwargs)
return ports['ports']
def _get_tenant_own_network_num(self, tenant_id):
- nets = self._list_networks()
- ownnets = [value for value in nets if tenant_id == value['tenant_id']]
- return len(ownnets)
+ nets = self._list_networks(tenant_id=tenant_id)
+ return len(nets)
def _get_tenant_own_subnet_num(self, tenant_id):
- subnets = self._list_subnets()
- ownsubnets = ([value for value in subnets
- if tenant_id == value['tenant_id']])
- return len(ownsubnets)
+ subnets = self._list_subnets(tenant_id=tenant_id)
+ return len(subnets)
def _get_tenant_own_port_num(self, tenant_id):
- ports = self._list_ports()
- ownports = ([value for value in ports
- if tenant_id == value['tenant_id']])
- return len(ownports)
+ ports = self._list_ports(tenant_id=tenant_id)
+ return len(ports)
def _create_subnet(self, network, namestart='subnet-smoke-'):
"""
Create a subnet for the given network within the cidr block
configured for tenant networks.
"""
+
+ def cidr_in_use(cidr, tenant_id):
+ """
+ :return True if subnet with cidr already exist in tenant
+ False else
+ """
+ cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
+ return len(cidr_in_use) != 0
+
tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
result = None
# Repeatedly attempt subnet creation with sequential cidr
# blocks until an unallocated block is found.
for subnet_cidr in tenant_cidr.subnet(
CONF.network.tenant_network_mask_bits):
+ str_cidr = str(subnet_cidr)
+ if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
+ continue
+
body = dict(
subnet=dict(
+ name=data_utils.rand_name(namestart),
ip_version=4,
network_id=network.id,
tenant_id=network.tenant_id,
- cidr=str(subnet_cidr),
+ cidr=str_cidr,
),
)
try:
@@ -647,7 +554,7 @@
self.assertIsNotNone(result, 'Unable to allocate tenant network')
subnet = net_common.DeletableSubnet(client=self.network_client,
**result['subnet'])
- self.assertEqual(subnet.cidr, str(subnet_cidr))
+ self.assertEqual(subnet.cidr, str_cidr)
self.set_resource(data_utils.rand_name(namestart), subnet)
return subnet
@@ -664,19 +571,15 @@
self.set_resource(name, port)
return port
- def _get_server_port_id(self, server):
- result = self.network_client.list_ports(device_id=server.id)
- ports = result.get('ports', [])
+ def _get_server_port_id(self, server, ip_addr=None):
+ ports = self._list_ports(device_id=server.id, fixed_ip=ip_addr)
self.assertEqual(len(ports), 1,
"Unable to determine which port to target.")
return ports[0]['id']
- def _create_floating_ip(self, thing, external_network_id,
- port_filters=None):
- if port_filters is None:
+ def _create_floating_ip(self, thing, external_network_id, port_id=None):
+ if not port_id:
port_id = self._get_server_port_id(thing)
- else:
- port_id = port_filters
body = dict(
floatingip=dict(
floating_network_id=external_network_id,
@@ -1030,9 +933,6 @@
router = self._get_router(tenant_id)
subnet = self._create_subnet(network)
subnet.add_to_router(router.id)
- self.networks.append(network)
- self.subnets.append(subnet)
- self.routers.append(router)
return network, subnet, router
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index cd7a2b2..82ba3c5 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -15,10 +15,7 @@
from tempest import config
from tempest.scenario import manager
-from tempest.test import attr
-from tempest.test import call_until_true
-from tempest.test import services
-from tempest.test import skip_because
+from tempest import test
CONF = config.CONF
@@ -64,9 +61,9 @@
if not CONF.orchestration.keypair_name:
self.set_resource('stack', self.stack)
- @skip_because(bug="1257575")
- @attr(type='slow')
- @services('orchestration', 'compute')
+ @test.skip_because(bug="1257575")
+ @test.attr(type='slow')
+ @test.services('orchestration', 'compute')
def test_scale_up_then_down(self):
self.assign_keypair()
@@ -98,8 +95,8 @@
return self.server_count
def assertScale(from_servers, to_servers):
- call_until_true(lambda: server_count() == to_servers,
- timeout, interval)
+ test.call_until_true(lambda: server_count() == to_servers,
+ timeout, interval)
self.assertEqual(to_servers, self.server_count,
'Failed scaling from %d to %d servers. '
'Current server count: %s' % (
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index f2b681e..8e34c16 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -14,7 +14,7 @@
# under the License.
from tempest.common import tempest_fixtures as fixtures
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
from tempest.openstack.common import log as logging
from tempest.scenario import manager
from tempest import test
@@ -107,7 +107,7 @@
def test_aggregate_basic_ops(self):
self.useFixture(fixtures.LockFixture('availability_zone'))
az = 'foo_zone'
- aggregate_name = rand_name('aggregate-scenario')
+ aggregate_name = data_utils.rand_name('aggregate-scenario')
aggregate = self._create_aggregate(name=aggregate_name,
availability_zone=az)
@@ -119,7 +119,7 @@
self._check_aggregate_details(aggregate, aggregate_name, az, [host],
metadata)
- aggregate_name = rand_name('renamed-aggregate-scenario')
+ aggregate_name = data_utils.rand_name('renamed-aggregate-scenario')
aggregate = self._update_aggregate(aggregate, aggregate_name, None)
additional_metadata = {'foo': 'bar'}
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 19996e5..6418a73 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -19,7 +19,7 @@
from tempest import config
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -69,7 +69,7 @@
response = self.opener.open(CONF.dashboard.dashboard_url)
self.assertIn('Overview', response.read())
- @services('dashboard')
+ @test.services('dashboard')
def test_basic_scenario(self):
self.check_login_page()
self.user_login()
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index e8030c9..b7a30f8 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -17,7 +17,7 @@
from tempest import config
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -47,43 +47,6 @@
self.status_timeout(
self.compute_client.servers, server.id, status)
- def _wait_for_volume_status(self, status):
- volume_id = self.volume.id
- self.status_timeout(
- self.volume_client.volumes, volume_id, status)
-
- def _image_create(self, name, fmt, path, properties={}):
- name = data_utils.rand_name('%s-' % name)
- image_file = open(path, 'rb')
- self.addCleanup(image_file.close)
- params = {
- 'name': name,
- 'container_format': fmt,
- 'disk_format': fmt,
- 'is_public': 'True',
- }
- params.update(properties)
- image = self.image_client.images.create(**params)
- self.addCleanup(self.image_client.images.delete, image)
- self.assertEqual("queued", image.status)
- image.update(data=image_file)
- return image.id
-
- def glance_image_create(self):
- aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
- ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
- ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
- LOG.debug("paths: ami: %s, ari: %s, aki: %s"
- % (ami_img_path, ari_img_path, aki_img_path))
- kernel_id = self._image_create('scenario-aki', 'aki', aki_img_path)
- ramdisk_id = self._image_create('scenario-ari', 'ari', ari_img_path)
- properties = {
- 'properties': {'kernel_id': kernel_id, 'ramdisk_id': ramdisk_id}
- }
- self.image = self._image_create('scenario-ami', 'ami',
- path=ami_img_path,
- properties=properties)
-
def nova_boot(self):
name = data_utils.rand_name('scenario-server-')
client = self.compute_client
@@ -100,7 +63,7 @@
self.set_resource(server.name, server)
self._wait_for_server_status('ACTIVE')
- @services('compute', 'image')
+ @test.services('compute', 'image')
def test_large_ops_scenario(self):
if CONF.scenario.large_ops_number < 1:
return
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 68f6e62..5bcdacd 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -61,12 +61,8 @@
super(TestLoadBalancerBasic, cls).setUpClass()
cls.check_preconditions()
cls.security_groups = {}
- cls.networks = []
- cls.subnets = []
cls.servers_keypairs = {}
- cls.pools = []
cls.members = []
- cls.vips = []
cls.floating_ips = {}
cls.port1 = 80
cls.port2 = 88
@@ -80,21 +76,19 @@
name = data_utils.rand_name("smoke_server-")
keypair = self.create_keypair(name='keypair-%s' % name)
security_groups = [self.security_groups[tenant_id].name]
- nets = self.network_client.list_networks()
- for net in nets['networks']:
- if net['tenant_id'] == self.tenant_id:
- self.networks.append(net)
- create_kwargs = {
- 'nics': [
- {'net-id': net['id']},
- ],
- 'key_name': keypair.name,
- 'security_groups': security_groups,
- }
- server = self.create_server(name=name,
- create_kwargs=create_kwargs)
- self.servers_keypairs[server] = keypair
- break
+ net = self.list_networks(tenant_id=self.tenant_id)[0]
+ self.network = net_common.DeletableNetwork(client=self.network_client,
+ **net['network'])
+ create_kwargs = {
+ 'nics': [
+ {'net-id': self.network.id},
+ ],
+ 'key_name': keypair.name,
+ 'security_groups': security_groups,
+ }
+ server = self.create_server(name=name,
+ create_kwargs=create_kwargs)
+ self.servers_keypairs[server] = keypair
self.assertTrue(self.servers_keypairs)
def _start_servers(self):
@@ -105,7 +99,7 @@
for server in self.servers_keypairs.keys():
ssh_login = config.compute.image_ssh_user
private_key = self.servers_keypairs[server].private_key
- network_name = self.networks[0]['name']
+ network_name = self.network.name
ip_address = server.networks[network_name][0]
ssh_client = ssh.Client(ip_address, ssh_login,
@@ -138,17 +132,15 @@
def _create_pool(self):
"""Create a pool with ROUND_ROBIN algorithm."""
- subnets = self.network_client.list_subnets()
- for subnet in subnets['subnets']:
- if subnet['tenant_id'] == self.tenant_id:
- self.subnets.append(subnet)
- pool = super(TestLoadBalancerBasic, self)._create_pool(
- 'ROUND_ROBIN',
- 'HTTP',
- subnet['id'])
- self.pools.append(pool)
- break
- self.assertTrue(self.pools)
+ # get tenant subnet and verify there's only one
+ subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
+ self.subnet = net_common.DeletableSubnet(client=self.network_client,
+ **subnet['subnet'])
+ self.pool = super(TestLoadBalancerBasic, self)._create_pool(
+ 'ROUND_ROBIN',
+ 'HTTP',
+ self.subnet.id)
+ self.assertTrue(self.pool)
def _create_members(self, network_name, server_ids):
"""
@@ -161,7 +153,7 @@
for server in servers:
if server.id in server_ids:
ip = server.networks[network_name][0]
- pool_id = self.pools[0]['id']
+ pool_id = self.pool.id
if len(set(server_ids)) == 1 or len(servers) == 1:
member1 = self._create_member(ip, self.port1, pool_id)
member2 = self._create_member(ip, self.port2, pool_id)
@@ -173,29 +165,27 @@
def _assign_floating_ip_to_vip(self, vip):
public_network_id = config.network.public_network_id
- port_id = vip['port_id']
- floating_ip = self._create_floating_ip(vip,
- public_network_id,
- port_filters=port_id)
- self.floating_ips.setdefault(vip['id'], [])
- self.floating_ips[vip['id']].append(floating_ip)
+ port_id = vip.port_id
+ floating_ip = self._create_floating_ip(vip, public_network_id,
+ port_id=port_id)
+ self.floating_ips.setdefault(vip.id, [])
+ self.floating_ips[vip.id].append(floating_ip)
def _create_load_balancer(self):
self._create_pool()
- self._create_members(self.networks[0]['name'],
+ self._create_members(self.network.name,
[self.servers_keypairs.keys()[0].id])
- subnet_id = self.subnets[0]['id']
- pool_id = self.pools[0]['id']
- vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
- subnet_id,
- pool_id)
- self.vips.append(vip)
+ subnet_id = self.subnet.id
+ pool_id = self.pool.id
+ self.vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
+ subnet_id,
+ pool_id)
self._status_timeout(NeutronRetriever(self.network_client,
self.network_client.vip_path,
net_common.DeletableVip),
- self.vips[0]['id'],
+ self.vip.id,
expected_status='ACTIVE')
- self._assign_floating_ip_to_vip(self.vips[0])
+ self._assign_floating_ip_to_vip(self.vip)
def _check_load_balancing(self):
"""
@@ -205,9 +195,8 @@
of the requests
"""
- vip = self.vips[0]
- floating_ip_vip = self.floating_ips[
- vip['id']][0]['floating_ip_address']
+ vip = self.vip
+ floating_ip_vip = self.floating_ips[vip.id][0]['floating_ip_address']
self._check_connection(floating_ip_vip)
resp = []
for count in range(10):
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index e868075..39b7760 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common.utils import data_utils
+from tempest.common import debug
from tempest import config
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -42,43 +42,6 @@
self.status_timeout(
self.compute_client.servers, server_id, status)
- def _wait_for_volume_status(self, status):
- volume_id = self.volume.id
- self.status_timeout(
- self.volume_client.volumes, volume_id, status)
-
- def _image_create(self, name, fmt, path, properties={}):
- name = data_utils.rand_name('%s-' % name)
- image_file = open(path, 'rb')
- self.addCleanup(image_file.close)
- params = {
- 'name': name,
- 'container_format': fmt,
- 'disk_format': fmt,
- 'is_public': 'True',
- }
- params.update(properties)
- image = self.image_client.images.create(**params)
- self.addCleanup(self.image_client.images.delete, image)
- self.assertEqual("queued", image.status)
- image.update(data=image_file)
- return image.id
-
- def glance_image_create(self):
- aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
- ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
- ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
- LOG.debug("paths: ami: %s, ari: %s, aki: %s"
- % (ami_img_path, ari_img_path, aki_img_path))
- kernel_id = self._image_create('scenario-aki', 'aki', aki_img_path)
- ramdisk_id = self._image_create('scenario-ari', 'ari', ari_img_path)
- properties = {
- 'properties': {'kernel_id': kernel_id, 'ramdisk_id': ramdisk_id}
- }
- self.image = self._image_create('scenario-ami', 'ami',
- path=ami_img_path,
- properties=properties)
-
def nova_keypair_add(self):
self.keypair = self.create_keypair()
@@ -114,7 +77,7 @@
self.volume.id,
'/dev/vdb')
self.assertEqual(self.volume.id, volume.id)
- self._wait_for_volume_status('in-use')
+ self.wait_for_volume_status('in-use')
def nova_reboot(self):
self.server.reboot()
@@ -134,6 +97,7 @@
except Exception:
LOG.exception('ssh to server failed')
self._log_console_output()
+ debug.log_ip_ns()
raise
def check_partitions(self):
@@ -143,12 +107,12 @@
def nova_volume_detach(self):
detach_volume_client = self.compute_client.volumes.delete_server_volume
detach_volume_client(self.server.id, self.volume.id)
- self._wait_for_volume_status('available')
+ self.wait_for_volume_status('available')
volume = self.volume_client.volumes.get(self.volume.id)
self.assertEqual('available', volume.status)
- @services('compute', 'volume', 'image', 'network')
+ @test.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
self.glance_image_create()
self.nova_keypair_add()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 0c0234f..998a474 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -13,6 +13,7 @@
# 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 collections
from tempest.common import debug
from tempest.common.utils import data_utils
@@ -24,6 +25,9 @@
CONF = config.CONF
LOG = logging.getLogger(__name__)
+Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple',
+ ['floating_ip', 'server'])
+
class TestNetworkBasicOps(manager.NetworkScenarioTest):
@@ -116,46 +120,57 @@
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
cls.check_preconditions()
- # TODO(mnewby) Consider looking up entities as needed instead
- # of storing them as collections on the class.
- cls.security_groups = {}
- cls.networks = []
- cls.subnets = []
- cls.routers = []
- cls.servers = {}
- cls.floating_ips = {}
- def _create_security_groups(self):
- self.security_groups[self.tenant_id] =\
+ def cleanup_wrapper(self, resource):
+ self.cleanup_resource(resource, self.__class__.__name__)
+
+ def setUp(self):
+ super(TestNetworkBasicOps, self).setUp()
+ self.security_group = \
self._create_security_group_neutron(tenant_id=self.tenant_id)
+ self.addCleanup(self.cleanup_wrapper, self.security_group)
+ self.network, self.subnet, self.router = self._create_networks()
+ for r in [self.network, self.router, self.subnet]:
+ self.addCleanup(self.cleanup_wrapper, r)
+ self.check_networks()
+ self.servers = {}
+ name = data_utils.rand_name('server-smoke')
+ serv_dict = self._create_server(name, self.network)
+ self.servers[serv_dict['server']] = serv_dict['keypair']
+ self._check_tenant_network_connectivity()
- def _check_networks(self):
- # Checks that we see the newly created network/subnet/router via
- # checking the result of list_[networks,routers,subnets]
+ self._create_and_associate_floating_ips()
+
+ def check_networks(self):
+ """
+ Checks that we see the newly created network/subnet/router via
+ checking the result of list_[networks,routers,subnets]
+ """
+
seen_nets = self._list_networks()
seen_names = [n['name'] for n in seen_nets]
seen_ids = [n['id'] for n in seen_nets]
- for mynet in self.networks:
- self.assertIn(mynet.name, seen_names)
- self.assertIn(mynet.id, seen_ids)
+ self.assertIn(self.network.name, seen_names)
+ self.assertIn(self.network.id, seen_ids)
+
seen_subnets = self._list_subnets()
seen_net_ids = [n['network_id'] for n in seen_subnets]
seen_subnet_ids = [n['id'] for n in seen_subnets]
- for mynet in self.networks:
- self.assertIn(mynet.id, seen_net_ids)
- for mysubnet in self.subnets:
- self.assertIn(mysubnet.id, seen_subnet_ids)
+ self.assertIn(self.network.id, seen_net_ids)
+ self.assertIn(self.subnet.id, seen_subnet_ids)
+
seen_routers = self._list_routers()
seen_router_ids = [n['id'] for n in seen_routers]
seen_router_names = [n['name'] for n in seen_routers]
- for myrouter in self.routers:
- self.assertIn(myrouter.name, seen_router_names)
- self.assertIn(myrouter.id, seen_router_ids)
+ self.assertIn(self.router.name,
+ seen_router_names)
+ self.assertIn(self.router.id,
+ seen_router_ids)
def _create_server(self, name, network):
- tenant_id = network.tenant_id
keypair = self.create_keypair(name='keypair-%s' % name)
- security_groups = [self.security_groups[tenant_id].name]
+ self.addCleanup(self.cleanup_wrapper, keypair)
+ security_groups = [self.security_group.name]
create_kwargs = {
'nics': [
{'net-id': network.id},
@@ -164,13 +179,8 @@
'security_groups': security_groups,
}
server = self.create_server(name=name, create_kwargs=create_kwargs)
- self.servers[server] = keypair
- return server
-
- def _create_servers(self):
- for i, network in enumerate(self.networks):
- name = data_utils.rand_name('server-smoke-%d-' % i)
- self._create_server(name, network)
+ self.addCleanup(self.cleanup_wrapper, server)
+ return dict(server=server, keypair=keypair)
def _check_tenant_network_connectivity(self):
if not CONF.network.tenant_networks_reachable:
@@ -181,7 +191,7 @@
# key-based authentication by cloud-init.
ssh_login = CONF.compute.image_ssh_user
try:
- for server, key in self.servers.items():
+ for server, key in self.servers.iteritems():
for net_name, ip_addresses in server.networks.iteritems():
for ip_address in ip_addresses:
self._check_vm_connectivity(ip_address, ssh_login,
@@ -196,7 +206,8 @@
public_network_id = CONF.network.public_network_id
for server in self.servers.keys():
floating_ip = self._create_floating_ip(server, public_network_id)
- self.floating_ips[floating_ip] = server
+ self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
+ self.addCleanup(self.cleanup_wrapper, floating_ip)
def _check_public_network_connectivity(self, should_connect=True,
msg=None):
@@ -204,16 +215,16 @@
# key-based authentication by cloud-init.
ssh_login = CONF.compute.image_ssh_user
LOG.debug('checking network connections')
+ floating_ip, server = self.floating_ip_tuple
+ ip_address = floating_ip.floating_ip_address
+ private_key = None
+ if should_connect:
+ private_key = self.servers[server].private_key
try:
- for floating_ip, server in self.floating_ips.iteritems():
- ip_address = floating_ip.floating_ip_address
- private_key = None
- if should_connect:
- private_key = self.servers[server].private_key
- self._check_vm_connectivity(ip_address,
- ssh_login,
- private_key,
- should_connect=should_connect)
+ self._check_vm_connectivity(ip_address,
+ ssh_login,
+ private_key,
+ should_connect=should_connect)
except Exception:
ex_msg = 'Public network connectivity check failed'
if msg:
@@ -224,28 +235,24 @@
raise
def _disassociate_floating_ips(self):
- for floating_ip, server in self.floating_ips.iteritems():
- self._disassociate_floating_ip(floating_ip)
- self.floating_ips[floating_ip] = None
+ floating_ip, server = self.floating_ip_tuple
+ self._disassociate_floating_ip(floating_ip)
+ self.floating_ip_tuple = Floating_IP_tuple(
+ floating_ip, None)
def _reassociate_floating_ips(self):
- network = self.networks[0]
- for floating_ip in self.floating_ips.keys():
- name = data_utils.rand_name('new_server-smoke-')
- # create a new server for the floating ip
- server = self._create_server(name, network)
- self._associate_floating_ip(floating_ip, server)
- self.floating_ips[floating_ip] = server
+ floating_ip, server = self.floating_ip_tuple
+ name = data_utils.rand_name('new_server-smoke-')
+ # create a new server for the floating ip
+ serv_dict = self._create_server(name, self.network)
+ self.servers[serv_dict['server']] = serv_dict['keypair']
+ self._associate_floating_ip(floating_ip, serv_dict['server'])
+ self.floating_ip_tuple = Floating_IP_tuple(
+ floating_ip, serv_dict['server'])
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_network_basic_ops(self):
- self._create_security_groups()
- self._create_networks()
- self._check_networks()
- self._create_servers()
- self._create_and_associate_floating_ips()
- self._check_tenant_network_connectivity()
self._check_public_network_connectivity(should_connect=True)
self._disassociate_floating_ips()
self._check_public_network_connectivity(should_connect=False,
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_security_groups_basic_ops.py
similarity index 77%
rename from tempest/scenario/test_cross_tenant_connectivity.py
rename to tempest/scenario/test_security_groups_basic_ops.py
index edcf091..a26e0cf 100644
--- a/tempest/scenario/test_cross_tenant_connectivity.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -13,23 +13,21 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import clients
from tempest.common import debug
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.scenario.manager import OfficialClientManager
-from tempest.test import attr
-from tempest.test import call_until_true
-from tempest.test import services
+from tempest import test
CONF = config.CONF
LOG = logging.getLogger(__name__)
-class TestNetworkCrossTenant(manager.NetworkScenarioTest):
+class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest):
"""
This test suite assumes that Nova has been configured to
@@ -50,7 +48,7 @@
failure - ping_timeout reached
setup:
- for each tenant (demo and alt):
+ for primary tenant:
1. create a network&subnet
2. create a router (if public router isn't configured)
3. connect tenant network to public network via router
@@ -59,8 +57,6 @@
b. a VM with a floating ip
5. create a general empty security group (same as "default", but
without rules allowing in-tenant traffic)
- 6. for demo tenant - create another server to test in-tenant
- connections
tests:
1. _verify_network_details
@@ -80,7 +76,7 @@
been created on source tenant
assumptions:
- 1. alt_tenant/user existed and is different from demo_tenant/user
+ 1. alt_tenant/user existed and is different from primary_tenant/user
2. Public network is defined and reachable from the Tempest host
3. Public router can either be:
* defined, in which case all tenants networks can connect directly
@@ -92,7 +88,7 @@
"""
class TenantProperties():
- '''
+ """
helper class to save tenant details
id
credentials
@@ -101,14 +97,15 @@
security groups
servers
access point
- '''
+ """
def __init__(self, tenant_id, tenant_user, tenant_pass, tenant_name):
- self.manager = OfficialClientManager(
+ self.manager = clients.OfficialClientManager(
tenant_user,
tenant_pass,
tenant_name
)
+ self.keypair = None
self.tenant_id = tenant_id
self.tenant_name = tenant_name
self.tenant_user = tenant_user
@@ -119,7 +116,7 @@
self.security_groups = {}
self.servers = list()
- def _set_network(self, network, subnet, router):
+ def set_network(self, network, subnet, router):
self.network = network
self.subnet = subnet
self.router = router
@@ -129,7 +126,7 @@
@classmethod
def check_preconditions(cls):
- super(TestNetworkCrossTenant, cls).check_preconditions()
+ super(TestSecurityGroupsBasicOps, cls).check_preconditions()
if (cls.alt_tenant_id is None) or (cls.tenant_id is cls.alt_tenant_id):
msg = 'No alt_tenant defined'
cls.enabled = False
@@ -143,7 +140,7 @@
@classmethod
def setUpClass(cls):
- super(TestNetworkCrossTenant, cls).setUpClass()
+ super(TestSecurityGroupsBasicOps, cls).setUpClass()
alt_creds = cls.alt_credentials()
cls.alt_tenant_id = cls.manager._get_identity_client(
*alt_creds
@@ -151,48 +148,44 @@
cls.check_preconditions()
# TODO(mnewby) Consider looking up entities as needed instead
# of storing them as collections on the class.
- cls.keypairs = {}
- cls.security_groups = {}
- cls.networks = []
- cls.subnets = []
- cls.routers = []
- cls.servers = []
cls.floating_ips = {}
cls.tenants = {}
- cls.demo_tenant = cls.TenantProperties(
- cls.tenant_id,
- *cls.credentials()
- )
- cls.alt_tenant = cls.TenantProperties(
- cls.alt_tenant_id,
- *alt_creds
- )
- for tenant in [cls.demo_tenant, cls.alt_tenant]:
+ cls.primary_tenant = cls.TenantProperties(cls.tenant_id,
+ *cls.credentials())
+ cls.alt_tenant = cls.TenantProperties(cls.alt_tenant_id,
+ *alt_creds)
+ for tenant in [cls.primary_tenant, cls.alt_tenant]:
cls.tenants[tenant.tenant_id] = tenant
- if not CONF.network.public_router_id:
- cls.floating_ip_access = True
- else:
- cls.floating_ip_access = False
+ cls.floating_ip_access = not CONF.network.public_router_id
- @classmethod
- def tearDownClass(cls):
- super(TestNetworkCrossTenant, cls).tearDownClass()
+ def cleanup_wrapper(self, resource):
+ self.cleanup_resource(resource, self.__class__.__name__)
+
+ def setUp(self):
+ super(TestSecurityGroupsBasicOps, self).setUp()
+ self._deploy_tenant(self.primary_tenant)
+ self._verify_network_details(self.primary_tenant)
+ self._verify_mac_addr(self.primary_tenant)
def _create_tenant_keypairs(self, tenant_id):
- self.keypairs[tenant_id] = self.create_keypair(
+ keypair = self.create_keypair(
name=data_utils.rand_name('keypair-smoke-'))
+ self.addCleanup(self.cleanup_wrapper, keypair)
+ self.tenants[tenant_id].keypair = keypair
def _create_tenant_security_groups(self, tenant):
- self.security_groups.setdefault(self.tenant_id, [])
access_sg = self._create_empty_security_group(
namestart='secgroup_access-',
tenant_id=tenant.tenant_id
)
+ self.addCleanup(self.cleanup_wrapper, access_sg)
+
# don't use default secgroup since it allows in-tenant traffic
def_sg = self._create_empty_security_group(
namestart='secgroup_general-',
tenant_id=tenant.tenant_id
)
+ self.addCleanup(self.cleanup_wrapper, def_sg)
tenant.security_groups.update(access=access_sg, default=def_sg)
ssh_rule = dict(
protocol='tcp',
@@ -200,9 +193,9 @@
port_range_max=22,
direction='ingress',
)
- self._create_security_group_rule(secgroup=access_sg,
- **ssh_rule
- )
+ rule = self._create_security_group_rule(secgroup=access_sg,
+ **ssh_rule)
+ self.addCleanup(self.cleanup_wrapper, rule)
def _verify_network_details(self, tenant):
# Checks that we see the newly created network/subnet/router via
@@ -245,11 +238,12 @@
'nics': [
{'net-id': tenant.network.id},
],
- 'key_name': self.keypairs[tenant.tenant_id].name,
+ 'key_name': tenant.keypair.name,
'security_groups': security_groups,
'tenant_id': tenant.tenant_id
}
server = self.create_server(name=name, create_kwargs=create_kwargs)
+ self.addCleanup(self.cleanup_wrapper, server)
return server
def _create_tenant_servers(self, tenant, num=1):
@@ -260,7 +254,6 @@
)
name = data_utils.rand_name(name)
server = self._create_server(name, tenant)
- self.servers.append(server)
tenant.servers.append(server)
def _set_access_point(self, tenant):
@@ -275,17 +268,20 @@
name = data_utils.rand_name(name)
server = self._create_server(name, tenant,
security_groups=secgroups)
- self.servers.append(server)
tenant.access_point = server
self._assign_floating_ips(server)
def _assign_floating_ips(self, server):
public_network_id = CONF.network.public_network_id
floating_ip = self._create_floating_ip(server, public_network_id)
+ self.addCleanup(self.cleanup_wrapper, floating_ip)
self.floating_ips.setdefault(server, floating_ip)
def _create_tenant_network(self, tenant):
- tenant._set_network(*self._create_networks(tenant.tenant_id))
+ network, subnet, router = self._create_networks(tenant.tenant_id)
+ for r in [network, router, subnet]:
+ self.addCleanup(self.cleanup_wrapper, r)
+ tenant.set_network(network, subnet, router)
def _set_compute_context(self, tenant):
self.compute_client = tenant.manager.compute_client
@@ -299,8 +295,6 @@
router (if public not defined)
access security group
access-point server
- for demo_tenant:
- creates general server to test against
"""
if not isinstance(tenant_or_id, self.TenantProperties):
tenant = self.tenants[tenant_or_id]
@@ -312,19 +306,20 @@
self._create_tenant_keypairs(tenant_id)
self._create_tenant_network(tenant)
self._create_tenant_security_groups(tenant)
- if tenant is self.demo_tenant:
- self._create_tenant_servers(tenant, num=1)
self._set_access_point(tenant)
def _get_server_ip(self, server, floating=False):
- '''
+ """
returns the ip (floating/internal) of a server
- '''
+ """
if floating:
- return self.floating_ips[server].floating_ip_address
+ server_ip = self.floating_ips[server].floating_ip_address
else:
+ server_ip = None
network_name = self.tenants[server.tenant_id].network.name
- return server.networks[network_name][0]
+ if network_name in server.networks:
+ server_ip = server.networks[network_name][0]
+ return server_ip
def _connect_to_access_point(self, tenant):
"""
@@ -332,7 +327,7 @@
"""
access_point_ssh = \
self.floating_ips[tenant.access_point].floating_ip_address
- private_key = self.keypairs[tenant.tenant_id].private_key
+ private_key = tenant.keypair.private_key
access_point_ssh = self._ssh_to_server(access_point_ssh,
private_key=private_key)
return access_point_ssh
@@ -355,9 +350,9 @@
return not should_succeed
return should_succeed
- return call_until_true(ping_remote,
- CONF.compute.ping_timeout,
- 1)
+ return test.call_until_true(ping_remote,
+ CONF.compute.ping_timeout,
+ 1)
def _check_connectivity(self, access_point, ip, should_succeed=True):
if should_succeed:
@@ -391,17 +386,17 @@
secgroup=tenant.security_groups['default'],
**ruleset
)
+ self.addCleanup(self.cleanup_wrapper, rule)
access_point_ssh = self._connect_to_access_point(tenant)
for server in tenant.servers:
self._check_connectivity(access_point=access_point_ssh,
ip=self._get_server_ip(server))
- rule.delete()
def _test_cross_tenant_block(self, source_tenant, dest_tenant):
- '''
+ """
if public router isn't defined, then dest_tenant access is via
floating-ip
- '''
+ """
access_point_ssh = self._connect_to_access_point(source_tenant)
ip = self._get_server_ip(dest_tenant.access_point,
floating=self.floating_ip_access)
@@ -409,10 +404,10 @@
should_succeed=False)
def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
- '''
+ """
check for each direction:
creating rule for tenant incoming traffic enables only 1way traffic
- '''
+ """
ruleset = dict(
protocol='icmp',
direction='ingress'
@@ -421,37 +416,26 @@
secgroup=dest_tenant.security_groups['default'],
**ruleset
)
- try:
- access_point_ssh = self._connect_to_access_point(source_tenant)
- ip = self._get_server_ip(dest_tenant.access_point,
- floating=self.floating_ip_access)
- self._check_connectivity(access_point_ssh, ip)
+ self.addCleanup(self.cleanup_wrapper, rule_s2d)
+ access_point_ssh = self._connect_to_access_point(source_tenant)
+ ip = self._get_server_ip(dest_tenant.access_point,
+ floating=self.floating_ip_access)
+ self._check_connectivity(access_point_ssh, ip)
- # test that reverse traffic is still blocked
- self._test_cross_tenant_block(dest_tenant, source_tenant)
+ # test that reverse traffic is still blocked
+ self._test_cross_tenant_block(dest_tenant, source_tenant)
- # allow reverse traffic and check
- rule_d2s = self._create_security_group_rule(
- secgroup=source_tenant.security_groups['default'],
- **ruleset
- )
- try:
- access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
- ip = self._get_server_ip(source_tenant.access_point,
- floating=self.floating_ip_access)
- self._check_connectivity(access_point_ssh_2, ip)
+ # allow reverse traffic and check
+ rule_d2s = self._create_security_group_rule(
+ secgroup=source_tenant.security_groups['default'],
+ **ruleset
+ )
+ self.addCleanup(self.cleanup_wrapper, rule_d2s)
- # clean_rules
- rule_s2d.delete()
- rule_d2s.delete()
-
- except Exception as e:
- rule_d2s.delete()
- raise e
-
- except Exception as e:
- rule_s2d.delete()
- raise e
+ access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
+ ip = self._get_server_ip(source_tenant.access_point,
+ floating=self.floating_ip_access)
+ self._check_connectivity(access_point_ssh_2, ip)
def _verify_mac_addr(self, tenant):
"""
@@ -471,24 +455,36 @@
subnet_id = tenant.subnet.id
self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list)
- @attr(type='smoke')
- @services('compute', 'network')
+ @test.attr(type='smoke')
+ @test.services('compute', 'network')
def test_cross_tenant_traffic(self):
try:
- for tenant_id in self.tenants.keys():
- self._deploy_tenant(tenant_id)
- self._verify_network_details(self.tenants[tenant_id])
- self._verify_mac_addr(self.tenants[tenant_id])
-
- # in-tenant check
- self._test_in_tenant_block(self.demo_tenant)
- self._test_in_tenant_allow(self.demo_tenant)
+ # deploy new tenant
+ self._deploy_tenant(self.alt_tenant)
+ self._verify_network_details(self.alt_tenant)
+ self._verify_mac_addr(self.alt_tenant)
# cross tenant check
- source_tenant = self.demo_tenant
+ source_tenant = self.primary_tenant
dest_tenant = self.alt_tenant
self._test_cross_tenant_block(source_tenant, dest_tenant)
self._test_cross_tenant_allow(source_tenant, dest_tenant)
except Exception:
- self._log_console_output(servers=self.servers)
+ for tenant in self.tenants.values():
+ self._log_console_output(servers=tenant.servers)
+ raise
+
+ @test.attr(type='smoke')
+ @test.services('compute', 'network')
+ def test_in_tenant_traffic(self):
+ try:
+ self._create_tenant_servers(self.primary_tenant, num=1)
+
+ # in-tenant check
+ self._test_in_tenant_block(self.primary_tenant)
+ self._test_in_tenant_allow(self.primary_tenant)
+
+ except Exception:
+ for tenant in self.tenants.values():
+ self._log_console_output(servers=tenant.servers)
raise
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 9626157..c0eb6e7 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -16,7 +16,7 @@
from tempest import config
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -47,7 +47,7 @@
msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
raise cls.skipException(msg)
- @services('compute')
+ @test.services('compute')
def test_resize_server_confirm(self):
# We create an instance for use in this test
instance = self.create_server()
@@ -65,7 +65,7 @@
self.status_timeout(
self.compute_client.servers, instance_id, 'ACTIVE')
- @services('compute')
+ @test.services('compute')
def test_server_sequence_suspend_resume(self):
# We create an instance for use in this test
instance = self.create_server()
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 57e7a22..d369f12 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -18,7 +18,7 @@
from tempest import config
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
import testscenarios
@@ -158,7 +158,7 @@
self._log_console_output()
raise
- @services('compute', 'network')
+ @test.services('compute', 'network')
def test_server_basicops(self):
self.add_keypair()
self.create_security_group()
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 2bb3d84..37beb07 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -16,7 +16,7 @@
from tempest import config
from tempest.openstack.common import log
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -69,7 +69,7 @@
def _set_floating_ip_to_server(self, server, floating_ip):
server.add_floating_ip(floating_ip)
- @services('compute', 'network', 'image')
+ @test.services('compute', 'network', 'image')
def test_snapshot_pattern(self):
# prepare for booting a instance
self._add_keypair()
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index 60df606..86e0867 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -14,11 +14,11 @@
# under the License.
-from tempest.common.utils.data_utils import rand_name
+from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -53,7 +53,8 @@
LOG.debug('Swift status information obtained successfully')
def _create_container(self, container_name=None):
- name = container_name or rand_name('swift-scenario-container')
+ name = container_name or data_utils.rand_name(
+ 'swift-scenario-container')
self.object_storage_client.put_container(name)
# look for the container to assure it is created
self._list_and_check_container_objects(name)
@@ -65,9 +66,9 @@
LOG.debug('Container %s deleted' % (container_name))
def _upload_object_to_container(self, container_name, obj_name=None):
- obj_name = obj_name or rand_name('swift-scenario-object')
+ obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
self.object_storage_client.put_object(container_name, obj_name,
- rand_name('obj_data'),
+ data_utils.rand_name('obj_data'),
content_type='text/plain')
return obj_name
@@ -93,7 +94,7 @@
for obj in not_present_obj:
self.assertNotIn(obj, object_list)
- @services('object_storage')
+ @test.services('object_storage')
def test_swift_basic_ops(self):
self._get_swift_stat()
container_name = self._create_container()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 7b002eb..9a250d7 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -14,7 +14,7 @@
from tempest import config
from tempest.openstack.common import log
from tempest.scenario import manager
-from tempest.test import services
+from tempest import test
CONF = config.CONF
@@ -127,7 +127,7 @@
actual = self._get_content(ssh_client)
self.assertEqual(expected, actual)
- @services('compute', 'volume', 'image')
+ @test.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
keypair = self.create_keypair()
self._create_loginable_secgroup_rule_nova()
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 03e87b1..b52d48c 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -35,6 +35,7 @@
def __init__(self, username=None, password=None,
auth_url=None, tenant_name=None,
*args, **kwargs):
+ # FIXME(andreaf) replace credentials and auth_url with auth_provider
self.connection_timeout = str(CONF.boto.http_socket_timeout)
self.num_retries = str(CONF.boto.num_retries)
@@ -45,6 +46,7 @@
"tenant_name": tenant_name}
def _keystone_aws_get(self):
+ # FIXME(andreaf) Move EC2 credentials to AuthProvider
import keystoneclient.v2_0.client
keystone = keystoneclient.v2_0.client.Client(**self.ks_cred)
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 89906f3..2cd2d2e 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -123,3 +123,10 @@
if sg['id'] == security_group_id:
return resp, sg['rules']
raise exceptions.NotFound('No such Security Group')
+
+ def is_resource_deleted(self, id):
+ try:
+ self.get_security_group(id)
+ except exceptions.NotFound:
+ return True
+ return False
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index a01b9d2..aa8bfaf 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -35,6 +35,14 @@
body = json.loads(body)
return resp, body['quota_set']
+ def get_quota_set_detail(self, tenant_id):
+ """Get the quota set detail for a tenant."""
+
+ url = 'os-quota-sets/%s/detail' % str(tenant_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['quota_set']
+
def get_default_quota_set(self, tenant_id):
"""List the default quota set for a tenant."""
diff --git a/tempest/services/compute/xml/aggregates_client.py b/tempest/services/compute/xml/aggregates_client.py
index cf853ba..5b250ee 100644
--- a/tempest/services/compute/xml/aggregates_client.py
+++ b/tempest/services/compute/xml/aggregates_client.py
@@ -15,7 +15,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -26,7 +26,8 @@
CONF = config.CONF
-class AggregatesClientXML(RestClientXML):
+class AggregatesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(AggregatesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/availability_zone_client.py b/tempest/services/compute/xml/availability_zone_client.py
index 3d8ac8a..4d71186 100644
--- a/tempest/services/compute/xml/availability_zone_client.py
+++ b/tempest/services/compute/xml/availability_zone_client.py
@@ -15,14 +15,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class AvailabilityZoneClientXML(RestClientXML):
+class AvailabilityZoneClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(AvailabilityZoneClientXML, self).__init__(
diff --git a/tempest/services/compute/xml/certificates_client.py b/tempest/services/compute/xml/certificates_client.py
index 4ee10c4..24ffca8 100644
--- a/tempest/services/compute/xml/certificates_client.py
+++ b/tempest/services/compute/xml/certificates_client.py
@@ -14,13 +14,14 @@
# under the License.
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class CertificatesClientXML(RestClientXML):
+class CertificatesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(CertificatesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/extensions_client.py b/tempest/services/compute/xml/extensions_client.py
index f97b64d..3e8254c 100644
--- a/tempest/services/compute/xml/extensions_client.py
+++ b/tempest/services/compute/xml/extensions_client.py
@@ -15,14 +15,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class ExtensionsClientXML(RestClientXML):
+class ExtensionsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ExtensionsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/fixed_ips_client.py b/tempest/services/compute/xml/fixed_ips_client.py
index b89e096..0475530 100644
--- a/tempest/services/compute/xml/fixed_ips_client.py
+++ b/tempest/services/compute/xml/fixed_ips_client.py
@@ -14,7 +14,7 @@
# under the License.
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -23,7 +23,8 @@
CONF = config.CONF
-class FixedIPsClientXML(RestClientXML):
+class FixedIPsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(FixedIPsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index 554b253..68a27c9 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -33,7 +33,8 @@
"http://docs.openstack.org/compute/ext/flavor_access/api/v2"
-class FlavorsClientXML(RestClientXML):
+class FlavorsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(FlavorsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/floating_ips_client.py b/tempest/services/compute/xml/floating_ips_client.py
index d6decf3..be54753 100644
--- a/tempest/services/compute/xml/floating_ips_client.py
+++ b/tempest/services/compute/xml/floating_ips_client.py
@@ -16,7 +16,7 @@
from lxml import etree
import urllib
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -27,7 +27,9 @@
CONF = config.CONF
-class FloatingIPsClientXML(RestClientXML):
+class FloatingIPsClientXML(rest_client.RestClient):
+ TYPE = "xml"
+
def __init__(self, auth_provider):
super(FloatingIPsClientXML, self).__init__(auth_provider)
self.service = CONF.compute.catalog_type
diff --git a/tempest/services/compute/xml/hosts_client.py b/tempest/services/compute/xml/hosts_client.py
index 13abe18..b74cd04 100644
--- a/tempest/services/compute/xml/hosts_client.py
+++ b/tempest/services/compute/xml/hosts_client.py
@@ -15,7 +15,7 @@
import urllib
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -24,7 +24,8 @@
CONF = config.CONF
-class HostsClientXML(RestClientXML):
+class HostsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(HostsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/hypervisor_client.py b/tempest/services/compute/xml/hypervisor_client.py
index 3c1ef08..ecd7541 100644
--- a/tempest/services/compute/xml/hypervisor_client.py
+++ b/tempest/services/compute/xml/hypervisor_client.py
@@ -15,14 +15,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class HypervisorClientXML(RestClientXML):
+class HypervisorClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(HypervisorClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index 9f80c55..9d529be 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -30,7 +30,8 @@
CONF = config.CONF
-class ImagesClientXML(RestClientXML):
+class ImagesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ImagesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/instance_usage_audit_log_client.py b/tempest/services/compute/xml/instance_usage_audit_log_client.py
index baa6966..1cd8c07 100644
--- a/tempest/services/compute/xml/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/xml/instance_usage_audit_log_client.py
@@ -15,14 +15,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class InstanceUsagesAuditLogClientXML(RestClientXML):
+class InstanceUsagesAuditLogClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(InstanceUsagesAuditLogClientXML, self).__init__(
diff --git a/tempest/services/compute/xml/interfaces_client.py b/tempest/services/compute/xml/interfaces_client.py
index 6155cd6..5df6187 100644
--- a/tempest/services/compute/xml/interfaces_client.py
+++ b/tempest/services/compute/xml/interfaces_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -28,7 +28,8 @@
CONF = config.CONF
-class InterfacesClientXML(RestClientXML):
+class InterfacesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(InterfacesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/keypairs_client.py b/tempest/services/compute/xml/keypairs_client.py
index 5641251..fb498c0 100644
--- a/tempest/services/compute/xml/keypairs_client.py
+++ b/tempest/services/compute/xml/keypairs_client.py
@@ -16,7 +16,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -26,7 +26,8 @@
CONF = config.CONF
-class KeyPairsClientXML(RestClientXML):
+class KeyPairsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(KeyPairsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/limits_client.py b/tempest/services/compute/xml/limits_client.py
index 61c434c..2327626 100644
--- a/tempest/services/compute/xml/limits_client.py
+++ b/tempest/services/compute/xml/limits_client.py
@@ -15,7 +15,7 @@
from lxml import objectify
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
@@ -23,7 +23,8 @@
NS = "{http://docs.openstack.org/common/api/v1.0}"
-class LimitsClientXML(RestClientXML):
+class LimitsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(LimitsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 00c3275..eb287c2 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -15,7 +15,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -25,7 +25,8 @@
CONF = config.CONF
-class QuotasClientXML(RestClientXML):
+class QuotasClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(QuotasClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/security_groups_client.py b/tempest/services/compute/xml/security_groups_client.py
index 324e165..d53e8da 100644
--- a/tempest/services/compute/xml/security_groups_client.py
+++ b/tempest/services/compute/xml/security_groups_client.py
@@ -16,7 +16,7 @@
from lxml import etree
import urllib
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -28,7 +28,8 @@
CONF = config.CONF
-class SecurityGroupsClientXML(RestClientXML):
+class SecurityGroupsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(SecurityGroupsClientXML, self).__init__(auth_provider)
@@ -154,3 +155,10 @@
rules = [xml_to_json(x) for x in node.getchildren()]
return resp, rules
raise exceptions.NotFound('No such Security Group')
+
+ def is_resource_deleted(self, id):
+ try:
+ self.get_security_group(id)
+ except exceptions.NotFound:
+ return True
+ return False
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index a182d35..da01b83 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -19,7 +19,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -139,7 +139,8 @@
return json
-class ServersClientXML(RestClientXML):
+class ServersClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ServersClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/services_client.py b/tempest/services/compute/xml/services_client.py
index 5943ea9..d7b8a60 100644
--- a/tempest/services/compute/xml/services_client.py
+++ b/tempest/services/compute/xml/services_client.py
@@ -18,7 +18,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -27,7 +27,8 @@
CONF = config.CONF
-class ServicesClientXML(RestClientXML):
+class ServicesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ServicesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/tenant_usages_client.py b/tempest/services/compute/xml/tenant_usages_client.py
index 96c3147..79f0ac9 100644
--- a/tempest/services/compute/xml/tenant_usages_client.py
+++ b/tempest/services/compute/xml/tenant_usages_client.py
@@ -17,14 +17,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class TenantUsagesClientXML(RestClientXML):
+class TenantUsagesClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(TenantUsagesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/volumes_extensions_client.py b/tempest/services/compute/xml/volumes_extensions_client.py
index a43fc21..570b715 100644
--- a/tempest/services/compute/xml/volumes_extensions_client.py
+++ b/tempest/services/compute/xml/volumes_extensions_client.py
@@ -18,7 +18,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -30,7 +30,8 @@
CONF = config.CONF
-class VolumesExtensionsClientXML(RestClientXML):
+class VolumesExtensionsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(VolumesExtensionsClientXML, self).__init__(
diff --git a/tempest/services/identity/v3/xml/credentials_client.py b/tempest/services/identity/v3/xml/credentials_client.py
index f6fa678..22ed44d 100644
--- a/tempest/services/identity/v3/xml/credentials_client.py
+++ b/tempest/services/identity/v3/xml/credentials_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -29,7 +29,8 @@
XMLNS = "http://docs.openstack.org/identity/api/v3"
-class CredentialsClientXML(RestClientXML):
+class CredentialsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(CredentialsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index 2a88c15..a32eede 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -16,7 +16,7 @@
from lxml import etree
from tempest.common import http
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -27,7 +27,8 @@
XMLNS = "http://docs.openstack.org/identity/api/v3"
-class EndPointClientXML(RestClientXML):
+class EndPointClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(EndPointClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index 5ae0461..e8e70d8 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -30,7 +30,8 @@
XMLNS = "http://docs.openstack.org/identity/api/v3"
-class IdentityV3ClientXML(RestClientXML):
+class IdentityV3ClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(IdentityV3ClientXML, self).__init__(auth_provider)
@@ -426,7 +427,8 @@
return resp, body
-class V3TokenClientXML(RestClientXML):
+class V3TokenClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self):
super(V3TokenClientXML, self).__init__(None)
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
index a7e63a7..c12018a 100644
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ b/tempest/services/identity/v3/xml/policy_client.py
@@ -16,7 +16,7 @@
from lxml import etree
from tempest.common import http
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -27,7 +27,8 @@
XMLNS = "http://docs.openstack.org/identity/api/v3"
-class PolicyClientXML(RestClientXML):
+class PolicyClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(PolicyClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
index be6c443..d5476c4 100644
--- a/tempest/services/identity/v3/xml/service_client.py
+++ b/tempest/services/identity/v3/xml/service_client.py
@@ -15,7 +15,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import Element
@@ -26,7 +26,8 @@
XMLNS = "http://docs.openstack.org/identity/api/v3"
-class ServiceClientXML(RestClientXML):
+class ServiceClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ServiceClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 0d00c75..366ccee 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -154,20 +154,6 @@
body = json.loads(body)
return resp, body
- def create_security_group(self, name, **kwargs):
- post_body = {
- 'security_group': {
- 'name': name,
- }
- }
- for key, value in kwargs.iteritems():
- post_body['security_group'][str(key)] = value
- body = json.dumps(post_body)
- uri = '%s/security-groups' % (self.uri_prefix)
- resp, body = self.post(uri, body)
- body = json.loads(body)
- return resp, body
-
def update_floating_ip(self, floating_ip_id, **kwargs):
post_body = {
'floatingip': kwargs}
@@ -177,22 +163,6 @@
body = json.loads(body)
return resp, body
- def create_security_group_rule(self, secgroup_id,
- direction='ingress', **kwargs):
- post_body = {
- 'security_group_rule': {
- 'direction': direction,
- 'security_group_id': secgroup_id
- }
- }
- for key, value in kwargs.iteritems():
- post_body['security_group_rule'][str(key)] = value
- body = json.dumps(post_body)
- uri = '%s/security-group-rules' % (self.uri_prefix)
- resp, body = self.post(uri, body)
- body = json.loads(body)
- return resp, body
-
def create_member(self, address, protocol_port, pool_id):
post_body = {
"member": {
@@ -285,6 +255,19 @@
body = json.loads(body)
return resp, body
+ def list_pools_hosted_by_one_lbaas_agent(self, agent_id):
+ uri = '%s/agents/%s/loadbalancer-pools' % (self.uri_prefix, agent_id)
+ resp, body = self.get(uri)
+ body = json.loads(body)
+ return resp, body
+
+ def show_lbaas_agent_hosting_pool(self, pool_id):
+ uri = ('%s/lb/pools/%s/loadbalancer-agent' %
+ (self.uri_prefix, pool_id))
+ resp, body = self.get(uri)
+ body = json.loads(body)
+ return resp, body
+
def list_routers_on_l3_agent(self, agent_id):
uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
resp, body = self.get(uri)
@@ -362,3 +345,9 @@
resp, body = self.put(uri, body)
body = json.loads(body)
return resp, body
+
+ def list_lb_pool_stats(self, pool_id):
+ uri = '%s/lb/pools/%s/stats' % (self.uri_prefix, pool_id)
+ resp, body = self.get(uri)
+ body = json.loads(body)
+ return resp, body
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 18b99d1..97d514f 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -13,32 +13,31 @@
from lxml import etree
import xml.etree.ElementTree as ET
-from tempest.common.rest_client import RestClientXML
-from tempest.services.compute.xml.common import deep_dict_to_xml
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import parse_array
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.common import rest_client
+from tempest.services.compute.xml import common
from tempest.services.network import network_client_base as client_base
class NetworkClientXML(client_base.NetworkClientBase):
+ TYPE = "xml"
# list of plurals used for xml serialization
PLURALS = ['dns_nameservers', 'host_routes', 'allocation_pools',
- 'fixed_ips', 'extensions']
+ 'fixed_ips', 'extensions', 'extra_dhcp_opts']
def get_rest_client(self, auth_provider):
- return RestClientXML(auth_provider)
+ rc = rest_client.RestClient(auth_provider)
+ rc.TYPE = self.TYPE
+ return rc
def _parse_array(self, node):
array = []
for child in node.getchildren():
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def deserialize_list(self, body):
- return parse_array(etree.fromstring(body), self.PLURALS)
+ return common.parse_array(etree.fromstring(body), self.PLURALS)
def deserialize_single(self, body):
return _root_tag_fetcher_and_xml_to_json_parse(body)
@@ -47,79 +46,67 @@
#TODO(enikanorov): implement better json to xml conversion
# expecting the dict with single key
root = body.keys()[0]
- post_body = Element(root)
+ post_body = common.Element(root)
post_body.add_attr('xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance')
for name, attr in body[root].items():
elt = self._get_element(name, attr)
post_body.append(elt)
- return str(Document(post_body))
+ return str(common.Document(post_body))
def serialize_list(self, body, root_name=None, item_name=None):
# expecting dict in form
# body = {'resources': [res_dict1, res_dict2, ...]
- post_body = Element(root_name)
+ post_body = common.Element(root_name)
post_body.add_attr('xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance')
for item in body[body.keys()[0]]:
- elt = Element(item_name)
+ elt = common.Element(item_name)
for name, attr in item.items():
elt_content = self._get_element(name, attr)
elt.append(elt_content)
post_body.append(elt)
- return str(Document(post_body))
+ return str(common.Document(post_body))
def _get_element(self, name, value):
if value is None:
- xml_elem = Element(name)
+ xml_elem = common.Element(name)
xml_elem.add_attr("xsi:nil", "true")
return xml_elem
+ elif isinstance(value, dict):
+ dict_element = common.Element(name)
+ for key, value in value.iteritems():
+ elem = self._get_element(key, value)
+ dict_element.append(elem)
+ return dict_element
+ elif isinstance(value, list):
+ list_element = common.Element(name)
+ for element in value:
+ elem = self._get_element(name[:-1], element)
+ list_element.append(elem)
+ return list_element
else:
- return Element(name, value)
-
- def create_security_group(self, name):
- uri = '%s/security-groups' % (self.uri_prefix)
- post_body = Element("security_group")
- p2 = Element("name", name)
- post_body.append(p2)
- resp, body = self.post(uri, str(Document(post_body)))
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
-
- def create_security_group_rule(self, secgroup_id,
- direction='ingress', **kwargs):
- uri = '%s/security-group-rules' % (self.uri_prefix)
- rule = Element("security_group_rule")
- p1 = Element('security_group_id', secgroup_id)
- p2 = Element('direction', direction)
- rule.append(p1)
- rule.append(p2)
- for key, val in kwargs.items():
- key = Element(key, val)
- rule.append(key)
- resp, body = self.post(uri, str(Document(rule)))
- body = _root_tag_fetcher_and_xml_to_json_parse(body)
- return resp, body
+ return common.Element(name, value)
def create_member(self, address, protocol_port, pool_id):
uri = '%s/lb/members' % (self.uri_prefix)
- post_body = Element("member")
- p1 = Element("address", address)
- p2 = Element("protocol_port", protocol_port)
- p3 = Element("pool_id", pool_id)
+ post_body = common.Element("member")
+ p1 = common.Element("address", address)
+ p2 = common.Element("protocol_port", protocol_port)
+ p3 = common.Element("pool_id", pool_id)
post_body.append(p1)
post_body.append(p2)
post_body.append(p3)
- resp, body = self.post(uri, str(Document(post_body)))
+ resp, body = self.post(uri, str(common.Document(post_body)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def update_member(self, admin_state_up, member_id):
uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
- put_body = Element("member")
- p2 = Element("admin_state_up", admin_state_up)
+ put_body = common.Element("member")
+ p2 = common.Element("admin_state_up", admin_state_up)
put_body.append(p2)
- resp, body = self.put(uri, str(Document(put_body)))
+ resp, body = self.put(uri, str(common.Document(put_body)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
@@ -127,10 +114,10 @@
pool_id):
uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
pool_id)
- post_body = Element("health_monitor")
- p1 = Element("id", health_monitor_id,)
+ post_body = common.Element("health_monitor")
+ p1 = common.Element("id", health_monitor_id,)
post_body.append(p1)
- resp, body = self.post(uri, str(Document(post_body)))
+ resp, body = self.post(uri, str(common.Document(post_body)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
@@ -148,94 +135,109 @@
def create_router(self, name, **kwargs):
uri = '%s/routers' % (self.uri_prefix)
- router = Element("router")
- router.append(Element("name", name))
- deep_dict_to_xml(router, kwargs)
- resp, body = self.post(uri, str(Document(router)))
+ router = common.Element("router")
+ router.append(common.Element("name", name))
+ common.deep_dict_to_xml(router, kwargs)
+ resp, body = self.post(uri, str(common.Document(router)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def update_router(self, router_id, **kwargs):
uri = '%s/routers/%s' % (self.uri_prefix, router_id)
- router = Element("router")
+ router = common.Element("router")
for element, content in kwargs.iteritems():
- router.append(Element(element, content))
- resp, body = self.put(uri, str(Document(router)))
+ router.append(common.Element(element, content))
+ resp, body = self.put(uri, str(common.Document(router)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def add_router_interface_with_subnet_id(self, router_id, subnet_id):
uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
router_id)
- subnet = Element("subnet_id", subnet_id)
- resp, body = self.put(uri, str(Document(subnet)))
+ subnet = common.Element("subnet_id", subnet_id)
+ resp, body = self.put(uri, str(common.Document(subnet)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def add_router_interface_with_port_id(self, router_id, port_id):
uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
router_id)
- port = Element("port_id", port_id)
- resp, body = self.put(uri, str(Document(port)))
+ port = common.Element("port_id", port_id)
+ resp, body = self.put(uri, str(common.Document(port)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def remove_router_interface_with_subnet_id(self, router_id, subnet_id):
uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
router_id)
- subnet = Element("subnet_id", subnet_id)
- resp, body = self.put(uri, str(Document(subnet)))
+ subnet = common.Element("subnet_id", subnet_id)
+ resp, body = self.put(uri, str(common.Document(subnet)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def remove_router_interface_with_port_id(self, router_id, port_id):
uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
router_id)
- port = Element("port_id", port_id)
- resp, body = self.put(uri, str(Document(port)))
+ port = common.Element("port_id", port_id)
+ resp, body = self.put(uri, str(common.Document(port)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def create_floating_ip(self, ext_network_id, **kwargs):
uri = '%s/floatingips' % (self.uri_prefix)
- floatingip = Element('floatingip')
- floatingip.append(Element("floating_network_id", ext_network_id))
+ floatingip = common.Element('floatingip')
+ floatingip.append(common.Element("floating_network_id",
+ ext_network_id))
for element, content in kwargs.iteritems():
- floatingip.append(Element(element, content))
- resp, body = self.post(uri, str(Document(floatingip)))
+ floatingip.append(common.Element(element, content))
+ resp, body = self.post(uri, str(common.Document(floatingip)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def update_floating_ip(self, floating_ip_id, **kwargs):
uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
- floatingip = Element('floatingip')
+ floatingip = common.Element('floatingip')
floatingip.add_attr('xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance')
for element, content in kwargs.iteritems():
if content is None:
- xml_elem = Element(element)
+ xml_elem = common.Element(element)
xml_elem.add_attr("xsi:nil", "true")
floatingip.append(xml_elem)
else:
- floatingip.append(Element(element, content))
- resp, body = self.put(uri, str(Document(floatingip)))
+ floatingip.append(common.Element(element, content))
+ resp, body = self.put(uri, str(common.Document(floatingip)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
def list_router_interfaces(self, uuid):
uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
resp, body = self.get(uri)
- ports = parse_array(etree.fromstring(body), self.PLURALS)
+ ports = common.parse_array(etree.fromstring(body), self.PLURALS)
ports = {"ports": ports}
return resp, ports
def update_agent(self, agent_id, agent_info):
uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
- agent = Element('agent')
+ agent = common.Element('agent')
for (key, value) in agent_info.items():
- p = Element(key, value)
+ p = common.Element(key, value)
agent.append(p)
- resp, body = self.put(uri, str(Document(agent)))
+ resp, body = self.put(uri, str(common.Document(agent)))
+ body = _root_tag_fetcher_and_xml_to_json_parse(body)
+ return resp, body
+
+ def list_pools_hosted_by_one_lbaas_agent(self, agent_id):
+ uri = '%s/agents/%s/loadbalancer-pools' % (self.uri_prefix, agent_id)
+ resp, body = self.get(uri)
+ pools = common.parse_array(etree.fromstring(body))
+ body = {'pools': pools}
+ return resp, body
+
+ def show_lbaas_agent_hosting_pool(self, pool_id):
+ uri = ('%s/lb/pools/%s/loadbalancer-agent' %
+ (self.uri_prefix, pool_id))
+ resp, body = self.get(uri)
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
@@ -254,14 +256,14 @@
def list_dhcp_agent_hosting_network(self, network_id):
uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
resp, body = self.get(uri)
- agents = parse_array(etree.fromstring(body))
+ agents = common.parse_array(etree.fromstring(body))
body = {'agents': agents}
return resp, body
def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
resp, body = self.get(uri)
- networks = parse_array(etree.fromstring(body))
+ networks = common.parse_array(etree.fromstring(body))
body = {'networks': networks}
return resp, body
@@ -271,14 +273,20 @@
resp, body = self.delete(uri)
return resp, body
+ def list_lb_pool_stats(self, pool_id):
+ uri = '%s/lb/pools/%s/stats' % (self.uri_prefix, pool_id)
+ resp, body = self.get(uri)
+ body = _root_tag_fetcher_and_xml_to_json_parse(body)
+ return resp, body
+
def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body):
body = ET.fromstring(xml_returned_body)
root_tag = body.tag
if root_tag.startswith("{"):
ns, root_tag = root_tag.split("}", 1)
- body = xml_to_json(etree.fromstring(xml_returned_body),
- NetworkClientXML.PLURALS)
+ body = common.xml_to_json(etree.fromstring(xml_returned_body),
+ NetworkClientXML.PLURALS)
nil = '{http://www.w3.org/2001/XMLSchema-instance}nil'
for key, val in body.iteritems():
if isinstance(val, dict):
diff --git a/tempest/services/telemetry/xml/telemetry_client.py b/tempest/services/telemetry/xml/telemetry_client.py
index f29fe22..165f29a 100644
--- a/tempest/services/telemetry/xml/telemetry_client.py
+++ b/tempest/services/telemetry/xml/telemetry_client.py
@@ -15,16 +15,19 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest.services.compute.xml.common import Document
from tempest.services.compute.xml.common import xml_to_json
import tempest.services.telemetry.telemetry_client_base as client
class TelemetryClientXML(client.TelemetryClientBase):
+ TYPE = "xml"
def get_rest_client(self, auth_provider):
- return RestClientXML(auth_provider)
+ rc = rest_client.RestClient(auth_provider)
+ rc.TYPE = self.TYPE
+ return rc
def _parse_array(self, body):
array = []
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
new file mode 100644
index 0000000..baaf5a0
--- /dev/null
+++ b/tempest/services/volume/json/backups_client.py
@@ -0,0 +1,89 @@
+# Copyright 2014 OpenStack Foundation
+# 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 json
+import time
+
+from tempest.common import rest_client
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
+
+
+class BackupsClientJSON(rest_client.RestClient):
+ """
+ Client class to send CRUD Volume backup API requests to a Cinder endpoint
+ """
+
+ def __init__(self, auth_provider):
+ super(BackupsClientJSON, self).__init__(auth_provider)
+ self.service = CONF.volume.catalog_type
+ self.build_interval = CONF.volume.build_interval
+ self.build_timeout = CONF.volume.build_timeout
+
+ def create_backup(self, volume_id, container=None, name=None,
+ description=None):
+ """Creates a backup of volume."""
+ post_body = {'volume_id': volume_id}
+ if container:
+ post_body['container'] = container
+ if name:
+ post_body['name'] = name
+ if description:
+ post_body['description'] = description
+ post_body = json.dumps({'backup': post_body})
+ resp, body = self.post('backups', post_body)
+ body = json.loads(body)
+ return resp, body['backup']
+
+ def restore_backup(self, backup_id, volume_id=None):
+ """Restore volume from backup."""
+ post_body = {'volume_id': volume_id}
+ post_body = json.dumps({'restore': post_body})
+ resp, body = self.post('backups/%s/restore' % (backup_id), post_body)
+ body = json.loads(body)
+ return resp, body['restore']
+
+ def delete_backup(self, backup_id):
+ """Delete a backup of volume."""
+ resp, body = self.delete('backups/%s' % (str(backup_id)))
+ return resp, body
+
+ def get_backup(self, backup_id):
+ """Returns the details of a single backup."""
+ url = "backups/%s" % str(backup_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['backup']
+
+ def wait_for_backup_status(self, backup_id, status):
+ """Waits for a Backup to reach a given status."""
+ resp, body = self.get_backup(backup_id)
+ backup_status = body['status']
+ start = int(time.time())
+
+ while backup_status != status:
+ time.sleep(self.build_interval)
+ resp, body = self.get_backup(backup_id)
+ backup_status = body['status']
+ if backup_status == 'error':
+ raise exceptions.VolumeBackupException(backup_id=backup_id)
+
+ if int(time.time()) - start >= self.build_timeout:
+ message = ('Volume backup %s failed to reach %s status within '
+ 'the required time (%s s).' %
+ (backup_id, status, self.build_timeout))
+ raise exceptions.TimeoutException(message)
diff --git a/tempest/services/volume/v2/xml/volumes_client.py b/tempest/services/volume/v2/xml/volumes_client.py
index 69e3f5b..bc57842 100644
--- a/tempest/services/volume/v2/xml/volumes_client.py
+++ b/tempest/services/volume/v2/xml/volumes_client.py
@@ -18,7 +18,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -30,10 +30,11 @@
CONF = config.CONF
-class VolumesV2ClientXML(RestClientXML):
+class VolumesV2ClientXML(rest_client.RestClient):
"""
Client class to send CRUD Volume API requests to a Cinder endpoint
"""
+ TYPE = "xml"
def __init__(self, auth_provider):
super(VolumesV2ClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/volume/xml/admin/volume_hosts_client.py b/tempest/services/volume/xml/admin/volume_hosts_client.py
index 080e3d1..fb84c83 100644
--- a/tempest/services/volume/xml/admin/volume_hosts_client.py
+++ b/tempest/services/volume/xml/admin/volume_hosts_client.py
@@ -17,17 +17,18 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class VolumeHostsClientXML(RestClientXML):
+class VolumeHostsClientXML(rest_client.RestClient):
"""
Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
"""
+ TYPE = "xml"
def __init__(self, auth_provider):
super(VolumeHostsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/volume/xml/admin/volume_types_client.py b/tempest/services/volume/xml/admin/volume_types_client.py
index 802d27a..77bafec 100644
--- a/tempest/services/volume/xml/admin/volume_types_client.py
+++ b/tempest/services/volume/xml/admin/volume_types_client.py
@@ -17,7 +17,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -29,10 +29,11 @@
CONF = config.CONF
-class VolumeTypesClientXML(RestClientXML):
+class VolumeTypesClientXML(rest_client.RestClient):
"""
Client class to send CRUD Volume Types API requests to a Cinder endpoint
"""
+ TYPE = "xml"
def __init__(self, auth_provider):
super(VolumeTypesClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/volume/xml/backups_client.py b/tempest/services/volume/xml/backups_client.py
new file mode 100644
index 0000000..81caaee
--- /dev/null
+++ b/tempest/services/volume/xml/backups_client.py
@@ -0,0 +1,26 @@
+# Copyright 2014 OpenStack Foundation
+# 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.services.volume.json import backups_client
+
+
+class BackupsClientXML(backups_client.BackupsClientJSON):
+ """
+ Client class to send CRUD Volume Backup API requests to a Cinder endpoint
+ """
+ TYPE = "xml"
+
+ #TODO(gfidente): XML client isn't yet implemented because of bug 1270589
+ pass
diff --git a/tempest/services/volume/xml/extensions_client.py b/tempest/services/volume/xml/extensions_client.py
index 03743a6..1ea974f 100644
--- a/tempest/services/volume/xml/extensions_client.py
+++ b/tempest/services/volume/xml/extensions_client.py
@@ -15,14 +15,15 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest.services.compute.xml.common import xml_to_json
CONF = config.CONF
-class ExtensionsClientXML(RestClientXML):
+class ExtensionsClientXML(rest_client.RestClient):
+ TYPE = "xml"
def __init__(self, auth_provider):
super(ExtensionsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index 9abe042..458001b 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -15,7 +15,7 @@
from lxml import etree
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -30,8 +30,9 @@
LOG = logging.getLogger(__name__)
-class SnapshotsClientXML(RestClientXML):
+class SnapshotsClientXML(rest_client.RestClient):
"""Client class to send CRUD Volume API requests."""
+ TYPE = "xml"
def __init__(self, auth_provider):
super(SnapshotsClientXML, self).__init__(auth_provider)
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index 2b500ae..aef1e3c 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -17,8 +17,9 @@
import urllib
from lxml import etree
+from xml.sax.saxutils import escape
-from tempest.common.rest_client import RestClientXML
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.services.compute.xml.common import Document
@@ -30,10 +31,11 @@
CONF = config.CONF
-class VolumesClientXML(RestClientXML):
+class VolumesClientXML(rest_client.RestClient):
"""
Client class to send CRUD Volume API requests to a Cinder endpoint
"""
+ TYPE = "xml"
def __init__(self, auth_provider):
super(VolumesClientXML, self).__init__(auth_provider)
@@ -358,7 +360,8 @@
post_body = Element('metadata')
for k, v in meta.items():
data = Element('meta', key=k)
- data.append(Text(v))
+ # Escape value to allow for special XML chars
+ data.append(Text(escape(v)))
post_body.append(data)
return post_body
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index d4689c4..3715636 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -220,7 +220,7 @@
LOG.info("Run %d actions (%d failed)" %
(sum_runs, sum_fails))
- if not had_errors:
+ if not had_errors and CONF.stress.full_clean_stack:
LOG.info("cleaning up")
cleanup.cleanup()
if had_errors:
diff --git a/tempest/stress/run_stress.py b/tempest/stress/run_stress.py
index 76320d0..c7c17c0 100755
--- a/tempest/stress/run_stress.py
+++ b/tempest/stress/run_stress.py
@@ -18,7 +18,7 @@
import inspect
import json
import sys
-from testtools.testsuite import iterate_tests
+from testtools import testsuite
try:
from unittest import loader
except ImportError:
@@ -38,7 +38,7 @@
tests = []
testloader = loader.TestLoader()
list = testloader.discover(path)
- for func in (iterate_tests(list)):
+ for func in (testsuite.iterate_tests(list)):
attrs = []
try:
method_name = getattr(func, '_testMethodName')
@@ -87,8 +87,13 @@
# NOTE(mkoderer): we just save the last result code
if (step_result != 0):
result = step_result
+ if ns.stop:
+ return result
else:
- driver.stress_openstack(tests, ns.duration, ns.number, ns.stop)
+ result = driver.stress_openstack(tests,
+ ns.duration,
+ ns.number,
+ ns.stop)
return result
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 42237ca..41b0558 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -21,6 +21,9 @@
class fake_identity(object):
disable_ssl_certificate_validation = True
+ catalog_type = 'identity'
+ uri = 'http://fake_uri.com/auth'
+ uri_v3 = 'http://fake_uri_v3.com/auth'
class fake_default_feature_enabled(object):
api_extensions = ['all']
diff --git a/tempest/tests/fake_http.py b/tempest/tests/fake_http.py
index ac5f765..a09d5ba 100644
--- a/tempest/tests/fake_http.py
+++ b/tempest/tests/fake_http.py
@@ -17,7 +17,7 @@
class fake_httplib2(object):
- def __init__(self, return_type=None):
+ def __init__(self, return_type=None, *args, **kwargs):
self.return_type = return_type
def request(self, uri, method="GET", body=None, headers=None,
diff --git a/tempest/tests/fake_identity.py b/tempest/tests/fake_identity.py
new file mode 100644
index 0000000..ea2bd44
--- /dev/null
+++ b/tempest/tests/fake_identity.py
@@ -0,0 +1,156 @@
+# Copyright 2014 IBM Corp.
+# 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 httplib2
+import json
+
+
+TOKEN = "fake_token"
+ALT_TOKEN = "alt_fake_token"
+
+# Fake Identity v2 constants
+COMPUTE_ENDPOINTS_V2 = {
+ "endpoints": [
+ {
+ "adminURL": "http://fake_url/api/admin",
+ "region": "NoMatchRegion",
+ "internalURL": "http://fake_url/api/internal",
+ "publicURL": "http://fake_url/api/public"
+ },
+ {
+ "adminURL": "http://fake_url/api/admin",
+ "region": "FakeRegion",
+ "internalURL": "http://fake_url/api/internal",
+ "publicURL": "http://fake_url/api/public"
+ },
+ ],
+ "type": "compute",
+ "name": "nova"
+}
+
+CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ]
+
+ALT_IDENTITY_V2_RESPONSE = {
+ "access": {
+ "token": {
+ "expires": "2020-01-01T00:00:10Z",
+ "id": ALT_TOKEN,
+ "tenant": {
+ "id": "fake_tenant_id"
+ },
+ },
+ "user": {
+ "id": "fake_user_id",
+ },
+ "serviceCatalog": CATALOG_V2,
+ },
+}
+
+IDENTITY_V2_RESPONSE = {
+ "access": {
+ "token": {
+ "expires": "2020-01-01T00:00:10Z",
+ "id": TOKEN,
+ "tenant": {
+ "id": "fake_tenant_id"
+ },
+ },
+ "user": {
+ "id": "fake_user_id",
+ },
+ "serviceCatalog": CATALOG_V2,
+ },
+}
+
+# Fake Identity V3 constants
+COMPUTE_ENDPOINTS_V3 = {
+ "endpoints": [
+ {
+ "id": "fake_service",
+ "interface": "public",
+ "region": "NoMatchRegion",
+ "url": "http://fake_url/v3"
+ },
+ {
+ "id": "another_fake_service",
+ "interface": "public",
+ "region": "FakeRegion",
+ "url": "http://fake_url/v3"
+ }
+ ],
+ "type": "compute",
+ "id": "fake_compute_endpoint"
+}
+
+CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ]
+
+IDENTITY_V3_RESPONSE = {
+ "token": {
+ "methods": [
+ "token",
+ "password"
+ ],
+ "expires_at": "2020-01-01T00:00:10.000123Z",
+ "project": {
+ "domain": {
+ "id": "fake_id",
+ "name": "fake"
+ },
+ "id": "project_id",
+ "name": "project_name"
+ },
+ "user": {
+ "domain": {
+ "id": "domain_id",
+ "name": "domain_name"
+ },
+ "id": "fake_user_id",
+ "name": "username"
+ },
+ "issued_at": "2013-05-29T16:55:21.468960Z",
+ "catalog": CATALOG_V3
+ }
+}
+
+ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE
+
+
+def _fake_v3_response(self, uri, method="GET", body=None, headers=None,
+ redirections=5, connection_type=None):
+ fake_headers = {
+ "status": "201",
+ "x-subject-token": TOKEN
+ }
+ return (httplib2.Response(fake_headers),
+ json.dumps(IDENTITY_V3_RESPONSE))
+
+
+def _fake_v2_response(self, uri, method="GET", body=None, headers=None,
+ redirections=5, connection_type=None):
+ return (httplib2.Response({"status": "200"}),
+ json.dumps(IDENTITY_V2_RESPONSE))
+
+
+def _fake_auth_failure_response():
+ # the response body isn't really used in this case, but lets send it anyway
+ # to have a safe check in some future change on the rest client.
+ body = {
+ "unauthorized": {
+ "message": "Unauthorized",
+ "code": "401"
+ }
+ }
+ return httplib2.Response({"status": "401"}), json.dumps(body)
diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg
index 8639baa..f6f9f73 100644
--- a/tempest/tests/files/setup.cfg
+++ b/tempest/tests/files/setup.cfg
@@ -2,8 +2,8 @@
name = tempest_unit_tests
version = 1
summary = Fake Project for testing wrapper scripts
-author = OpenStack QA
-author-email = openstack-qa@lists.openstack.org
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
home-page = http://www.openstack.org/
classifier =
Intended Audience :: Information Technology
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
new file mode 100644
index 0000000..5346052
--- /dev/null
+++ b/tempest/tests/test_auth.py
@@ -0,0 +1,210 @@
+# Copyright 2014 IBM Corp.
+# 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 copy
+
+from tempest import auth
+from tempest.common import http
+from tempest import config
+from tempest import exceptions
+from tempest.openstack.common.fixture import mockpatch
+from tempest.tests import base
+from tempest.tests import fake_config
+from tempest.tests import fake_http
+from tempest.tests import fake_identity
+
+
+class BaseAuthTestsSetUp(base.TestCase):
+ _auth_provider_class = None
+ credentials = {
+ 'username': 'fake_user',
+ 'password': 'fake_pwd',
+ 'tenant_name': 'fake_tenant'
+ }
+
+ def _auth(self, credentials, **params):
+ """
+ returns auth method according to keystone
+ """
+ return self._auth_provider_class(credentials, **params)
+
+ def setUp(self):
+ super(BaseAuthTestsSetUp, self).setUp()
+ self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakeConfig)
+ self.fake_http = fake_http.fake_httplib2(return_type=200)
+ self.stubs.Set(http.ClosingHttp, 'request', self.fake_http.request)
+ self.auth_provider = self._auth(self.credentials)
+
+
+class TestBaseAuthProvider(BaseAuthTestsSetUp):
+ """
+ This tests auth.AuthProvider class which is base for the other so we
+ obviously don't test not implemented method or the ones which strongly
+ depends on them.
+ """
+ _auth_provider_class = auth.AuthProvider
+
+ def test_check_credentials_is_dict(self):
+ self.assertTrue(self.auth_provider.check_credentials({}))
+
+ def test_check_credentials_bad_type(self):
+ self.assertFalse(self.auth_provider.check_credentials([]))
+
+ def test_instantiate_with_bad_credentials_type(self):
+ """
+ Assure that credentials with bad type fail with TypeError
+ """
+ self.assertRaises(TypeError, self._auth, [])
+
+ def test_auth_data_property(self):
+ self.assertRaises(NotImplementedError, getattr, self.auth_provider,
+ 'auth_data')
+
+ def test_auth_data_property_when_cache_exists(self):
+ self.auth_provider.cache = 'foo'
+ self.useFixture(mockpatch.PatchObject(self.auth_provider,
+ 'is_expired',
+ return_value=False))
+ self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
+
+ def test_delete_auth_data_property_through_deleter(self):
+ self.auth_provider.cache = 'foo'
+ del self.auth_provider.auth_data
+ self.assertIsNone(self.auth_provider.cache)
+
+ def test_delete_auth_data_property_through_clear_auth(self):
+ self.auth_provider.cache = 'foo'
+ self.auth_provider.clear_auth()
+ self.assertIsNone(self.auth_provider.cache)
+
+ def test_set_and_reset_alt_auth_data(self):
+ self.auth_provider.set_alt_auth_data('foo', 'bar')
+ self.assertEqual(self.auth_provider.alt_part, 'foo')
+ self.assertEqual(self.auth_provider.alt_auth_data, 'bar')
+
+ self.auth_provider.reset_alt_auth_data()
+ self.assertIsNone(self.auth_provider.alt_part)
+ self.assertIsNone(self.auth_provider.alt_auth_data)
+
+
+class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
+ _auth_provider_class = auth.KeystoneV2AuthProvider
+
+ def setUp(self):
+ super(TestKeystoneV2AuthProvider, self).setUp()
+ self.stubs.Set(http.ClosingHttp, 'request',
+ fake_identity._fake_v2_response)
+ self.target_url = 'test_api'
+
+ def _get_fake_alt_identity(self):
+ return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
+
+ def _get_result_url_from_fake_identity(self):
+ return fake_identity.COMPUTE_ENDPOINTS_V2['endpoints'][1]['publicURL']
+
+ def _get_token_from_fake_identity(self):
+ return fake_identity.TOKEN
+
+ def _test_request_helper(self):
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'fakeRegion'
+ }
+
+ url, headers, body = self.auth_provider.auth_request('GET',
+ self.target_url,
+ filters=filters)
+
+ result_url = self._get_result_url_from_fake_identity()
+ self.assertEqual(url, result_url + '/' + self.target_url)
+ self.assertEqual(self._get_token_from_fake_identity(),
+ headers['X-Auth-Token'])
+ self.assertEqual(body, None)
+
+ def test_request(self):
+ self._test_request_helper()
+
+ def test_request_with_alt_auth(self):
+ self.auth_provider.set_alt_auth_data(
+ 'body',
+ (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
+ self._test_request_helper()
+ # Assert alt auth data is clear after it
+ self.assertIsNone(self.auth_provider.alt_part)
+ self.assertIsNone(self.auth_provider.alt_auth_data)
+
+ def test_request_with_bad_service(self):
+ filters = {
+ 'service': 'BAD_SERVICE',
+ 'endpoint_type': 'publicURL',
+ 'region': 'fakeRegion'
+ }
+ self.assertRaises(exceptions.EndpointNotFound,
+ self.auth_provider.auth_request, 'GET',
+ 'http://fakeurl.com/fake_api', filters=filters)
+
+ def test_request_without_service(self):
+ filters = {
+ 'service': None,
+ 'endpoint_type': 'publicURL',
+ 'region': 'fakeRegion'
+ }
+ self.assertRaises(exceptions.EndpointNotFound,
+ self.auth_provider.auth_request, 'GET',
+ 'http://fakeurl.com/fake_api', filters=filters)
+
+ def test_check_credentials_missing_attribute(self):
+ for attr in ['username', 'password']:
+ cred = copy.copy(self.credentials)
+ del cred[attr]
+ self.assertFalse(self.auth_provider.check_credentials(cred))
+
+ def test_check_credentials_not_scoped_missing_tenant_name(self):
+ cred = copy.copy(self.credentials)
+ del cred['tenant_name']
+ self.assertTrue(self.auth_provider.check_credentials(cred,
+ scoped=False))
+
+ def test_check_credentials_missing_tenant_name(self):
+ cred = copy.copy(self.credentials)
+ del cred['tenant_name']
+ self.assertFalse(self.auth_provider.check_credentials(cred))
+
+
+class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
+ _auth_provider_class = auth.KeystoneV3AuthProvider
+ credentials = {
+ 'username': 'fake_user',
+ 'password': 'fake_pwd',
+ 'tenant_name': 'fake_tenant',
+ 'domain_name': 'fake_domain_name',
+ }
+
+ def setUp(self):
+ super(TestKeystoneV3AuthProvider, self).setUp()
+ self.stubs.Set(http.ClosingHttp, 'request',
+ fake_identity._fake_v3_response)
+
+ def _get_fake_alt_identity(self):
+ return fake_identity.ALT_IDENTITY_V3['token']
+
+ def _get_result_url_from_fake_identity(self):
+ return fake_identity.COMPUTE_ENDPOINTS_V3['endpoints'][1]['url']
+
+ def test_check_credentials_missing_tenant_name(self):
+ cred = copy.copy(self.credentials)
+ del cred['domain_name']
+ self.assertFalse(self.auth_provider.check_credentials(cred))
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 399a3c8..54861be 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -123,15 +123,6 @@
_terminate_reservation(reservation_1, rcuk_1)
_terminate_reservation(reservation_2, rcuk_2)
- reservation_3, rcuk_3 = _run_instance('token_1')
- self.assertIsNotNone(reservation_3)
-
- # make sure we don't get the old reservation back
- self.assertNotEqual(reservation_1.id, reservation_3.id)
-
- # clean up
- _terminate_reservation(reservation_3, rcuk_3)
-
@attr(type='smoke')
def test_run_stop_terminate_instance(self):
# EC2 run, stop and terminate instance
diff --git a/tools/verify_tempest_config.py b/tools/verify_tempest_config.py
index 29eed9d..4be812c 100755
--- a/tools/verify_tempest_config.py
+++ b/tools/verify_tempest_config.py
@@ -42,7 +42,12 @@
def verify_nova_api_versions(os):
# Check nova api versions - only get base URL without PATH
os.servers_client.skip_path = True
- __, body = RAW_HTTP.request(os.servers_client.base_url, 'GET')
+ # The nova base endpoint url includes the version but to get the versions
+ # list the unversioned endpoint is needed
+ v2_endpoint = os.servers_client.base_url
+ v2_endpoint_parts = v2_endpoint.split('/')
+ endpoint = v2_endpoint_parts[0] + '//' + v2_endpoint_parts[2]
+ __, body = RAW_HTTP.request(endpoint, 'GET')
body = json.loads(body)
# Restore full base_url
os.servers_client.skip_path = False