Merge "Separate negative tests for V3 test_quotas"
diff --git a/HACKING.rst b/HACKING.rst
index e7e7651..c0df0fb 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -108,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 1d368af..0f18f5e 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -320,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
@@ -553,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
@@ -579,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
@@ -874,6 +873,10 @@
# 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/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_servers.py b/tempest/api/compute/admin/test_servers.py
index 1078847..03b041c 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -120,7 +120,7 @@
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
# Administrator can delete servers of others
- _, server = self.create_test_server()
+ _, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.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/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/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_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/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index 195bb0e..b388b70 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -53,6 +53,22 @@
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
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 653eaf0..653e498 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -105,7 +105,7 @@
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
# Administrator can delete servers of others
- _, server = self.create_test_server()
+ _, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.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_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_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_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_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/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/network/test_networks.py b/tempest/api/network/test_networks.py
index 9029b1f..aba2c8e 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -467,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/object_storage/base.py b/tempest/api/object_storage/base.py
index d08dc34..45c895b 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -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/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 3db05e5..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
@@ -169,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,
@@ -187,153 +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.backups_client = BackupsClientXML(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.backups_client = BackupsClientJSON(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:
@@ -347,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):
@@ -452,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 5064f07..03dccd4 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -502,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 a2d35a9..e1a19f3 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -235,8 +235,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'
@@ -343,6 +343,9 @@
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"),
@@ -369,8 +372,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',
@@ -427,8 +430,8 @@
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"),
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 4dd51fb..1763808 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,184 +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
- 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)
-
-
class OfficialClientTest(tempest.test.BaseTestCase):
"""
Official Client test base class for scenario testing.
@@ -253,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
@@ -544,7 +358,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:
@@ -590,7 +404,7 @@
properties={'disk_format':
'qcow2'})
except IOError:
- LOG.debug("A qcow2 image was not got. Try to get a uec image.")
+ 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 = {
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 7667515..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
@@ -63,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_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 5464790..39b7760 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -13,10 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+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
@@ -96,6 +97,7 @@
except Exception:
LOG.exception('ssh to server failed')
self._log_console_output()
+ debug.log_ip_ns()
raise
def check_partitions(self):
@@ -110,7 +112,7 @@
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_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index eabc734..8e4192d 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -13,16 +13,14 @@
# 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
@@ -102,7 +100,7 @@
"""
def __init__(self, tenant_id, tenant_user, tenant_pass, tenant_name):
- self.manager = OfficialClientManager(
+ self.manager = clients.OfficialClientManager(
tenant_user,
tenant_pass,
tenant_name
@@ -318,10 +316,13 @@
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):
"""
@@ -352,9 +353,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:
@@ -457,8 +458,8 @@
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:
# deploy new tenant
@@ -476,8 +477,8 @@
self._log_console_output(servers=tenant.servers)
raise
- @attr(type='smoke')
- @services('compute', 'network')
+ @test.attr(type='smoke')
+ @test.services('compute', 'network')
def test_in_tenant_traffic(self):
try:
self._create_tenant_servers(self.primary_tenant, num=1)
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 73ff6b4..1144414 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
@@ -162,7 +162,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/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 947f6da..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)
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/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 5f3f8c1..25e6edb 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', '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,91 +46,91 @@
#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 = Element(name)
+ 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 = Element(name)
+ 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)
+ return common.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 = common.Element("security_group")
+ p2 = common.Element("name", name)
post_body.append(p2)
- 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 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 = common.Element("security_group_rule")
+ p1 = common.Element('security_group_id', secgroup_id)
+ p2 = common.Element('direction', direction)
rule.append(p1)
rule.append(p2)
for key, val in kwargs.items():
- key = Element(key, val)
+ key = common.Element(key, val)
rule.append(key)
- resp, body = self.post(uri, str(Document(rule)))
+ resp, body = self.post(uri, str(common.Document(rule)))
body = _root_tag_fetcher_and_xml_to_json_parse(body)
return resp, body
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
@@ -139,10 +138,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
@@ -160,101 +159,102 @@
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 = parse_array(etree.fromstring(body))
+ pools = common.parse_array(etree.fromstring(body))
body = {'pools': pools}
return resp, body
@@ -280,14 +280,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
@@ -309,8 +309,8 @@
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/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
index 6a71f8b..81caaee 100644
--- a/tempest/services/volume/xml/backups_client.py
+++ b/tempest/services/volume/xml/backups_client.py
@@ -13,13 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common.rest_client import RestClientXML
+from tempest.services.volume.json import backups_client
-class BackupsClientXML(RestClientXML):
+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 94c1ff6..aef1e3c 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -19,7 +19,7 @@
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
@@ -31,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)
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/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