Merge "Add Ironic show driver API test"
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index b0692b1..939f1a1 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -40,17 +40,20 @@
break
@test.attr(type='gate')
+ @test.services('network')
def test_list_fixed_ip_details(self):
resp, fixed_ip = self.client.get_fixed_ip_details(self.ip)
self.assertEqual(fixed_ip['address'], self.ip)
@test.attr(type='gate')
+ @test.services('network')
def test_set_reserve(self):
body = {"reserve": "None"}
resp, body = self.client.reserve_fixed_ip(self.ip, body)
self.assertEqual(resp.status, 202)
@test.attr(type='gate')
+ @test.services('network')
def test_set_unreserve(self):
body = {"unreserve": "None"}
resp, body = self.client.reserve_fixed_ip(self.ip, body)
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 3fb3829..1caa246 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -41,11 +41,13 @@
break
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_list_fixed_ip_details_with_non_admin_user(self):
self.assertRaises(exceptions.Unauthorized,
self.non_admin_client.get_fixed_ip_details, self.ip)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_set_reserve_with_non_admin_user(self):
body = {"reserve": "None"}
self.assertRaises(exceptions.Unauthorized,
@@ -53,6 +55,7 @@
self.ip, body)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_set_unreserve_with_non_admin_user(self):
body = {"unreserve": "None"}
self.assertRaises(exceptions.Unauthorized,
@@ -60,6 +63,7 @@
self.ip, body)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_set_reserve_with_invalid_ip(self):
# NOTE(maurosr): since this exercises the same code snippet, we do it
# only for reserve action
@@ -69,6 +73,7 @@
"my.invalid.ip", body)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_fixed_ip_with_invalid_action(self):
body = {"invalid_action": "None"}
self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 208b032..16c2810 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -58,6 +58,7 @@
pass
@test.attr(type='gate')
+ @test.services('network')
def test_create_list_delete_floating_ips_bulk(self):
# Create, List and delete the Floating IPs Bulk
pool = 'test_pool'
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 348666d..9263396 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -13,14 +13,26 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
+from testtools import matchers
+
from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
from tempest.common.utils import data_utils
+from tempest.openstack.common import log as logging
from tempest import test
+LOG = logging.getLogger(__name__)
+
class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
force_tenant_isolation = True
+ def setUp(self):
+ # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+ self.useFixture(fixtures.LockFixture('compute_quotas'))
+ super(QuotasAdminTestJSON, self).setUp()
+
@classmethod
def setUpClass(cls):
super(QuotasAdminTestJSON, cls).setUpClass()
@@ -134,3 +146,49 @@
class QuotasAdminTestXML(QuotasAdminTestJSON):
_interface = 'xml'
+
+
+class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest):
+ """Tests the os-quota-class-sets API to update default quotas.
+ """
+
+ def setUp(self):
+ # All test cases in this class need to externally lock on doing
+ # anything with default quota values.
+ self.useFixture(fixtures.LockFixture('compute_quotas'))
+ super(QuotaClassesAdminTestJSON, self).setUp()
+
+ @classmethod
+ def setUpClass(cls):
+ super(QuotaClassesAdminTestJSON, cls).setUpClass()
+ cls.adm_client = cls.os_adm.quota_classes_client
+
+ def _restore_default_quotas(self, original_defaults):
+ LOG.debug("restoring quota class defaults")
+ resp, body = self.adm_client.update_quota_class_set(
+ 'default', **original_defaults)
+ self.assertEqual(200, resp.status)
+
+ @test.attr(type='gate')
+ def test_update_default_quotas(self):
+ LOG.debug("get the current 'default' quota class values")
+ resp, body = self.adm_client.get_quota_class_set('default')
+ self.assertEqual(200, resp.status)
+ self.assertIn('id', body)
+ self.assertEqual('default', body.pop('id'))
+ # restore the defaults when the test is done
+ self.addCleanup(self._restore_default_quotas, body.copy())
+ # increment all of the values for updating the default quota class
+ for quota, default in six.iteritems(body):
+ body[quota] = default + 1
+ LOG.debug("update limits for the default quota class set")
+ resp, update_body = self.adm_client.update_quota_class_set('default',
+ **body)
+ self.assertEqual(200, resp.status)
+ LOG.debug("assert that the response has all of the changed values")
+ self.assertThat(update_body.items(),
+ matchers.ContainsAll(body.items()))
+
+
+class QuotaClassesAdminTestXML(QuotaClassesAdminTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index f728d68..004ce8f 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -43,6 +43,7 @@
"Skipped because neutron do not support all_tenants"
"search filter.")
@test.attr(type='smoke')
+ @test.services('network')
def test_list_security_groups_list_all_tenants_filter(self):
# Admin can list security groups of all tenants
# List of all security groups created
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a1aaa95..caf4174 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -67,6 +67,8 @@
cls.keypairs_client = cls.os.keypairs_client
cls.security_groups_client = cls.os.security_groups_client
cls.quotas_client = cls.os.quotas_client
+ # NOTE(mriedem): os-quota-class-sets is v2 API only
+ cls.quota_classes_client = cls.os.quota_classes_client
cls.limits_client = cls.os.limits_client
cls.volumes_extensions_client = cls.os.volumes_extensions_client
cls.volumes_client = cls.os.volumes_client
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 b3789f8..1eae66f 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -54,6 +54,7 @@
pass
@test.attr(type='gate')
+ @test.services('network')
def test_allocate_floating_ip(self):
# Positive test:Allocation of a new floating IP to a project
# should be successful
@@ -69,6 +70,7 @@
self.assertIn(floating_ip_details, body)
@test.attr(type='gate')
+ @test.services('network')
def test_delete_floating_ip(self):
# Positive test:Deletion of valid floating IP from project
# should be successful
@@ -85,6 +87,7 @@
self.client.wait_for_resource_deletion(floating_ip_body['id'])
@test.attr(type='gate')
+ @test.services('network')
def test_associate_disassociate_floating_ip(self):
# Positive test:Associate and disassociate the provided floating IP
# to a specific server should be successful
@@ -101,6 +104,7 @@
self.assertEqual(202, resp.status)
@test.attr(type='gate')
+ @test.services('network')
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
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 9fc43e2..042a19a 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -48,6 +48,7 @@
break
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_allocate_floating_ip_from_nonexistent_pool(self):
# Negative test:Allocation of a new floating IP from a nonexistent_pool
# to a project should fail
@@ -56,6 +57,7 @@
"non_exist_pool")
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_delete_nonexistent_floating_ip(self):
# Negative test:Deletion of a nonexistent floating IP
# from project should fail
@@ -65,6 +67,7 @@
self.non_exist_id)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_associate_nonexistent_floating_ip(self):
# Negative test:Association of a non existent floating IP
# to specific server should fail
@@ -74,6 +77,7 @@
"0.0.0.0", self.server_id)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_dissociate_nonexistent_floating_ip(self):
# Negative test:Dissociation of a non existent floating IP should fail
# Dissociating non existent floating IP
@@ -82,6 +86,7 @@
"0.0.0.0", self.server_id)
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_associate_ip_to_server_without_passing_floating_ip(self):
# Negative test:Association of empty floating IP to specific server
# should raise NotFound exception
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 94dcf61..a6878d9 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -37,6 +37,7 @@
super(FloatingIPDetailsTestJSON, cls).tearDownClass()
@test.attr(type='gate')
+ @test.services('network')
def test_list_floating_ips(self):
# Positive test:Should return the list of floating IPs
resp, body = self.client.list_floating_ips()
@@ -48,6 +49,7 @@
self.assertIn(self.floating_ip[i], floating_ips)
@test.attr(type='gate')
+ @test.services('network')
def test_get_floating_ip_details(self):
# Positive test:Should be able to GET the details of floatingIP
# Creating a floating IP for which details are to be checked
@@ -70,6 +72,7 @@
self.assertEqual(floating_ip_id, body['id'])
@test.attr(type='gate')
+ @test.services('network')
def test_list_floating_ip_pools(self):
# Positive test:Should return the list of floating IP Pools
resp, floating_ip_pools = self.client.list_floating_ip_pools()
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index 8cb2f08..b11ef5b 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -32,6 +32,7 @@
cls.client = cls.floating_ips_client
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_get_nonexistent_floating_ip_details(self):
# Negative test:Should not be able to GET the details
# of non-existent floating IP
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 35f6fc2..a1808dc 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -29,6 +29,7 @@
cls.neutron_available = CONF.service_available.neutron
@test.attr(type='smoke')
+ @test.services('network')
def test_security_group_rules_create(self):
# Positive test: Creation of Security Group rule
# should be successful
@@ -48,6 +49,7 @@
self.assertEqual(200, resp.status)
@test.attr(type='smoke')
+ @test.services('network')
def test_security_group_rules_create_with_optional_arguments(self):
# Positive test: Creation of Security Group rule
# with optional arguments
@@ -78,6 +80,7 @@
self.assertEqual(200, resp.status)
@test.attr(type='smoke')
+ @test.services('network')
def test_security_group_rules_list(self):
# Positive test: Created Security Group rules should be
# in the list of all rules
@@ -114,6 +117,7 @@
self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
@test.attr(type='smoke')
+ @test.services('network')
def test_security_group_rules_delete_when_peer_group_deleted(self):
# Positive test:rule will delete when peer group deleting
# Creating a Security Group to add rules to it
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 0b53037..cfa839a 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -37,6 +37,7 @@
cls.client = cls.security_groups_client
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_non_existent_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
@@ -50,6 +51,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with Parent group id which is not integer
@@ -63,6 +65,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_duplicate(self):
# Negative test: Create Security Group rule duplicate should fail
# Creating a Security Group to add rule to it
@@ -86,6 +89,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_invalid_ip_protocol(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid ip_protocol
@@ -102,6 +106,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_invalid_from_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid from_port
@@ -117,6 +122,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_invalid_to_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid to_port
@@ -132,6 +138,7 @@
parent_group_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_create_security_group_rule_with_invalid_port_range(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid port range.
@@ -147,6 +154,7 @@
secgroup_id, ip_protocol, from_port, to_port)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index a077943..860aebc 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -27,6 +27,7 @@
cls.client = cls.security_groups_client
@test.attr(type='smoke')
+ @test.services('network')
def test_security_groups_create_list_delete(self):
# Positive test:Should return the list of Security Groups
# Create 3 Security Groups
@@ -61,6 +62,7 @@
for m_group in deleted_sgs))
@test.attr(type='smoke')
+ @test.services('network')
def test_security_group_create_get_delete(self):
# Security Group should be created, fetched and deleted
# with char space between name along with
@@ -85,6 +87,7 @@
self.client.wait_for_resource_deletion(securitygroup['id'])
@test.attr(type='smoke')
+ @test.services('network')
def test_server_security_groups(self):
# Checks that security groups may be added and linked to a server
# and not deleted if the server is active.
@@ -131,6 +134,7 @@
self.assertEqual(202, resp.status)
@test.attr(type='smoke')
+ @test.services('network')
def test_update_security_groups(self):
# Update security group name and description
# Create a security group
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index aa2d32e..a9cca55 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -47,6 +47,7 @@
return non_exist_id
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_security_group_get_nonexistent_group(self):
# Negative test:Should not be able to GET the details
# of non-existent Security Group
@@ -57,6 +58,7 @@
@test.skip_because(bug="1161411",
condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_security_group_create_with_invalid_group_name(self):
# Negative test: Security Group should not be created with group name
# as an empty string/with white spaces/chars more than 255
@@ -77,6 +79,7 @@
@test.skip_because(bug="1161411",
condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_security_group_create_with_invalid_group_description(self):
# Negative test:Security Group should not be created with description
# as an empty string/with white spaces/chars more than 255
@@ -96,6 +99,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron allows duplicate names for security groups")
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_security_group_create_with_duplicate_name(self):
# Negative test:Security Group with duplicate name should not
# be created
@@ -110,6 +114,7 @@
s_description)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_delete_the_default_security_group(self):
# Negative test:Deletion of the "default" Security Group should Fail
default_security_group_id = None
@@ -124,6 +129,7 @@
default_security_group_id)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_delete_nonexistent_security_group(self):
# Negative test:Deletion of a non-existent Security Group should fail
non_exist_id = self._generate_a_non_existent_security_group_id()
@@ -131,6 +137,7 @@
self.client.delete_security_group, non_exist_id)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_delete_security_group_without_passing_id(self):
# Negative test:Deletion of a Security Group with out passing ID
# should Fail
@@ -140,6 +147,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_id")
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_update_security_group_with_invalid_sg_id(self):
# Update security_group with invalid sg_id should fail
s_name = data_utils.rand_name('sg-')
@@ -153,6 +161,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_name")
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_update_security_group_with_invalid_sg_name(self):
# Update security_group with invalid sg_name should fail
resp, securitygroup = self.create_security_group()
@@ -168,6 +177,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_description")
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_update_security_group_with_invalid_sg_des(self):
# Update security_group with invalid sg_des should fail
resp, securitygroup = self.create_security_group()
@@ -181,6 +191,7 @@
securitygroup_id, description=s_new_des)
@test.attr(type=['negative', 'smoke'])
+ @test.services('network')
def test_update_non_existent_security_group(self):
# Update a non-existent Security Group should Fail
non_exist_id = self._generate_a_non_existent_security_group_id()
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 297b300..067d721 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -107,6 +107,7 @@
self.assertEqual(sorted(list1), sorted(list2))
@test.attr(type='smoke')
+ @test.services('network')
def test_create_list_show_delete_interfaces(self):
server, ifs = self._create_server_get_interfaces()
interface_count = len(ifs)
@@ -128,6 +129,7 @@
self.assertEqual(len(ifs) - 1, len(_ifs))
@test.attr(type='smoke')
+ @test.services('network')
def test_add_remove_fixed_ip(self):
# Add and Remove the fixed IP to server.
server, ifs = self._create_server_get_interfaces()
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 0c14dc2..846bf3e 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -34,6 +34,7 @@
@test.skip_because(bug="1210483",
condition=CONF.service_available.neutron)
@test.attr(type='smoke')
+ @test.services('network')
def test_list_server_addresses(self):
# All public and private addresses for
# a server should be returned
@@ -51,6 +52,7 @@
self.assertTrue(address['version'])
@test.attr(type='smoke')
+ @test.services('network')
def test_list_server_addresses_by_network(self):
# Providing a network type should filter
# the addresses return by that type
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index d37f7fa..e190161 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -29,12 +29,14 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_list_server_addresses_invalid_server_id(self):
# List addresses request should fail if server id not in system
self.assertRaises(exceptions.NotFound, self.client.list_addresses,
'999')
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_list_server_addresses_by_network_neg(self):
# List addresses by network should fail if network name not valid
self.assertRaises(exceptions.NotFound,
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 6354996..421ba8b 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -36,6 +36,7 @@
@test.skip_because(bug="1183436",
condition=CONF.service_available.neutron)
@test.attr(type='gate')
+ @test.services('network')
def test_list_virtual_interfaces(self):
# Positive test:Should be able to GET the virtual interfaces list
# for a given server_id
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 87289d8..bcb2686 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -30,6 +30,7 @@
cls.client = cls.servers_client
@test.attr(type=['negative', 'gate'])
+ @test.services('network')
def test_list_virtual_interfaces_invalid_server_id(self):
# Negative test: Should not be able to GET virtual interfaces
# for an invalid server_id
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index dc85e76..eeff3ce 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -14,11 +14,17 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
from tempest import test
class QuotasTestJSON(base.BaseV2ComputeTest):
+ def setUp(self):
+ # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+ self.useFixture(fixtures.LockFixture('compute_quotas'))
+ super(QuotasTestJSON, self).setUp()
+
@classmethod
def setUpClass(cls):
super(QuotasTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index 64339b8..4c2dcbe 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -27,7 +27,6 @@
cls.resp = resp
cls.server_id = server['id']
- @test.skip_because(bug="1206032")
@test.attr(type='gate')
def test_list_server_actions(self):
# List actions of the provided server
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index 62a7556..ecf70cf 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -14,11 +14,17 @@
# under the License.
from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
from tempest import test
class QuotasV3Test(base.BaseV3ComputeTest):
+ def setUp(self):
+ # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+ self.useFixture(fixtures.LockFixture('compute_quotas'))
+ super(QuotasV3Test, self).setUp()
+
@classmethod
def setUpClass(cls):
super(QuotasV3Test, cls).setUpClass()
diff --git a/tempest/api/data_processing/test_cluster_templates.py b/tempest/api/data_processing/test_cluster_templates.py
index e5c6303..ad9ed2a 100644
--- a/tempest/api/data_processing/test_cluster_templates.py
+++ b/tempest/api/data_processing/test_cluster_templates.py
@@ -22,6 +22,7 @@
sahara/restapi/rest_api_v1.0.html#cluster-templates
"""
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ClusterTemplateTest, cls).setUpClass()
# create node group template
@@ -39,6 +40,7 @@
}
}
resp_body = cls.create_node_group_template(**node_group_template)[1]
+ node_group_template_id = resp_body['id']
cls.full_cluster_template = {
'description': 'Test cluster template',
@@ -65,7 +67,7 @@
},
{
'name': 'worker-node',
- 'node_group_template_id': resp_body['id'],
+ 'node_group_template_id': node_group_template_id,
'count': 3
}
]
diff --git a/tempest/api/data_processing/test_data_sources.py b/tempest/api/data_processing/test_data_sources.py
index c72e828..345153b 100644
--- a/tempest/api/data_processing/test_data_sources.py
+++ b/tempest/api/data_processing/test_data_sources.py
@@ -14,11 +14,8 @@
from tempest.api.data_processing import base as dp_base
from tempest.common.utils import data_utils
-from tempest import config
from tempest import test
-CONF = config.CONF
-
class DataSourceTest(dp_base.BaseDataProcessingTest):
@classmethod
@@ -28,8 +25,8 @@
'url': 'swift://sahara-container.sahara/input-source',
'description': 'Test data source',
'credentials': {
- 'user': CONF.identity.username,
- 'password': CONF.identity.password
+ 'user': cls.os.credentials.username,
+ 'password': cls.os.credentials.password
},
'type': 'swift'
}
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 90dccca..b680b64 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -25,6 +25,10 @@
@test.safe_setup
def setUpClass(cls):
super(RolesV3TestJSON, cls).setUpClass()
+ for _ in range(3):
+ role_name = data_utils.rand_name(name='role-')
+ _, role = cls.client.create_role(role_name)
+ cls.data.v3_roles.append(role)
cls.fetched_role_ids = list()
u_name = data_utils.rand_name('user-')
u_desc = '%s description' % u_name
@@ -186,6 +190,14 @@
self.domain['id'], self.group_body['id'], self.role['id'])
self.assertEqual(resp['status'], '204')
+ @test.attr(type='gate')
+ def test_list_roles(self):
+ # Return a list of all roles
+ resp, body = self.client.list_roles()
+ self.assertEqual(200, resp.status)
+ found = [role for role in body if role in self.data.v3_roles]
+ self.assertEqual(len(found), len(self.data.v3_roles))
+
class RolesV3TestXML(RolesV3TestJSON):
_interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 78cb221..ac3a072 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -277,13 +277,6 @@
block defined by tenant-network_cidr
"""
- @classmethod
- @test.safe_setup
- def setUpClass(cls):
- super(BulkNetworkOpsTestJSON, cls).setUpClass()
- cls.network1 = cls.create_network()
- cls.network2 = cls.create_network()
-
def _delete_networks(self, created_networks):
for n in created_networks:
resp, body = self.client.delete_network(n['id'])
@@ -332,11 +325,11 @@
@test.attr(type='smoke')
def test_bulk_create_delete_subnet(self):
+ networks = [self.create_network(), self.create_network()]
# Creates 2 subnets in one request
cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
mask_bits = CONF.network.tenant_network_mask_bits
cidrs = [subnet_cidr for subnet_cidr in cidr.subnet(mask_bits)]
- networks = [self.network1['id'], self.network2['id']]
names = [data_utils.rand_name('subnet-') for i in range(len(networks))]
subnets_list = []
# TODO(raies): "for IPv6, version list [4, 6] will be used.
@@ -344,7 +337,7 @@
ip_version = [4, 4]
for i in range(len(names)):
p1 = {
- 'network_id': networks[i],
+ 'network_id': networks[i]['id'],
'cidr': str(cidrs[(i)]),
'name': names[i],
'ip_version': ip_version[i]
@@ -364,14 +357,14 @@
@test.attr(type='smoke')
def test_bulk_create_delete_port(self):
+ networks = [self.create_network(), self.create_network()]
# Creates 2 ports in one request
- networks = [self.network1['id'], self.network2['id']]
names = [data_utils.rand_name('port-') for i in range(len(networks))]
port_list = []
state = [True, False]
for i in range(len(names)):
p1 = {
- 'network_id': networks[i],
+ 'network_id': networks[i]['id'],
'name': names[i],
'admin_state_up': state[i],
}
diff --git a/tempest/api_schema/compute/hypervisors.py b/tempest/api_schema/compute/hypervisors.py
index 630901e..e9e1bc9 100644
--- a/tempest/api_schema/compute/hypervisors.py
+++ b/tempest/api_schema/compute/hypervisors.py
@@ -24,7 +24,7 @@
'properties': {
'count': {'type': 'integer'},
'current_workload': {'type': 'integer'},
- 'disk_available_least': {'type': 'integer'},
+ 'disk_available_least': {'type': ['integer', 'null']},
'free_disk_gb': {'type': 'integer'},
'free_ram_mb': {'type': 'integer'},
'local_gb': {'type': 'integer'},
@@ -110,7 +110,7 @@
'properties': {
'cpu_info': {'type': 'string'},
'current_workload': {'type': 'integer'},
- 'disk_available_least': {'type': 'integer'},
+ 'disk_available_least': {'type': ['integer', 'null']},
'host_ip': {
'type': 'string',
'format': 'ip-address'
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index 2519eb5..ad0aa29 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -48,7 +48,7 @@
}
}
-base_update_server = {
+base_update_get_server = {
'status_code': [200],
'response_body': {
'type': 'object',
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/compute/v2/floating_ips.py
index fb3667b..def0a78 100644
--- a/tempest/api_schema/compute/v2/floating_ips.py
+++ b/tempest/api_schema/compute/v2/floating_ips.py
@@ -128,3 +128,31 @@
'required': ['floating_ips_bulk_delete']
}
}
+
+list_floating_ips_bulk = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'floating_ip_info': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'address': {
+ 'type': 'string',
+ 'format': 'ip-address'
+ },
+ 'instance_uuid': {'type': ['string', 'null']},
+ 'interface': {'type': ['string', 'null']},
+ 'pool': {'type': ['string', 'null']},
+ 'project_id': {'type': ['string', 'null']}
+ },
+ 'required': ['address', 'instance_uuid', 'interface',
+ 'pool', 'project_id']
+ }
+ }
+ },
+ 'required': ['floating_ip_info']
+ }
+}
diff --git a/tempest/api_schema/compute/v2/quota_classes.py b/tempest/api_schema/compute/v2/quota_classes.py
new file mode 100644
index 0000000..3464fb4
--- /dev/null
+++ b/tempest/api_schema/compute/v2/quota_classes.py
@@ -0,0 +1,31 @@
+# Copyright 2014 IBM 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.
+
+import copy
+
+from tempest.api_schema.compute.v2 import quotas
+
+# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets
+# except for the key in the response body is quota_class_set instead of
+# quota_set, so update this copy of the schema from os-quota-sets.
+quota_set = copy.deepcopy(quotas.quota_set)
+quota_set['response_body']['properties']['quota_class_set'] = (
+ quota_set['response_body']['properties'].pop('quota_set'))
+quota_set['response_body']['required'] = ['quota_class_set']
+
+quota_set_update = copy.deepcopy(quotas.quota_set_update)
+quota_set_update['response_body']['properties']['quota_class_set'] = (
+ quota_set_update['response_body']['properties'].pop('quota_set'))
+quota_set_update['response_body']['required'] = ['quota_class_set']
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index 5e9fbd5..dc4054c 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -43,7 +43,7 @@
}
}
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
update_server['response_body']['properties']['server']['properties'].update({
'hostId': {'type': 'string'},
'OS-DCF:diskConfig': {'type': 'string'},
@@ -57,6 +57,39 @@
'hostId'
)
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+ 'key_name': {'type': ['string', 'null']},
+ 'hostId': {'type': 'string'},
+
+ # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
+ # attributes.
+ 'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+ 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+ 'OS-EXT-AZ:availability_zone': {'type': 'string'},
+
+ # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR"
+ # attributes.
+ 'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+ 'OS-EXT-STS:vm_state': {'type': 'string'},
+ 'OS-EXT-STS:power_state': {'type': 'integer'},
+ 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+ 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+ 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+ 'os-extended-volumes:volumes_attached': {'type': 'array'},
+ 'OS-DCF:diskConfig': {'type': 'string'},
+ 'accessIPv4': parameter_types.access_ip_v4,
+ 'accessIPv6': parameter_types.access_ip_v6,
+ 'config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+ # NOTE: OS-SRV-USG, OS-EXT-AZ, OS-EXT-STS, OS-EXT-SRV-ATTR,
+ # os-extended-volumes, OS-DCF and accessIPv4/v6 are API
+ # extension, and some environments return a response without
+ # these attributes. So they are not 'required'.
+ 'hostId'
+)
+
list_virtual_interfaces = {
'status_code': [200],
'response_body': {
@@ -175,6 +208,20 @@
'status_code': [204]
}
+list_server_groups = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'server_groups': {
+ 'type': 'array',
+ 'items': common_server_group
+ }
+ },
+ 'required': ['server_groups']
+ }
+}
+
instance_actions_object = copy.deepcopy(servers.common_instance_actions)
instance_actions_object[
'properties'].update({'instance_uuid': {'type': 'string'}})
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index 7572029..3b50516 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -54,7 +54,7 @@
['type', 'mac_addr']
)
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
update_server['response_body']['properties']['server']['properties'].update({
'addresses': addresses_v3,
'host_id': {'type': 'string'},
@@ -68,6 +68,43 @@
'host_id'
)
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+ 'key_name': {'type': ['string', 'null']},
+ 'host_id': {'type': 'string'},
+
+ # NOTE: Non-admin users also can see "os-server-usage" and
+ # "os-extended-availability-zone" attributes.
+ 'os-server-usage:launched_at': {'type': ['string', 'null']},
+ 'os-server-usage:terminated_at': {'type': ['string', 'null']},
+ 'os-extended-availability-zone:availability_zone': {'type': 'string'},
+
+ # NOTE: Admin users only can see "os-extended-status" and
+ # "os-extended-server-attributes" attributes.
+ 'os-extended-status:task_state': {'type': ['string', 'null']},
+ 'os-extended-status:vm_state': {'type': 'string'},
+ 'os-extended-status:power_state': {'type': 'integer'},
+ 'os-extended-status:locked_by': {'type': ['string', 'null']},
+ 'os-extended-server-attributes:host': {'type': ['string', 'null']},
+ 'os-extended-server-attributes:instance_name': {'type': 'string'},
+ 'os-extended-server-attributes:hypervisor_hostname': {
+ 'type': ['string', 'null']
+ },
+ 'os-extended-volumes:volumes_attached': {'type': 'array'},
+ 'os-pci:pci_devices': {'type': 'array'},
+ 'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+ 'os-access-ips:access_ip_v6': parameter_types.access_ip_v6,
+ 'os-config-drive:config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+ # NOTE: os-server-usage, os-extended-availability-zone,
+ # os-extended-status, os-extended-server-attributes,
+ # os-extended-volumes, os-pci, os-access-ips and
+ # os-config-driveare API extension, and some environments
+ # return a response without these attributes. So they are not 'required'.
+ 'host_id'
+)
+
attach_detach_volume = {
'status_code': [202]
}
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/test_cinder.py
index 63ad0e3..946b89e 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/test_cinder.py
@@ -50,13 +50,20 @@
self.assertTableStruct(roles, ['Name', 'Value'])
def test_cinder_backup_list(self):
- self.cinder('backup-list')
+ backup_list = self.parser.listing(self.cinder('backup-list'))
+ self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status',
+ 'Name', 'Size', 'Object Count',
+ 'Container'])
def test_cinder_extra_specs_list(self):
- self.cinder('extra-specs-list')
+ extra_specs_list = self.parser.listing(self.cinder('extra-specs-list'))
+ self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs'])
def test_cinder_volumes_list(self):
- self.cinder('list')
+ list = self.parser.listing(self.cinder('list'))
+ self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size',
+ 'Volume Type', 'Bootable',
+ 'Attached to'])
self.cinder('list', params='--all-tenants 1')
self.cinder('list', params='--all-tenants 0')
self.assertRaises(subprocess.CalledProcessError,
@@ -85,43 +92,59 @@
self.assertTableStruct(roles, ['Property', 'Value'])
def test_cinder_rate_limits(self):
- self.cinder('rate-limits')
+ rate_limits = self.parser.listing(self.cinder('rate-limits'))
+ self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain',
+ 'Unit', 'Next_Available'])
@testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
'Volume snapshot not available.')
def test_cinder_snapshot_list(self):
- self.cinder('snapshot-list')
+ snapshot_list = self.parser.listing(self.cinder('snapshot-list'))
+ self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status',
+ 'Name', 'Size'])
def test_cinder_type_list(self):
- self.cinder('type-list')
+ type_list = self.parser.listing(self.cinder('type-list'))
+ self.assertTableStruct(type_list, ['ID', 'Name'])
def test_cinder_list_extensions(self):
roles = self.parser.listing(self.cinder('list-extensions'))
self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
def test_cinder_credentials(self):
- self.cinder('credentials')
+ credentials = self.parser.listing(self.cinder('credentials'))
+ self.assertTableStruct(credentials, ['User Credentials', 'Value'])
def test_cinder_availability_zone_list(self):
- self.cinder('availability-zone-list')
+ zone_list = self.parser.listing(self.cinder('availability-zone-list'))
+ self.assertTableStruct(zone_list, ['Name', 'Status'])
def test_cinder_endpoints(self):
- self.cinder('endpoints')
+ endpoints = self.parser.listing(self.cinder('endpoints'))
+ self.assertTableStruct(endpoints, ['nova', 'Value'])
def test_cinder_service_list(self):
- self.cinder('service-list')
+ service_list = self.parser.listing(self.cinder('service-list'))
+ self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
+ 'Status', 'State', 'Updated_at',
+ 'Disabled Reason'])
def test_cinder_transfer_list(self):
- self.cinder('transfer-list')
+ transfer_list = self.parser.listing(self.cinder('transfer-list'))
+ self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name'])
def test_cinder_bash_completion(self):
self.cinder('bash-completion')
def test_cinder_qos_list(self):
- self.cinder('qos-list')
+ qos_list = self.parser.listing(self.cinder('qos-list'))
+ self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs'])
def test_cinder_encryption_type_list(self):
- self.cinder('encryption-type-list')
+ encrypt_list = self.parser.listing(self.cinder('encryption-type-list'))
+ self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider',
+ 'Cipher', 'Key Size',
+ 'Control Location'])
def test_admin_help(self):
help_text = self.cinder('help')
diff --git a/tempest/clients.py b/tempest/clients.py
index 4050a20..4e2205e 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -50,6 +50,7 @@
from tempest.services.compute.json.limits_client import LimitsClientJSON
from tempest.services.compute.json.migrations_client import \
MigrationsClientJSON
+from tempest.services.compute.json.quotas_client import QuotaClassesClientJSON
from tempest.services.compute.json.quotas_client import QuotasClientJSON
from tempest.services.compute.json.security_groups_client import \
SecurityGroupsClientJSON
@@ -105,6 +106,7 @@
InterfacesClientXML
from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
from tempest.services.compute.xml.limits_client import LimitsClientXML
+from tempest.services.compute.xml.quotas_client import QuotaClassesClientXML
from tempest.services.compute.xml.quotas_client import QuotasClientXML
from tempest.services.compute.xml.security_groups_client \
import SecurityGroupsClientXML
@@ -220,6 +222,8 @@
self.images_client = ImagesClientXML(self.auth_provider)
self.keypairs_client = KeyPairsClientXML(self.auth_provider)
self.quotas_client = QuotasClientXML(self.auth_provider)
+ self.quota_classes_client = QuotaClassesClientXML(
+ self.auth_provider)
self.flavors_client = FlavorsClientXML(self.auth_provider)
self.extensions_client = ExtensionsClientXML(self.auth_provider)
self.volumes_extensions_client = VolumesExtensionsClientXML(
@@ -288,6 +292,8 @@
self.keypairs_v3_client = KeyPairsV3ClientJSON(
self.auth_provider)
self.quotas_client = QuotasClientJSON(self.auth_provider)
+ self.quota_classes_client = QuotaClassesClientJSON(
+ 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)
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index e041fd2..800b3b0 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -258,6 +258,13 @@
else:
self.vip_ip = self.vip.address
+ # Currently the ovs-agent is not enforcing security groups on the
+ # vip port - see https://bugs.launchpad.net/neutron/+bug/1163569
+ # However the linuxbridge-agent does, and it is necessary to add a
+ # security group with a rule that allows tcp port 80 to the vip port.
+ body = {'port': {'security_groups': [self.security_group.id]}}
+ self.network_client.update_port(self.vip.port_id, body)
+
def _check_load_balancing(self):
"""
1. Send 10 requests on the floating ip associated with the VIP
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0028eea..cd195f4 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -130,6 +130,7 @@
"""Returns a list of all floating IPs bulk."""
resp, body = self.get('os-floating-ips-bulk')
body = json.loads(body)
+ self.validate_response(schema.list_floating_ips_bulk, resp, body)
return resp, body['floating_ip_info']
def delete_floating_ips_bulk(self, ip_range):
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7e828d8..14b7100 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,6 +15,7 @@
import json
+from tempest.api_schema.compute.v2 import quota_classes as classes_schema
from tempest.api_schema.compute.v2 import quotas as schema
from tempest.common import rest_client
from tempest import config
@@ -118,3 +119,32 @@
resp, body = self.delete('os-quota-sets/%s' % str(tenant_id))
self.validate_response(schema.delete_quota, resp, body)
return resp, body
+
+
+class QuotaClassesClientJSON(rest_client.RestClient):
+
+ def __init__(self, auth_provider):
+ super(QuotaClassesClientJSON, self).__init__(auth_provider)
+ self.service = CONF.compute.catalog_type
+
+ def get_quota_class_set(self, quota_class_id):
+ """List the quota class set for a quota class."""
+
+ url = 'os-quota-class-sets/%s' % str(quota_class_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.validate_response(classes_schema.quota_set, resp, body)
+ return resp, body['quota_class_set']
+
+ def update_quota_class_set(self, quota_class_id, **kwargs):
+ """
+ Updates the quota class's limits for one or more resources.
+ """
+ post_body = json.dumps({'quota_class_set': kwargs})
+
+ resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+ post_body)
+
+ body = json.loads(body)
+ self.validate_response(classes_schema.quota_set_update, resp, body)
+ return resp, body['quota_class_set']
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index e1661c0..69d2f35 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -134,6 +134,7 @@
"""Returns the details of an existing server."""
resp, body = self.get("servers/%s" % str(server_id))
body = json.loads(body)
+ self.validate_response(schema.get_server, resp, body)
return resp, body['server']
def delete_server(self, server_id):
@@ -524,6 +525,7 @@
"""List the server-groups."""
resp, body = self.get("os-server-groups")
body = json.loads(body)
+ self.validate_response(schema.list_server_groups, resp, body)
return resp, body['server_groups']
def get_server_group(self, server_group_id):
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 11258a6..d933998 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -136,6 +136,7 @@
"""Returns the details of an existing server."""
resp, body = self.get("servers/%s" % str(server_id))
body = json.loads(body)
+ self.validate_response(schema.get_server, resp, body)
return resp, body['server']
def delete_server(self, server_id):
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 5502fcc..7f87248 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -22,6 +22,19 @@
CONF = config.CONF
+def format_quota(q):
+ quota = {}
+ for k, v in q.items():
+ try:
+ v = int(v)
+ except ValueError:
+ pass
+
+ quota[k] = v
+
+ return quota
+
+
class QuotasClientXML(rest_client.RestClient):
TYPE = "xml"
@@ -29,18 +42,6 @@
super(QuotasClientXML, self).__init__(auth_provider)
self.service = CONF.compute.catalog_type
- def _format_quota(self, q):
- quota = {}
- for k, v in q.items():
- try:
- v = int(v)
- except ValueError:
- pass
-
- quota[k] = v
-
- return quota
-
def get_quota_set(self, tenant_id, user_id=None):
"""List the quota set for a tenant."""
@@ -49,7 +50,7 @@
url += '?user_id=%s' % str(user_id)
resp, body = self.get(url)
body = xml_utils.xml_to_json(etree.fromstring(body))
- body = self._format_quota(body)
+ body = format_quota(body)
return resp, body
def get_default_quota_set(self, tenant_id):
@@ -58,7 +59,7 @@
url = 'os-quota-sets/%s/defaults' % str(tenant_id)
resp, body = self.get(url)
body = xml_utils.xml_to_json(etree.fromstring(body))
- body = self._format_quota(body)
+ body = format_quota(body)
return resp, body
def update_quota_set(self, tenant_id, user_id=None,
@@ -124,9 +125,41 @@
str(xml_utils.Document(post_body)))
body = xml_utils.xml_to_json(etree.fromstring(body))
- body = self._format_quota(body)
+ body = format_quota(body)
return resp, body
def delete_quota_set(self, tenant_id):
"""Delete the tenant's quota set."""
return self.delete('os-quota-sets/%s' % str(tenant_id))
+
+
+class QuotaClassesClientXML(rest_client.RestClient):
+ TYPE = "xml"
+
+ def __init__(self, auth_provider):
+ super(QuotaClassesClientXML, self).__init__(auth_provider)
+ self.service = CONF.compute.catalog_type
+
+ def get_quota_class_set(self, quota_class_id):
+ """List the quota class set for a quota class."""
+
+ url = 'os-quota-class-sets/%s' % str(quota_class_id)
+ resp, body = self.get(url)
+ body = xml_utils.xml_to_json(etree.fromstring(body))
+ body = format_quota(body)
+ return resp, body
+
+ def update_quota_class_set(self, quota_class_id, **kwargs):
+ """
+ Updates the quota class's limits for one or more resources.
+ """
+ post_body = xml_utils.Element("quota_class_set",
+ xmlns=xml_utils.XMLNS_11,
+ **kwargs)
+
+ resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+ str(xml_utils.Document(post_body)))
+
+ body = xml_utils.xml_to_json(etree.fromstring(body))
+ body = format_quota(body)
+ return resp, body
diff --git a/tempest/services/telemetry/telemetry_client_base.py b/tempest/services/telemetry/telemetry_client_base.py
index a073f54..b45c239 100644
--- a/tempest/services/telemetry/telemetry_client_base.py
+++ b/tempest/services/telemetry/telemetry_client_base.py
@@ -101,17 +101,17 @@
uri += "?%s" % urllib.urlencode(uri_dict)
return self.get(uri)
- def list_resources(self):
+ def list_resources(self, query=None):
uri = '%s/resources' % self.uri_prefix
- return self.get(uri)
+ return self.helper_list(uri, query)
- def list_meters(self):
+ def list_meters(self, query=None):
uri = '%s/meters' % self.uri_prefix
- return self.get(uri)
+ return self.helper_list(uri, query)
- def list_alarms(self):
+ def list_alarms(self, query=None):
uri = '%s/alarms' % self.uri_prefix
- return self.get(uri)
+ return self.helper_list(uri, query)
def list_statistics(self, meter, period=None, query=None):
uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)