Merge "Add a new credential provider to use a list of creds"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 9949577..4dcf460 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -422,6 +422,10 @@
# Does the test environment support pausing? (boolean value)
#pause=true
+# Does the test environment support shelving/unshelving?
+# (boolean value)
+#shelve=true
+
# Does the test environment support suspend/resume? (boolean
# value)
#suspend=true
@@ -454,6 +458,15 @@
# (boolean value)
#rescue=true
+# Enables returning of the instance password by the relevant
+# server API calls such as create, rebuild or rescue. (boolean
+# value)
+#enable_instance_password=true
+
+# Does the test environment support dynamic network interface
+# attachment? (boolean value)
+#interface_attach=true
+
[dashboard]
diff --git a/tempest/api/baremetal/README.rst b/tempest/api/baremetal/README.rst
new file mode 100644
index 0000000..759c937
--- /dev/null
+++ b/tempest/api/baremetal/README.rst
@@ -0,0 +1,25 @@
+Tempest Field Guide to Baremetal API tests
+==========================================
+
+
+What are these tests?
+---------------------
+
+These tests stress the OpenStack baremetal provisioning API provided by
+Ironic.
+
+
+Why are these tests in tempest?
+------------------------------
+
+The purpose of these tests is to exercise the various APIs provided by Ironic
+for managing baremetal nodes.
+
+
+Scope of these tests
+--------------------
+
+The baremetal API test perform basic CRUD operations on the Ironic node
+inventory. They do not actually perform hardware provisioning. It is important
+to note that all Ironic API actions are admin operations meant to be used
+either by cloud operators or other OpenStack services (i.e., Nova).
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api/baremetal/admin/__init__.py
similarity index 100%
copy from tempest/api_schema/compute/__init__.py
copy to tempest/api/baremetal/admin/__init__.py
diff --git a/tempest/api/baremetal/base.py b/tempest/api/baremetal/admin/base.py
similarity index 100%
rename from tempest/api/baremetal/base.py
rename to tempest/api/baremetal/admin/base.py
diff --git a/tempest/api/baremetal/test_api_discovery.py b/tempest/api/baremetal/admin/test_api_discovery.py
similarity index 97%
rename from tempest/api/baremetal/test_api_discovery.py
rename to tempest/api/baremetal/admin/test_api_discovery.py
index bee10b9..7368b3e 100644
--- a/tempest/api/baremetal/test_api_discovery.py
+++ b/tempest/api/baremetal/admin/test_api_discovery.py
@@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest import test
diff --git a/tempest/api/baremetal/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
similarity index 98%
rename from tempest/api/baremetal/test_chassis.py
rename to tempest/api/baremetal/admin/test_chassis.py
index 4ab86c2..c306c34 100644
--- a/tempest/api/baremetal/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -11,7 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest.common.utils import data_utils
from tempest import exceptions as exc
from tempest import test
diff --git a/tempest/api/baremetal/test_drivers.py b/tempest/api/baremetal/admin/test_drivers.py
similarity index 96%
rename from tempest/api/baremetal/test_drivers.py
rename to tempest/api/baremetal/admin/test_drivers.py
index 852b6ab..649886b 100644
--- a/tempest/api/baremetal/test_drivers.py
+++ b/tempest/api/baremetal/admin/test_drivers.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest import config
from tempest import test
diff --git a/tempest/api/baremetal/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
similarity index 98%
rename from tempest/api/baremetal/test_nodes.py
rename to tempest/api/baremetal/admin/test_nodes.py
index 1572840..fc67854 100644
--- a/tempest/api/baremetal/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -12,7 +12,7 @@
import six
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest import exceptions as exc
from tempest import test
diff --git a/tempest/api/baremetal/test_nodestates.py b/tempest/api/baremetal/admin/test_nodestates.py
similarity index 97%
rename from tempest/api/baremetal/test_nodestates.py
rename to tempest/api/baremetal/admin/test_nodestates.py
index 3044bc6..f24f490 100644
--- a/tempest/api/baremetal/test_nodestates.py
+++ b/tempest/api/baremetal/admin/test_nodestates.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest import exceptions
from tempest.openstack.common import timeutils
from tempest import test
diff --git a/tempest/api/baremetal/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
similarity index 99%
rename from tempest/api/baremetal/test_ports.py
rename to tempest/api/baremetal/admin/test_ports.py
index 4ac7e29..d4adba9 100644
--- a/tempest/api/baremetal/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest.common.utils import data_utils
from tempest import exceptions as exc
from tempest import test
diff --git a/tempest/api/baremetal/test_ports_negative.py b/tempest/api/baremetal/admin/test_ports_negative.py
similarity index 99%
rename from tempest/api/baremetal/test_ports_negative.py
rename to tempest/api/baremetal/admin/test_ports_negative.py
index 3e77a5f..7646677 100644
--- a/tempest/api/baremetal/test_ports_negative.py
+++ b/tempest/api/baremetal/admin/test_ports_negative.py
@@ -10,7 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
from tempest.common.utils import data_utils
from tempest import exceptions as exc
from tempest import test
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index f147b9c..599b058 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -111,7 +111,9 @@
security_groups=default_sg_quota)
# Check we cannot create anymore
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
self.sg_client.create_security_group,
"sg-overlimit", "sg-desc")
@@ -147,7 +149,9 @@
ip_protocol = 'tcp'
# Check we cannot create SG rule anymore
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.OverLimit, exceptions.Unauthorized),
self.sg_client.create_security_group_rule,
secgroup_id, ip_protocol, 1025, 1025)
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
new file mode 100644
index 0000000..07408a8
--- /dev/null
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -0,0 +1,127 @@
+# 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.
+
+import testtools
+
+from tempest.api.compute import base
+from tempest import config
+from tempest import exceptions
+from tempest import test
+
+CONF = config.CONF
+
+
+class SecurityGroupDefaultRulesTest(base.BaseV2ComputeAdminTest):
+
+ @classmethod
+ # TODO(GMann): Once Bug# 1311500 is fixed, these test can run
+ # for Neutron also.
+ @testtools.skipIf(CONF.service_available.neutron,
+ "Skip as this functionality is not yet "
+ "implemented in Neutron. Related Bug#1311500")
+ @test.safe_setup
+ def setUpClass(cls):
+ # A network and a subnet will be created for these tests
+ cls.set_network_resources(network=True, subnet=True)
+ super(SecurityGroupDefaultRulesTest, cls).setUpClass()
+ cls.adm_client = cls.os_adm.security_group_default_rules_client
+
+ def _create_security_group_default_rules(self, ip_protocol='tcp',
+ from_port=22, to_port=22,
+ cidr='10.10.0.0/24'):
+ # Create Security Group default rule
+ _, rule = self.adm_client.create_security_default_group_rule(
+ ip_protocol,
+ from_port,
+ to_port,
+ cidr=cidr)
+ self.assertEqual(ip_protocol, rule['ip_protocol'])
+ self.assertEqual(from_port, rule['from_port'])
+ self.assertEqual(to_port, rule['to_port'])
+ self.assertEqual(cidr, rule['ip_range']['cidr'])
+ return rule
+
+ @test.attr(type='smoke')
+ def test_create_delete_security_group_default_rules(self):
+ # Create and delete Security Group default rule
+ ip_protocols = {'tcp', 'udp', 'icmp'}
+ for ip_protocol in ip_protocols:
+ rule = self._create_security_group_default_rules(ip_protocol)
+ # Delete Security Group default rule
+ self.adm_client.delete_security_group_default_rule(rule['id'])
+ self.assertRaises(exceptions.NotFound,
+ self.adm_client.get_security_group_default_rule,
+ rule['id'])
+
+ @test.attr(type='smoke')
+ def test_create_security_group_default_rule_without_cidr(self):
+ ip_protocol = 'udp'
+ from_port = 80
+ to_port = 80
+ _, rule = self.adm_client.create_security_default_group_rule(
+ ip_protocol,
+ from_port,
+ to_port)
+ self.addCleanup(self.adm_client.delete_security_group_default_rule,
+ rule['id'])
+ self.assertNotEqual(0, rule['id'])
+ self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
+
+ @test.attr(type='smoke')
+ def test_create_security_group_default_rule_with_blank_cidr(self):
+ ip_protocol = 'icmp'
+ from_port = 10
+ to_port = 10
+ cidr = ''
+ _, rule = self.adm_client.create_security_default_group_rule(
+ ip_protocol,
+ from_port,
+ to_port,
+ cidr=cidr)
+ self.addCleanup(self.adm_client.delete_security_group_default_rule,
+ rule['id'])
+ self.assertNotEqual(0, rule['id'])
+ self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
+
+ @test.attr(type='smoke')
+ def test_security_group_default_rules_list(self):
+ ip_protocol = 'tcp'
+ from_port = 22
+ to_port = 22
+ cidr = '10.10.0.0/24'
+ rule = self._create_security_group_default_rules(ip_protocol,
+ from_port,
+ to_port,
+ cidr)
+ self.addCleanup(self.adm_client.delete_security_group_default_rule,
+ rule['id'])
+ _, rules = self.adm_client.list_security_group_default_rules()
+ self.assertNotEqual(0, len(rules))
+ self.assertIn(rule, rules)
+
+ @test.attr(type='smoke')
+ def test_default_security_group_default_rule_show(self):
+ ip_protocol = 'tcp'
+ from_port = 22
+ to_port = 22
+ cidr = '10.10.0.0/24'
+ rule = self._create_security_group_default_rules(ip_protocol,
+ from_port,
+ to_port,
+ cidr)
+ self.addCleanup(self.adm_client.delete_security_group_default_rule,
+ rule['id'])
+ _, fetched_rule = self.adm_client.get_security_group_default_rule(
+ rule['id'])
+ self.assertEqual(rule, fetched_rule)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 70a9604..a3295eb 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -83,6 +83,8 @@
cls.hypervisor_client = cls.os.hypervisor_client
cls.certificates_client = cls.os.certificates_client
cls.migrations_client = cls.os.migrations_client
+ cls.security_group_default_rules_client = (
+ cls.os.security_group_default_rules_client)
elif cls._api_version == 3:
if not CONF.compute_feature_enabled.api_v3:
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index f88699b..b2e2981 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -39,7 +39,9 @@
for xx in range(max_meta_data):
meta_data[str(xx)] = str(xx)
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
self.server_client.create_server,
name='test', meta=meta_data,
flavor_ref=self.flavor_ref,
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 067d721..d1192c0 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -29,6 +29,8 @@
def setUpClass(cls):
if not CONF.service_available.neutron:
raise cls.skipException("Neutron is required")
+ if not CONF.compute_feature_enabled.interface_attach:
+ raise cls.skipException("Interface attachment is not available.")
# This test class requires network and subnet
cls.set_network_resources(network=True, subnet=True)
super(AttachInterfacesTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 9e34922..9c8271f 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -70,6 +70,8 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_server_termination(server['id'])
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
# Delete a server while it's VM state is Shelved
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 71fcbff..ee525e7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -403,6 +403,8 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type='gate')
def test_shelve_unshelve_server(self):
resp, server = self.client.shelve_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index b55833c..fbda401 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -119,20 +119,22 @@
@test.attr(type=['negative', 'gate'])
def test_metadata_items_limit(self):
- # Raise a 413 OverLimit exception while exceeding metadata items limit
- # for tenant.
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised while exceeding metadata items limit for
+ # tenant.
_, quota_set = self.quotas.get_quota_set(self.tenant_id)
quota_metadata = quota_set['metadata_items']
req_metadata = {}
for num in range(1, quota_metadata + 2):
req_metadata['key' + str(num)] = 'val' + str(num)
- self.assertRaises(exceptions.OverLimit,
+ self.assertRaises((exceptions.OverLimit, exceptions.Unauthorized),
self.client.set_server_metadata,
self.server_id, req_metadata)
- # Raise a 413 OverLimit exception while exceeding metadata items limit
- # for tenant (update).
- self.assertRaises(exceptions.OverLimit,
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised while exceeding metadata items limit for
+ # tenant.
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
self.client.update_server_metadata,
self.server_id, req_metadata)
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index b7e4e38..6cc463d 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -40,8 +40,10 @@
path = 'etc/test' + str(i) + '.txt'
personality.append({'path': path,
'contents': base64.b64encode(file_contents)})
- self.assertRaises(exceptions.OverLimit, self.create_test_server,
- personality=personality)
+ # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+ # will be raised when out of quota
+ self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+ self.create_test_server, personality=personality)
@test.attr(type='gate')
def test_can_create_server_with_max_number_personality_files(self):
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index b35e55c..4582a46 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -34,7 +34,7 @@
cls.set_network_resources(network=True, subnet=True, router=True)
super(ServerRescueNegativeTestJSON, cls).setUpClass()
- cls.device = 'vdf'
+ cls.device = CONF.compute.volume_device_name
# Create a volume and wait for it to become ready for attach
resp, cls.volume = cls.volumes_extensions_client.create_volume(
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index d3297ce..792b523 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -425,6 +425,8 @@
self.client.restore_soft_deleted_server,
self.server_id)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_shelve_non_existent_server(self):
# shelve a non existent server
@@ -432,6 +434,8 @@
self.assertRaises(exceptions.NotFound, self.client.shelve_server,
nonexistent_server)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_shelve_shelved_server(self):
# shelve a shelved server.
@@ -460,6 +464,8 @@
self.client.unshelve_server(self.server_id)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_unshelve_non_existent_server(self):
# unshelve a non existent server
@@ -467,6 +473,8 @@
self.assertRaises(exceptions.NotFound, self.client.unshelve_server,
nonexistent_server)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_unshelve_server_invalid_state(self):
# unshelve an active server.
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 366cfc6..d99c329 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -51,7 +51,6 @@
self.assertEqual('200', resp['status'])
self.assertEqual([], servers)
- @test.skip_because(bug='1265416')
@test.attr(type='gate')
def test_list_servers_by_admin_with_all_tenants(self):
# Listing servers by admin user with all tenants parameter
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index 43440c1..c2cf7e0 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -29,6 +29,8 @@
def setUpClass(cls):
if not CONF.service_available.neutron:
raise cls.skipException("Neutron is required")
+ if not CONF.compute_feature_enabled.interface_attach:
+ raise cls.skipException("Interface attachment is not available.")
# This test class requires network and subnet
cls.set_network_resources(network=True, subnet=True)
super(AttachInterfacesV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index add69ab..e2b47ee 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -68,6 +68,8 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_server_termination(server['id'])
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
# Delete a server while it's VM state is Shelved
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 3ee8050..4404043 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -394,6 +394,8 @@
self.assertEqual(202, resp.status)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type='gate')
def test_shelve_unshelve_server(self):
resp, server = self.client.shelve_server(self.server_id)
diff --git a/tempest/api/compute/v3/servers/test_server_rescue_negative.py b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
index 5eb6c9a..83fe128 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -33,7 +33,7 @@
raise cls.skipException(msg)
super(ServerRescueNegativeV3Test, cls).setUpClass()
- cls.device = 'vdf'
+ cls.device = CONF.compute.volume_device_name
# Create a volume and wait for it to become ready for attach
resp, cls.volume = cls.volumes_client.create_volume(
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 90deaa9..f8ff7c8 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -397,6 +397,8 @@
self.client.restore_soft_deleted_server,
self.server_id)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_shelve_non_existent_server(self):
# shelve a non existent server
@@ -404,6 +406,8 @@
self.assertRaises(exceptions.NotFound, self.client.shelve_server,
nonexistent_server)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_shelve_shelved_server(self):
# shelve a shelved server.
@@ -431,6 +435,8 @@
self.client.unshelve_server(self.server_id)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_unshelve_non_existent_server(self):
# unshelve a non existent server
@@ -438,6 +444,8 @@
self.assertRaises(exceptions.NotFound, self.client.unshelve_server,
nonexistent_server)
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
@test.attr(type=['negative', 'gate'])
def test_unshelve_server_invalid_state(self):
# unshelve an active server.
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index cfb5a3d..65085b9 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -40,6 +40,7 @@
cls._data_sources = []
cls._job_binary_internals = []
cls._job_binaries = []
+ cls._jobs = []
@classmethod
def tearDownClass(cls):
@@ -47,12 +48,13 @@
cls.client.delete_cluster_template)
cls.cleanup_resources(getattr(cls, '_node_group_templates', []),
cls.client.delete_node_group_template)
- cls.cleanup_resources(getattr(cls, '_data_sources', []),
- cls.client.delete_data_source)
- cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
- cls.client.delete_job_binary_internal)
+ cls.cleanup_resources(getattr(cls, '_jobs', []), cls.client.delete_job)
cls.cleanup_resources(getattr(cls, '_job_binaries', []),
cls.client.delete_job_binary)
+ cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
+ cls.client.delete_job_binary_internal)
+ cls.cleanup_resources(getattr(cls, '_data_sources', []),
+ cls.client.delete_data_source)
cls.clear_isolated_creds()
super(BaseDataProcessingTest, cls).tearDownClass()
@@ -132,6 +134,7 @@
return resp_body
+ @classmethod
def create_job_binary(cls, name, url, extra=None, **kwargs):
"""Creates watched job binary with specified params.
@@ -144,3 +147,18 @@
cls._job_binaries.append(resp_body['id'])
return resp_body
+
+ @classmethod
+ def create_job(cls, name, job_type, mains, libs=None, **kwargs):
+ """Creates watched job with specified params.
+
+ It supports passing additional params using kwargs and returns created
+ object. All resources created in this method will be automatically
+ removed in tearDownClass method.
+ """
+ _, resp_body = cls.client.create_job(name,
+ job_type, mains, libs, **kwargs)
+ # store id of created job
+ cls._jobs.append(resp_body['id'])
+
+ return resp_body
diff --git a/tempest/api/data_processing/test_jobs.py b/tempest/api/data_processing/test_jobs.py
new file mode 100644
index 0000000..8591dbd
--- /dev/null
+++ b/tempest/api/data_processing/test_jobs.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2014 Mirantis Inc.
+#
+# 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.data_processing import base as dp_base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class JobTest(dp_base.BaseDataProcessingTest):
+ """Link to the API documentation is http://docs.openstack.org/developer/
+ sahara/restapi/rest_api_v1.1_EDP.html#jobs
+ """
+ @classmethod
+ @test.safe_setup
+ def setUpClass(cls):
+ super(JobTest, cls).setUpClass()
+ # create job binary
+ job_binary = {
+ 'name': data_utils.rand_name('sahara-job-binary'),
+ 'url': 'swift://sahara-container.sahara/example.jar',
+ 'description': 'Test job binary',
+ 'extra': {
+ 'user': cls.os.credentials.username,
+ 'password': cls.os.credentials.password
+ }
+ }
+ resp_body = cls.create_job_binary(**job_binary)
+ job_binary_id = resp_body['id']
+
+ cls.job = {
+ 'job_type': 'Pig',
+ 'mains': [job_binary_id]
+ }
+
+ def _create_job(self, job_name=None):
+ """Creates Job with optional name specified.
+
+ It creates job and ensures job name. Returns id and name of created
+ job.
+ """
+ if not job_name:
+ # generate random name if it's not specified
+ job_name = data_utils.rand_name('sahara-job')
+
+ # create job
+ resp_body = self.create_job(job_name, **self.job)
+
+ # ensure that job created successfully
+ self.assertEqual(job_name, resp_body['name'])
+
+ return resp_body['id'], job_name
+
+ @test.attr(type='smoke')
+ def test_job_create(self):
+ self._create_job()
+
+ @test.attr(type='smoke')
+ def test_job_list(self):
+ job_info = self._create_job()
+
+ # check for job in list
+ _, jobs = self.client.list_jobs()
+ jobs_info = [(job['id'], job['name']) for job in jobs]
+ self.assertIn(job_info, jobs_info)
+
+ @test.attr(type='smoke')
+ def test_job_get(self):
+ job_id, job_name = self._create_job()
+
+ # check job fetch by id
+ _, job = self.client.get_job(job_id)
+ self.assertEqual(job_name, job['name'])
+
+ @test.attr(type='smoke')
+ def test_job_delete(self):
+ job_id, _ = self._create_job()
+
+ # delete the job by id
+ self.client.delete_job(job_id)
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index 7a6d07f..492d56f 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -49,7 +49,7 @@
@test.attr(type='gate')
def test_list_roles(self):
- # Return a list of all roles
+ """Return a list of all roles."""
_, body = self.client.list_roles()
found = [role for role in body if role in self.data.roles]
self.assertTrue(any(found))
@@ -57,7 +57,7 @@
@test.attr(type='gate')
def test_role_create_delete(self):
- # Role should be created, verified, and deleted
+ """Role should be created, verified, and deleted."""
role_name = data_utils.rand_name(name='role-test-')
_, body = self.client.create_role(role_name)
self.assertEqual(role_name, body['name'])
@@ -74,7 +74,7 @@
@test.attr(type='gate')
def test_get_role_by_id(self):
- # Get a role by its id
+ """Get a role by its id."""
self.data.setup_test_role()
role_id = self.data.role['id']
role_name = self.data.role['name']
@@ -84,7 +84,7 @@
@test.attr(type='gate')
def test_assign_user_role(self):
- # Assign a role to a user on a tenant
+ """Assign a role to a user on a tenant."""
(user, tenant, role) = self._get_role_params()
self.client.assign_user_role(tenant['id'], user['id'], role['id'])
_, roles = self.client.list_user_roles(tenant['id'], user['id'])
@@ -92,7 +92,7 @@
@test.attr(type='gate')
def test_remove_user_role(self):
- # Remove a role assigned to a user on a tenant
+ """Remove a role assigned to a user on a tenant."""
(user, tenant, role) = self._get_role_params()
_, user_role = self.client.assign_user_role(tenant['id'],
user['id'], role['id'])
@@ -101,7 +101,7 @@
@test.attr(type='gate')
def test_list_user_roles(self):
- # List roles assigned to a user on tenant
+ """List roles assigned to a user on tenant."""
(user, tenant, role) = self._get_role_params()
self.client.assign_user_role(tenant['id'], user['id'], role['id'])
_, roles = self.client.list_user_roles(tenant['id'], user['id'])
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
new file mode 100644
index 0000000..a3944e2
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -0,0 +1,73 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class ListProjectsTestJSON(base.BaseIdentityV3AdminTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(ListProjectsTestJSON, cls).setUpClass()
+ cls.project_ids = list()
+ cls.data.setup_test_domain()
+ # Create project with domain
+ cls.p1_name = data_utils.rand_name('project')
+ _, cls.p1 = cls.client.create_project(
+ cls.p1_name, enabled=False, domain_id=cls.data.domain['id'])
+ cls.data.projects.append(cls.p1)
+ cls.project_ids.append(cls.p1['id'])
+ # Create default project
+ p2_name = data_utils.rand_name('project')
+ _, cls.p2 = cls.client.create_project(p2_name)
+ cls.data.projects.append(cls.p2)
+ cls.project_ids.append(cls.p2['id'])
+
+ @test.attr(type='gate')
+ def test_projects_list(self):
+ # List projects
+ resp, list_projects = self.client.list_projects()
+
+ for p in self.project_ids:
+ _, get_project = self.client.get_project(p)
+ self.assertIn(get_project, list_projects)
+
+ @test.attr(type='gate')
+ def test_list_projects_with_domains(self):
+ # List projects with domain
+ self._list_projects_with_params(
+ {'domain_id': self.data.domain['id']}, 'domain_id')
+
+ @test.attr(type='gate')
+ def test_list_projects_with_enabled(self):
+ # List the projects with enabled
+ self._list_projects_with_params({'enabled': False}, 'enabled')
+
+ @test.attr(type='gate')
+ def test_list_projects_with_name(self):
+ # List projects with name
+ self._list_projects_with_params({'name': self.p1_name}, 'name')
+
+ def _list_projects_with_params(self, params, key):
+ resp, body = self.client.list_projects(params)
+ self.assertIn(self.p1[key], map(lambda x: x[key], body))
+ self.assertNotIn(self.p2[key], map(lambda x: x[key], body))
+
+
+class ListProjectsTestXML(ListProjectsTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 77acd57..5890eab 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,35 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
-from six import moves
-
from tempest.api.identity import base
from tempest.common.utils import data_utils
-from tempest import exceptions
from tempest import test
class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
_interface = 'json'
- def _delete_project(self, project_id):
- self.client.delete_project(project_id)
- self.assertRaises(
- exceptions.NotFound, self.client.get_project, project_id)
-
- @test.attr(type='gate')
- def test_project_list_delete(self):
- # Create several projects and delete them
- for _ in moves.xrange(3):
- _, project = self.client.create_project(
- data_utils.rand_name('project-new'))
- self.addCleanup(self._delete_project, project['id'])
-
- _, list_projects = self.client.list_projects()
-
- _, get_project = self.client.get_project(project['id'])
- self.assertIn(get_project, list_projects)
-
@test.attr(type='gate')
def test_project_create_with_description(self):
# Create project with a description
@@ -60,6 +39,21 @@
'to be set')
@test.attr(type='gate')
+ def test_project_create_with_domain(self):
+ # Create project with a domain
+ self.data.setup_test_domain()
+ project_name = data_utils.rand_name('project')
+ resp, project = self.client.create_project(
+ project_name, domain_id=self.data.domain['id'])
+ self.data.projects.append(project)
+ project_id = project['id']
+ self.assertEqual(project_name, project['name'])
+ self.assertEqual(self.data.domain['id'], project['domain_id'])
+ _, body = self.client.get_project(project_id)
+ self.assertEqual(project_name, body['name'])
+ self.assertEqual(self.data.domain['id'], body['domain_id'])
+
+ @test.attr(type='gate')
def test_project_create_enabled(self):
# Create a project that is enabled
project_name = data_utils.rand_name('project-')
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index e61b738..bd08614 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -48,6 +48,7 @@
self.assertRaises(exceptions.NotFound, self.client.get_token,
subject_token)
+ @test.skip_because(bug="1351026")
@test.attr(type='gate')
def test_rescope_token(self):
"""Rescope a token.
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 02d391b..c875b2f 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -100,7 +100,7 @@
cls.alt_tenant_id = cls.alt_img_cli.tenant_id
def _create_image(self):
- image_file = StringIO.StringIO('*' * 1024)
+ image_file = StringIO.StringIO(data_utils.random_bytes())
resp, image = self.create_image(container_format='bare',
disk_format='raw',
is_public=False,
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 8528e42..bf55b89 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -44,7 +44,7 @@
self.assertEqual(val, body.get('properties')[key])
# Now try uploading an image file
- image_file = StringIO.StringIO(('*' * 1024))
+ image_file = StringIO.StringIO(data_utils.random_bytes())
_, body = self.client.update_image(image_id, data=image_file)
self.assertIn('size', body)
self.assertEqual(1024, body.get('size'))
@@ -157,7 +157,7 @@
image. Note that the size of the new image is a random number between
1024 and 4096
"""
- image_file = StringIO.StringIO('*' * size)
+ image_file = StringIO.StringIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
_, image = cls.create_image(name=name,
container_format=container_format,
@@ -338,10 +338,9 @@
disk_format, size):
"""
Create a new standard image and return the ID of the newly-registered
- image. Note that the size of the new image is a random number between
- 1024 and 4096
+ image.
"""
- image_file = StringIO.StringIO('*' * size)
+ image_file = StringIO.StringIO(data_utils.random_bytes(size))
name = 'New Standard Image %s' % name
_, image = cls.create_image(name=name,
container_format=container_format,
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 4226815..a974ebb 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -52,7 +52,7 @@
self.assertEqual('queued', body['status'])
# Now try uploading an image file
- file_content = '*' * 1024
+ file_content = data_utils.random_bytes()
image_file = StringIO.StringIO(file_content)
self.client.store_image(image_id, image_file)
@@ -104,8 +104,7 @@
image_id = body['id']
# Now try uploading an image file
- file_content = '*' * 1024
- image_file = StringIO.StringIO(file_content)
+ image_file = StringIO.StringIO(data_utils.random_bytes())
self.client.store_image(image_id, image_file)
# Update Image
@@ -146,7 +145,8 @@
image. Note that the size of the new image is a random number between
1024 and 4096
"""
- image_file = StringIO.StringIO('*' * random.randint(1024, 4096))
+ size = random.randint(1024, 4096)
+ image_file = StringIO.StringIO(data_utils.random_bytes(size))
name = data_utils.rand_name('image-')
_, body = cls.create_image(name=name,
container_format=container_format,
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 087b87a..d75339c 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -85,57 +85,58 @@
@classmethod
def tearDownClass(cls):
- # Clean up ipsec policies
- for ipsecpolicy in cls.ipsecpolicies:
- cls.client.delete_ipsecpolicy(ipsecpolicy['id'])
- # Clean up firewall policies
- for fw_policy in cls.fw_policies:
- cls.client.delete_firewall_policy(fw_policy['id'])
- # Clean up firewall rules
- for fw_rule in cls.fw_rules:
- cls.client.delete_firewall_rule(fw_rule['id'])
- # Clean up ike policies
- for ikepolicy in cls.ikepolicies:
- cls.client.delete_ikepolicy(ikepolicy['id'])
- # Clean up vpn services
- for vpnservice in cls.vpnservices:
- cls.client.delete_vpnservice(vpnservice['id'])
- # Clean up floating IPs
- for floating_ip in cls.floating_ips:
- cls.client.delete_floatingip(floating_ip['id'])
- # Clean up routers
- for router in cls.routers:
- cls.delete_router(router)
+ if CONF.service_available.neutron:
+ # Clean up ipsec policies
+ for ipsecpolicy in cls.ipsecpolicies:
+ cls.client.delete_ipsecpolicy(ipsecpolicy['id'])
+ # Clean up firewall policies
+ for fw_policy in cls.fw_policies:
+ cls.client.delete_firewall_policy(fw_policy['id'])
+ # Clean up firewall rules
+ for fw_rule in cls.fw_rules:
+ cls.client.delete_firewall_rule(fw_rule['id'])
+ # Clean up ike policies
+ for ikepolicy in cls.ikepolicies:
+ cls.client.delete_ikepolicy(ikepolicy['id'])
+ # Clean up vpn services
+ for vpnservice in cls.vpnservices:
+ cls.client.delete_vpnservice(vpnservice['id'])
+ # Clean up floating IPs
+ for floating_ip in cls.floating_ips:
+ cls.client.delete_floatingip(floating_ip['id'])
+ # Clean up routers
+ for router in cls.routers:
+ cls.delete_router(router)
- # Clean up health monitors
- for health_monitor in cls.health_monitors:
- cls.client.delete_health_monitor(health_monitor['id'])
- # Clean up members
- for member in cls.members:
- cls.client.delete_member(member['id'])
- # Clean up vips
- for vip in cls.vips:
- cls.client.delete_vip(vip['id'])
- # Clean up pools
- for pool in cls.pools:
- cls.client.delete_pool(pool['id'])
- # Clean up metering label rules
- for metering_label_rule in cls.metering_label_rules:
- cls.admin_client.delete_metering_label_rule(
- metering_label_rule['id'])
- # Clean up metering labels
- for metering_label in cls.metering_labels:
- cls.admin_client.delete_metering_label(metering_label['id'])
- # Clean up ports
- for port in cls.ports:
- cls.client.delete_port(port['id'])
- # Clean up subnets
- for subnet in cls.subnets:
- cls.client.delete_subnet(subnet['id'])
- # Clean up networks
- for network in cls.networks:
- cls.client.delete_network(network['id'])
- cls.clear_isolated_creds()
+ # Clean up health monitors
+ for health_monitor in cls.health_monitors:
+ cls.client.delete_health_monitor(health_monitor['id'])
+ # Clean up members
+ for member in cls.members:
+ cls.client.delete_member(member['id'])
+ # Clean up vips
+ for vip in cls.vips:
+ cls.client.delete_vip(vip['id'])
+ # Clean up pools
+ for pool in cls.pools:
+ cls.client.delete_pool(pool['id'])
+ # Clean up metering label rules
+ for metering_label_rule in cls.metering_label_rules:
+ cls.admin_client.delete_metering_label_rule(
+ metering_label_rule['id'])
+ # Clean up metering labels
+ for metering_label in cls.metering_labels:
+ cls.admin_client.delete_metering_label(metering_label['id'])
+ # Clean up ports
+ for port in cls.ports:
+ cls.client.delete_port(port['id'])
+ # Clean up subnets
+ for subnet in cls.subnets:
+ cls.client.delete_subnet(subnet['id'])
+ # Clean up networks
+ for network in cls.networks:
+ cls.client.delete_network(network['id'])
+ cls.clear_isolated_creds()
super(BaseNetworkTest, cls).tearDownClass()
@classmethod
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d38633f..dca4c17 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -110,6 +110,36 @@
create_body['router']['id'])
self.assertEqual(tenant_id, create_body['router']['tenant_id'])
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @test.attr(type='smoke')
+ def test_create_router_with_default_snat_value(self):
+ # Create a router with default snat rule
+ name = data_utils.rand_name('router')
+ router = self._create_router(name,
+ external_network_id=CONF.network.public_network_id)
+ self._verify_router_gateway(router['id'],
+ {'network_id': CONF.network.public_network_id,
+ 'enable_snat': True})
+
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @test.attr(type='smoke')
+ def test_create_router_with_snat_explicit(self):
+ name = data_utils.rand_name('snat-router')
+ # Create a router enabling snat attributes
+ enable_snat_states = [False, True]
+ for enable_snat in enable_snat_states:
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': enable_snat}
+ resp, create_body = self.admin_client.create_router(
+ name, external_gateway_info=external_gateway_info)
+ self.assertEqual('201', resp['status'])
+ self.addCleanup(self.admin_client.delete_router,
+ create_body['router']['id'])
+ # Verify snat attributes after router creation
+ self._verify_router_gateway(create_body['router']['id'],
+ exp_ext_gw_info=external_gateway_info)
+
@test.attr(type='smoke')
def test_add_remove_router_interface_with_subnet_id(self):
network = self.create_network()
@@ -151,7 +181,7 @@
router['id'])
def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
- resp, show_body = self.client.show_router(router_id)
+ resp, show_body = self.admin_client.show_router(router_id)
self.assertEqual('200', resp['status'])
actual_ext_gw_info = show_body['router']['external_gateway_info']
if exp_ext_gw_info is None:
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 1ef9aa1..b21aa44 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -17,7 +17,7 @@
import hashlib
import random
import re
-from six import moves
+import six
import time
import zlib
@@ -54,15 +54,36 @@
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
- data_segments = [data + str(i) for i in moves.xrange(segments)]
+ data_segments = [data + str(i) for i in six.moves.xrange(segments)]
# uploading segments
- for i in moves.xrange(segments):
+ for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
self.assertEqual(resp['status'], '201')
return object_name, data_segments
+ def _copy_object_2d(self, src_object_name, metadata=None):
+ dst_object_name = data_utils.rand_name(name='TestObject')
+ resp, _ = self.object_client.copy_object_2d_way(self.container_name,
+ src_object_name,
+ dst_object_name,
+ metadata=metadata)
+ return dst_object_name, resp
+
+ def _check_copied_obj(self, dst_object_name, src_body,
+ in_meta=None, not_in_meta=None):
+ resp, dest_body = self.object_client.get_object(self.container_name,
+ dst_object_name)
+
+ self.assertEqual(src_body, dest_body)
+ if in_meta:
+ for meta_key in in_meta:
+ self.assertIn('x-object-meta-' + meta_key, resp)
+ if not_in_meta:
+ for meta_key in not_in_meta:
+ self.assertNotIn('x-object-meta-' + meta_key, resp)
+
@test.attr(type='gate')
def test_create_object(self):
# create object
@@ -765,10 +786,7 @@
# change the content type of an existing object
# create object
- object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
- self.object_client.create_object(self.container_name,
- object_name, data)
+ object_name, data = self._create_object()
# get the old content type
resp_tmp, _ = self.object_client.list_object_metadata(
self.container_name, object_name)
@@ -805,20 +823,12 @@
dst_object_name)
self.assertEqual(resp['status'], '201')
self.assertHeaders(resp, 'Object', 'COPY')
-
- self.assertIn('last-modified', resp)
- self.assertIn('x-copied-from', resp)
- self.assertIn('x-copied-from-last-modified', resp)
- self.assertNotEqual(len(resp['last-modified']), 0)
self.assertEqual(
resp['x-copied-from'],
self.container_name + "/" + src_object_name)
- self.assertNotEqual(len(resp['x-copied-from-last-modified']), 0)
# check data
- resp, body = self.object_client.get_object(self.container_name,
- dst_object_name)
- self.assertEqual(body, src_data)
+ self._check_copied_obj(dst_object_name, src_data)
@test.attr(type='smoke')
def test_copy_object_across_containers(self):
@@ -862,15 +872,82 @@
self.assertIn(actual_meta_key, resp)
self.assertEqual(resp[actual_meta_key], meta_value)
+ @test.attr(type='smoke')
+ def test_copy_object_with_x_fresh_metadata(self):
+ # create source object
+ metadata = {'x-object-meta-src': 'src_value'}
+ src_object_name, data = self._create_object(metadata)
+
+ # copy source object with x_fresh_metadata header
+ metadata = {'X-Fresh-Metadata': 'true'}
+ dst_object_name, resp = self._copy_object_2d(src_object_name,
+ metadata)
+
+ self.assertEqual(resp['status'], '201')
+ self.assertHeaders(resp, 'Object', 'COPY')
+
+ self.assertNotIn('x-object-meta-src', resp)
+ self.assertEqual(resp['x-copied-from'],
+ self.container_name + "/" + src_object_name)
+
+ # check that destination object does NOT have any object-meta
+ self._check_copied_obj(dst_object_name, data, not_in_meta=["src"])
+
+ @test.attr(type='smoke')
+ def test_copy_object_with_x_object_metakey(self):
+ # create source object
+ metadata = {'x-object-meta-src': 'src_value'}
+ src_obj_name, data = self._create_object(metadata)
+
+ # copy source object to destination with x-object-meta-key
+ metadata = {'x-object-meta-test': ''}
+ dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
+
+ self.assertEqual(resp['status'], '201')
+ self.assertHeaders(resp, 'Object', 'COPY')
+
+ expected = {'x-object-meta-test': '',
+ 'x-object-meta-src': 'src_value',
+ 'x-copied-from': self.container_name + "/" + src_obj_name}
+ for key, value in six.iteritems(expected):
+ self.assertIn(key, resp)
+ self.assertEqual(value, resp[key])
+
+ # check destination object
+ self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
+
+ @test.attr(type='smoke')
+ def test_copy_object_with_x_object_meta(self):
+ # create source object
+ metadata = {'x-object-meta-src': 'src_value'}
+ src_obj_name, data = self._create_object(metadata)
+
+ # copy source object to destination with object metadata
+ metadata = {'x-object-meta-test': 'value'}
+ dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
+
+ self.assertEqual(resp['status'], '201')
+ self.assertHeaders(resp, 'Object', 'COPY')
+
+ expected = {'x-object-meta-test': 'value',
+ 'x-object-meta-src': 'src_value',
+ 'x-copied-from': self.container_name + "/" + src_obj_name}
+ for key, value in six.iteritems(expected):
+ self.assertIn(key, resp)
+ self.assertEqual(value, resp[key])
+
+ # check destination object
+ self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"])
+
@test.attr(type='gate')
def test_object_upload_in_segments(self):
# create object
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
- data_segments = [data + str(i) for i in moves.xrange(segments)]
+ data_segments = [data + str(i) for i in six.moves.xrange(segments)]
# uploading segments
- for i in moves.xrange(segments):
+ for i in six.moves.xrange(segments):
resp, _ = self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
self.assertEqual(resp['status'], '201')
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index e22a08b..e3ffdaf 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -48,7 +48,7 @@
for resource in resources:
cls.test_resources[resource['logical_resource_id']] = resource
- @test.attr(type='slow')
+ @test.attr(type='gate')
def test_created_resources(self):
"""Verifies created keypair resource."""
@@ -68,7 +68,7 @@
self.assertEqual(resource_type, resource['resource_type'])
self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
- @test.attr(type='slow')
+ @test.attr(type='gate')
def test_stack_keypairs_output(self):
resp, stack = self.client.get_stack(self.stack_name)
self.assertEqual('200', resp['status'])
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index 5b45d82..d5e66e8 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -64,3 +64,4 @@
# delete the stack
resp = self.client.delete_stack(stack_identifier)
self.assertEqual('204', resp[0]['status'])
+ self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 2a170c7..9b15c51 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -47,6 +47,7 @@
@test.services("image")
@testtools.skipIf(not CONF.image_feature_enabled.api_v1,
"Glance api v1 is disabled")
+ @test.skip_because(bug='1351627')
def test_check_glance_v1_notifications(self):
_, body = self.create_image(self.image_client)
self.image_client.update_image(body['id'], data='data')
@@ -62,6 +63,7 @@
@test.services("image")
@testtools.skipIf(not CONF.image_feature_enabled.api_v2,
"Glance api v2 is disabled")
+ @test.skip_because(bug='1351627')
def test_check_glance_v2_notifications(self):
_, body = self.create_image(self.image_client_v2)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c5be1f3..b7de767 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -61,12 +61,23 @@
cls.volumes_extension_client = cls.os.volumes_extension_client
cls.availability_zone_client = (
cls.os.volume_availability_zone_client)
+ # Special fields and resp code for cinder v1
+ cls.special_fields = {'name_field': 'display_name',
+ 'descrip_field': 'display_description',
+ 'create_resp': 200}
elif cls._api_version == 2:
if not CONF.volume_feature_enabled.api_v2:
msg = "Volume API v2 is disabled"
raise cls.skipException(msg)
cls.volumes_client = cls.os.volumes_v2_client
+ cls.volumes_extension_client = cls.os.volumes_v2_extension_client
+ cls.availability_zone_client = (
+ cls.os.volume_v2_availability_zone_client)
+ # Special fields and resp code for cinder v2
+ cls.special_fields = {'name_field': 'name',
+ 'descrip_field': 'description',
+ 'create_resp': 202}
else:
msg = ("Invalid Cinder API version (%s)" % cls._api_version)
@@ -82,15 +93,15 @@
@classmethod
def create_volume(cls, size=1, **kwargs):
"""Wrapper utility that returns a test volume."""
- vol_name = data_utils.rand_name('Volume')
- if cls._api_version == 1:
- resp, volume = cls.volumes_client.create_volume(
- size, display_name=vol_name, **kwargs)
- assert 200 == resp.status
- elif cls._api_version == 2:
- resp, volume = cls.volumes_client.create_volume(
- size, name=vol_name, **kwargs)
- assert 202 == resp.status
+ name = data_utils.rand_name('Volume')
+
+ name_field = cls.special_fields['name_field']
+ expect_status = cls.special_fields['create_resp']
+
+ kwargs[name_field] = name
+ resp, volume = cls.volumes_client.create_volume(size, **kwargs)
+ assert expect_status == resp.status
+
cls.volumes.append(volume)
cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
return volume
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index fe8f96e..25b7b85 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -17,16 +17,15 @@
from tempest import test
-class AvailabilityZoneTestJSON(base.BaseVolumeV1Test):
+class AvailabilityZoneV2TestJSON(base.BaseVolumeTest):
"""
- Tests Availability Zone API List
+ Tests Availability Zone V2 API List
"""
- _interface = 'json'
@classmethod
def setUpClass(cls):
- super(AvailabilityZoneTestJSON, cls).setUpClass()
+ super(AvailabilityZoneV2TestJSON, cls).setUpClass()
cls.client = cls.availability_zone_client
@test.attr(type='gate')
@@ -37,5 +36,13 @@
self.assertTrue(len(availability_zone) > 0)
-class AvailabilityZoneTestXML(AvailabilityZoneTestJSON):
+class AvailabilityZoneV2TestXML(AvailabilityZoneV2TestJSON):
+ _interface = 'xml'
+
+
+class AvailabilityZoneV1TestJSON(AvailabilityZoneV2TestJSON):
+ _api_version = 1
+
+
+class AvailabilityZoneV1TestXML(AvailabilityZoneV1TestJSON):
_interface = 'xml'
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index ce019a2..ff00dd1 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -25,8 +25,7 @@
LOG = logging.getLogger(__name__)
-class ExtensionsTestJSON(base.BaseVolumeV1Test):
- _interface = 'json'
+class ExtensionsV2TestJSON(base.BaseVolumeTest):
@test.attr(type='gate')
def test_list_extensions(self):
@@ -46,5 +45,13 @@
raise self.skipException('There are not any extensions configured')
-class ExtensionsTestXML(ExtensionsTestJSON):
+class ExtensionsV2TestXML(ExtensionsV2TestJSON):
+ _interface = 'xml'
+
+
+class ExtensionsV1TestJSON(ExtensionsV2TestJSON):
+ _api_version = 1
+
+
+class ExtensionsV1TestXML(ExtensionsV1TestJSON):
_interface = 'xml'
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index 0d57d47..0505f19 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -19,13 +19,12 @@
from tempest import test
-class VolumeMetadataTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2MetadataTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumeMetadataTest, cls).setUpClass()
+ super(VolumesV2MetadataTest, cls).setUpClass()
# Create a volume
cls.volume = cls.create_volume()
cls.volume_id = cls.volume['id']
@@ -33,7 +32,7 @@
def tearDown(self):
# Update the metadata to {}
self.volumes_client.update_volume_metadata(self.volume_id, {})
- super(VolumeMetadataTest, self).tearDown()
+ super(VolumesV2MetadataTest, self).tearDown()
@test.attr(type='gate')
def test_create_get_delete_volume_metadata(self):
@@ -117,5 +116,13 @@
self.assertThat(body.items(), matchers.ContainsAll(expect.items()))
-class VolumeMetadataTestXML(VolumeMetadataTest):
+class VolumesV2MetadataTestXML(VolumesV2MetadataTest):
+ _interface = "xml"
+
+
+class VolumesV1MetadataTest(VolumesV2MetadataTest):
+ _api_version = 1
+
+
+class VolumesV1MetadataTestXML(VolumesV1MetadataTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 82d1364..bf61222 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -23,12 +23,11 @@
CONF = config.CONF
-class VolumesTransfersTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2TransfersTest(base.BaseVolumeTest):
@classmethod
def setUpClass(cls):
- super(VolumesTransfersTest, cls).setUpClass()
+ super(VolumesV2TransfersTest, cls).setUpClass()
# Add another tenant to test volume-transfer
if CONF.compute.allow_tenant_isolation:
@@ -110,5 +109,13 @@
self.client.wait_for_volume_status(volume['id'], 'available')
-class VolumesTransfersTestXML(VolumesTransfersTest):
+class VolumesV2TransfersTestXML(VolumesV2TransfersTest):
+ _interface = "xml"
+
+
+class VolumesV1TransfersTest(VolumesV2TransfersTest):
+ _api_version = 1
+
+
+class VolumesV1TransfersTestXML(VolumesV1TransfersTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index cfab0bd..6fef564 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -21,13 +21,12 @@
CONF = config.CONF
-class VolumesActionsTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2ActionsTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumesActionsTest, cls).setUpClass()
+ super(VolumesV2ActionsTest, cls).setUpClass()
cls.client = cls.volumes_client
cls.image_client = cls.os.image_client
@@ -47,7 +46,7 @@
cls.servers_client.delete_server(cls.server['id'])
cls.servers_client.wait_for_server_termination(cls.server['id'])
- super(VolumesActionsTest, cls).tearDownClass()
+ super(VolumesV2ActionsTest, cls).tearDownClass()
@test.stresstest(class_setup_per='process')
@test.attr(type='smoke')
@@ -165,5 +164,13 @@
self.assertEqual(False, bool_flag)
-class VolumesActionsTestXML(VolumesActionsTest):
+class VolumesV2ActionsTestXML(VolumesV2ActionsTest):
+ _interface = "xml"
+
+
+class VolumesV1ActionsTest(VolumesV2ActionsTest):
+ _api_version = 1
+
+
+class VolumesV1ActionsTestXML(VolumesV1ActionsTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 2745b95..82208aa 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -23,14 +23,17 @@
CONF = config.CONF
-class VolumesGetTest(base.BaseVolumeV1Test):
- _interface = "json"
+class VolumesV2GetTest(base.BaseVolumeTest):
@classmethod
def setUpClass(cls):
- super(VolumesGetTest, cls).setUpClass()
+ super(VolumesV2GetTest, cls).setUpClass()
cls.client = cls.volumes_client
+ cls.name_field = cls.special_fields['name_field']
+ cls.descrip_field = cls.special_fields['descrip_field']
+ cls.create_resp = cls.special_fields['create_resp']
+
def _delete_volume(self, volume_id):
resp, _ = self.client.delete_volume(volume_id)
self.assertEqual(202, resp.status)
@@ -51,24 +54,24 @@
v_name = data_utils.rand_name('Volume')
metadata = {'Type': 'Test'}
# Create a volume
- resp, volume = self.client.create_volume(display_name=v_name,
- metadata=metadata,
- **kwargs)
- self.assertEqual(200, resp.status)
+ kwargs[self.name_field] = v_name
+ kwargs['metadata'] = metadata
+ resp, volume = self.client.create_volume(**kwargs)
+ self.assertEqual(self.create_resp, resp.status)
self.assertIn('id', volume)
self.addCleanup(self._delete_volume, volume['id'])
- self.assertIn('display_name', volume)
- self.assertEqual(volume['display_name'], v_name,
+ self.client.wait_for_volume_status(volume['id'], 'available')
+ self.assertIn(self.name_field, volume)
+ self.assertEqual(volume[self.name_field], v_name,
"The created volume name is not equal "
"to the requested name")
self.assertTrue(volume['id'] is not None,
"Field volume id is empty or not found.")
- self.client.wait_for_volume_status(volume['id'], 'available')
# Get Volume information
resp, fetched_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(v_name,
- fetched_volume['display_name'],
+ fetched_volume[self.name_field],
'The fetched Volume name is different '
'from the created Volume')
self.assertEqual(volume['id'],
@@ -90,27 +93,25 @@
# Update Volume
# Test volume update when display_name is same with original value
- resp, update_volume = \
- self.client.update_volume(volume['id'],
- display_name=v_name)
+ params = {self.name_field: v_name}
+ resp, update_volume = self.client.update_volume(volume['id'], **params)
self.assertEqual(200, resp.status)
# Test volume update when display_name is new
new_v_name = data_utils.rand_name('new-Volume')
new_desc = 'This is the new description of volume'
- resp, update_volume = \
- self.client.update_volume(volume['id'],
- display_name=new_v_name,
- display_description=new_desc)
+ params = {self.name_field: new_v_name,
+ self.descrip_field: new_desc}
+ resp, update_volume = self.client.update_volume(volume['id'], **params)
# Assert response body for update_volume method
self.assertEqual(200, resp.status)
- self.assertEqual(new_v_name, update_volume['display_name'])
- self.assertEqual(new_desc, update_volume['display_description'])
+ self.assertEqual(new_v_name, update_volume[self.name_field])
+ self.assertEqual(new_desc, update_volume[self.descrip_field])
# Assert response body for get_volume method
resp, updated_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(volume['id'], updated_volume['id'])
- self.assertEqual(new_v_name, updated_volume['display_name'])
- self.assertEqual(new_desc, updated_volume['display_description'])
+ self.assertEqual(new_v_name, updated_volume[self.name_field])
+ self.assertEqual(new_desc, updated_volume[self.descrip_field])
self.assertThat(updated_volume['metadata'].items(),
matchers.ContainsAll(metadata.items()),
'The fetched Volume metadata misses data '
@@ -120,20 +121,18 @@
# then test volume update if display_name is duplicated
new_volume = {}
new_v_desc = data_utils.rand_name('@#$%^* description')
- resp, new_volume = \
- self.client.create_volume(
- size=1,
- display_description=new_v_desc,
- availability_zone=volume['availability_zone'])
- self.assertEqual(200, resp.status)
+ params = {self.descrip_field: new_v_desc,
+ 'availability_zone': volume['availability_zone']}
+ resp, new_volume = self.client.create_volume(size=1, **params)
+ self.assertEqual(self.create_resp, resp.status)
self.assertIn('id', new_volume)
self.addCleanup(self._delete_volume, new_volume['id'])
self.client.wait_for_volume_status(new_volume['id'], 'available')
- resp, update_volume = \
- self.client.update_volume(
- new_volume['id'],
- display_name=volume['display_name'],
- display_description=volume['display_description'])
+
+ params = {self.name_field: volume[self.name_field],
+ self.descrip_field: volume[self.descrip_field]}
+ resp, update_volume = self.client.update_volume(new_volume['id'],
+ **params)
self.assertEqual(200, resp.status)
# NOTE(jdg): Revert back to strict true/false checking
@@ -159,5 +158,13 @@
self._volume_create_get_update_delete(source_volid=origin['id'])
-class VolumesGetTestXML(VolumesGetTest):
+class VolumesV2GetTestXML(VolumesV2GetTest):
+ _interface = "xml"
+
+
+class VolumesV1GetTest(VolumesV2GetTest):
+ _api_version = 1
+
+
+class VolumesV1GetTestXML(VolumesV1GetTest):
_interface = "xml"
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index bc5b1dc..8bd4c88 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -21,15 +21,16 @@
from tempest import test
-class VolumesNegativeTest(base.BaseVolumeV1Test):
- _interface = 'json'
+class VolumesV2NegativeTest(base.BaseVolumeTest):
@classmethod
@test.safe_setup
def setUpClass(cls):
- super(VolumesNegativeTest, cls).setUpClass()
+ super(VolumesV2NegativeTest, cls).setUpClass()
cls.client = cls.volumes_client
+ cls.name_field = cls.special_fields['name_field']
+
# Create a test shared instance and volume for attach/detach tests
cls.volume = cls.create_volume()
cls.mountpoint = "/dev/vdc"
@@ -237,7 +238,7 @@
@test.attr(type=['negative', 'gate'])
def test_list_volumes_with_nonexistent_name(self):
v_name = data_utils.rand_name('Volume-')
- params = {'display_name': v_name}
+ params = {self.name_field: v_name}
resp, fetched_volume = self.client.list_volumes(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
@@ -245,7 +246,7 @@
@test.attr(type=['negative', 'gate'])
def test_list_volumes_detail_with_nonexistent_name(self):
v_name = data_utils.rand_name('Volume-')
- params = {'display_name': v_name}
+ params = {self.name_field: v_name}
resp, fetched_volume = self.client.list_volumes_with_detail(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
@@ -265,5 +266,14 @@
self.assertEqual(0, len(fetched_volume))
-class VolumesNegativeTestXML(VolumesNegativeTest):
+class VolumesV2NegativeTestXML(VolumesV2NegativeTest):
+ _interface = 'xml'
+
+
+class VolumesV1NegativeTest(VolumesV2NegativeTest):
+ _api_version = 1
+ _name = 'display_name'
+
+
+class VolumesV1NegativeTestXML(VolumesV1NegativeTest):
_interface = 'xml'
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api_schema/response/__init__.py
similarity index 100%
copy from tempest/api_schema/compute/__init__.py
copy to tempest/api_schema/response/__init__.py
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api_schema/response/compute/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/__init__.py
rename to tempest/api_schema/response/compute/__init__.py
diff --git a/tempest/api_schema/compute/agents.py b/tempest/api_schema/response/compute/agents.py
similarity index 100%
rename from tempest/api_schema/compute/agents.py
rename to tempest/api_schema/response/compute/agents.py
diff --git a/tempest/api_schema/compute/aggregates.py b/tempest/api_schema/response/compute/aggregates.py
similarity index 100%
rename from tempest/api_schema/compute/aggregates.py
rename to tempest/api_schema/response/compute/aggregates.py
diff --git a/tempest/api_schema/compute/availability_zone.py b/tempest/api_schema/response/compute/availability_zone.py
similarity index 100%
rename from tempest/api_schema/compute/availability_zone.py
rename to tempest/api_schema/response/compute/availability_zone.py
diff --git a/tempest/api_schema/compute/certificates.py b/tempest/api_schema/response/compute/certificates.py
similarity index 100%
rename from tempest/api_schema/compute/certificates.py
rename to tempest/api_schema/response/compute/certificates.py
diff --git a/tempest/api_schema/compute/flavors.py b/tempest/api_schema/response/compute/flavors.py
similarity index 96%
rename from tempest/api_schema/compute/flavors.py
rename to tempest/api_schema/response/compute/flavors.py
index aa019e4..44020d2 100644
--- a/tempest/api_schema/compute/flavors.py
+++ b/tempest/api_schema/response/compute/flavors.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
list_flavors = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/flavors_access.py b/tempest/api_schema/response/compute/flavors_access.py
similarity index 100%
rename from tempest/api_schema/compute/flavors_access.py
rename to tempest/api_schema/response/compute/flavors_access.py
diff --git a/tempest/api_schema/compute/flavors_extra_specs.py b/tempest/api_schema/response/compute/flavors_extra_specs.py
similarity index 100%
rename from tempest/api_schema/compute/flavors_extra_specs.py
rename to tempest/api_schema/response/compute/flavors_extra_specs.py
diff --git a/tempest/api_schema/compute/hosts.py b/tempest/api_schema/response/compute/hosts.py
similarity index 100%
rename from tempest/api_schema/compute/hosts.py
rename to tempest/api_schema/response/compute/hosts.py
diff --git a/tempest/api_schema/compute/hypervisors.py b/tempest/api_schema/response/compute/hypervisors.py
similarity index 100%
rename from tempest/api_schema/compute/hypervisors.py
rename to tempest/api_schema/response/compute/hypervisors.py
diff --git a/tempest/api_schema/compute/interfaces.py b/tempest/api_schema/response/compute/interfaces.py
similarity index 95%
rename from tempest/api_schema/compute/interfaces.py
rename to tempest/api_schema/response/compute/interfaces.py
index 79a8f42..fd53eb3 100644
--- a/tempest/api_schema/compute/interfaces.py
+++ b/tempest/api_schema/response/compute/interfaces.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
delete_interface = {
'status_code': [202]
diff --git a/tempest/api_schema/compute/keypairs.py b/tempest/api_schema/response/compute/keypairs.py
similarity index 100%
rename from tempest/api_schema/compute/keypairs.py
rename to tempest/api_schema/response/compute/keypairs.py
diff --git a/tempest/api_schema/compute/migrations.py b/tempest/api_schema/response/compute/migrations.py
similarity index 100%
rename from tempest/api_schema/compute/migrations.py
rename to tempest/api_schema/response/compute/migrations.py
diff --git a/tempest/api_schema/compute/parameter_types.py b/tempest/api_schema/response/compute/parameter_types.py
similarity index 100%
rename from tempest/api_schema/compute/parameter_types.py
rename to tempest/api_schema/response/compute/parameter_types.py
diff --git a/tempest/api_schema/compute/quotas.py b/tempest/api_schema/response/compute/quotas.py
similarity index 100%
rename from tempest/api_schema/compute/quotas.py
rename to tempest/api_schema/response/compute/quotas.py
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/response/compute/servers.py
similarity index 98%
rename from tempest/api_schema/compute/servers.py
rename to tempest/api_schema/response/compute/servers.py
index a16e425..d6c2ddb 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/response/compute/servers.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
get_password = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/services.py b/tempest/api_schema/response/compute/services.py
similarity index 100%
rename from tempest/api_schema/compute/services.py
rename to tempest/api_schema/response/compute/services.py
diff --git a/tempest/api_schema/compute/v2/__init__.py b/tempest/api_schema/response/compute/v2/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/v2/__init__.py
rename to tempest/api_schema/response/compute/v2/__init__.py
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/api_schema/response/compute/v2/agents.py
similarity index 93%
rename from tempest/api_schema/compute/v2/agents.py
rename to tempest/api_schema/response/compute/v2/agents.py
index 30f999f..d827377 100644
--- a/tempest/api_schema/compute/v2/agents.py
+++ b/tempest/api_schema/response/compute/v2/agents.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import agents
+from tempest.api_schema.response.compute import agents
create_agent = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/aggregates.py b/tempest/api_schema/response/compute/v2/aggregates.py
similarity index 93%
rename from tempest/api_schema/compute/v2/aggregates.py
rename to tempest/api_schema/response/compute/v2/aggregates.py
index bc36044..d87e4de 100644
--- a/tempest/api_schema/compute/v2/aggregates.py
+++ b/tempest/api_schema/response/compute/v2/aggregates.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import aggregates
+from tempest.api_schema.response.compute import aggregates
delete_aggregate = {
'status_code': [200]
diff --git a/tempest/api_schema/compute/v2/availability_zone.py b/tempest/api_schema/response/compute/v2/availability_zone.py
similarity index 95%
rename from tempest/api_schema/compute/v2/availability_zone.py
rename to tempest/api_schema/response/compute/v2/availability_zone.py
index d3d2787..e261d3d 100644
--- a/tempest/api_schema/compute/v2/availability_zone.py
+++ b/tempest/api_schema/response/compute/v2/availability_zone.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import availability_zone as common
+from tempest.api_schema.response.compute import availability_zone as common
base = {
diff --git a/tempest/api_schema/compute/v2/certificates.py b/tempest/api_schema/response/compute/v2/certificates.py
similarity index 91%
rename from tempest/api_schema/compute/v2/certificates.py
rename to tempest/api_schema/response/compute/v2/certificates.py
index 1eb38ce..bda6075 100644
--- a/tempest/api_schema/compute/v2/certificates.py
+++ b/tempest/api_schema/response/compute/v2/certificates.py
@@ -14,6 +14,6 @@
import copy
-from tempest.api_schema.compute import certificates
+from tempest.api_schema.response.compute import certificates
create_certificate = copy.deepcopy(certificates._common_schema)
diff --git a/tempest/api_schema/compute/v2/extensions.py b/tempest/api_schema/response/compute/v2/extensions.py
similarity index 100%
rename from tempest/api_schema/compute/v2/extensions.py
rename to tempest/api_schema/response/compute/v2/extensions.py
diff --git a/tempest/api_schema/compute/v2/fixed_ips.py b/tempest/api_schema/response/compute/v2/fixed_ips.py
similarity index 100%
rename from tempest/api_schema/compute/v2/fixed_ips.py
rename to tempest/api_schema/response/compute/v2/fixed_ips.py
diff --git a/tempest/api_schema/compute/v2/flavors.py b/tempest/api_schema/response/compute/v2/flavors.py
similarity index 92%
rename from tempest/api_schema/compute/v2/flavors.py
rename to tempest/api_schema/response/compute/v2/flavors.py
index bee6ecb..811ea84 100644
--- a/tempest/api_schema/compute/v2/flavors.py
+++ b/tempest/api_schema/response/compute/v2/flavors.py
@@ -14,11 +14,11 @@
import copy
-from tempest.api_schema.compute import flavors
+from tempest.api_schema.response.compute import flavors
list_flavors_details = copy.deepcopy(flavors.common_flavor_list_details)
-# 'swap' attributes comes as integre value but if it is empty it comes as "".
+# 'swap' attributes comes as integer value but if it is empty it comes as "".
# So defining type of as string and integer.
list_flavors_details['response_body']['properties']['flavors']['items'][
'properties']['swap'] = {'type': ['string', 'integer']}
@@ -38,7 +38,7 @@
create_get_flavor_details = copy.deepcopy(flavors.common_flavor_details)
-# 'swap' attributes comes as integre value but if it is empty it comes as "".
+# 'swap' attributes comes as integer value but if it is empty it comes as "".
# So defining type of as string and integer.
create_get_flavor_details['response_body']['properties']['flavor'][
'properties']['swap'] = {'type': ['string', 'integer']}
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/response/compute/v2/floating_ips.py
similarity index 100%
rename from tempest/api_schema/compute/v2/floating_ips.py
rename to tempest/api_schema/response/compute/v2/floating_ips.py
diff --git a/tempest/api_schema/compute/v2/hosts.py b/tempest/api_schema/response/compute/v2/hosts.py
similarity index 95%
rename from tempest/api_schema/compute/v2/hosts.py
rename to tempest/api_schema/response/compute/v2/hosts.py
index 86efadf..0944792 100644
--- a/tempest/api_schema/compute/v2/hosts.py
+++ b/tempest/api_schema/response/compute/v2/hosts.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import hosts
+from tempest.api_schema.response.compute import hosts
startup_host = {
diff --git a/tempest/api_schema/compute/v2/hypervisors.py b/tempest/api_schema/response/compute/v2/hypervisors.py
similarity index 95%
rename from tempest/api_schema/compute/v2/hypervisors.py
rename to tempest/api_schema/response/compute/v2/hypervisors.py
index 6bb43a7..7ad81c0 100644
--- a/tempest/api_schema/compute/v2/hypervisors.py
+++ b/tempest/api_schema/response/compute/v2/hypervisors.py
@@ -13,7 +13,7 @@
# under the License.
import copy
-from tempest.api_schema.compute import hypervisors
+from tempest.api_schema.response.compute import hypervisors
hypervisors_servers = copy.deepcopy(hypervisors.common_hypervisors_detail)
diff --git a/tempest/api_schema/compute/v2/images.py b/tempest/api_schema/response/compute/v2/images.py
similarity index 97%
rename from tempest/api_schema/compute/v2/images.py
rename to tempest/api_schema/response/compute/v2/images.py
index 90737a2..923c744 100644
--- a/tempest/api_schema/compute/v2/images.py
+++ b/tempest/api_schema/response/compute/v2/images.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
common_image_schema = {
'type': 'object',
diff --git a/tempest/api_schema/compute/v2/instance_usage_audit_logs.py b/tempest/api_schema/response/compute/v2/instance_usage_audit_logs.py
similarity index 100%
rename from tempest/api_schema/compute/v2/instance_usage_audit_logs.py
rename to tempest/api_schema/response/compute/v2/instance_usage_audit_logs.py
diff --git a/tempest/api_schema/compute/v2/interfaces.py b/tempest/api_schema/response/compute/v2/interfaces.py
similarity index 92%
rename from tempest/api_schema/compute/v2/interfaces.py
rename to tempest/api_schema/response/compute/v2/interfaces.py
index 7fca791..64d161d 100644
--- a/tempest/api_schema/compute/v2/interfaces.py
+++ b/tempest/api_schema/response/compute/v2/interfaces.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import interfaces as common_schema
list_interfaces = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/keypairs.py b/tempest/api_schema/response/compute/v2/keypairs.py
similarity index 96%
rename from tempest/api_schema/compute/v2/keypairs.py
rename to tempest/api_schema/response/compute/v2/keypairs.py
index 32d8cca..ec26fa0 100644
--- a/tempest/api_schema/compute/v2/keypairs.py
+++ b/tempest/api_schema/response/compute/v2/keypairs.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import keypairs
+from tempest.api_schema.response.compute import keypairs
get_keypair = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/limits.py b/tempest/api_schema/response/compute/v2/limits.py
similarity index 100%
rename from tempest/api_schema/compute/v2/limits.py
rename to tempest/api_schema/response/compute/v2/limits.py
diff --git a/tempest/api_schema/compute/v2/quota_classes.py b/tempest/api_schema/response/compute/v2/quota_classes.py
similarity index 95%
rename from tempest/api_schema/compute/v2/quota_classes.py
rename to tempest/api_schema/response/compute/v2/quota_classes.py
index 3464fb4..5474a89 100644
--- a/tempest/api_schema/compute/v2/quota_classes.py
+++ b/tempest/api_schema/response/compute/v2/quota_classes.py
@@ -15,7 +15,7 @@
import copy
-from tempest.api_schema.compute.v2 import quotas
+from tempest.api_schema.response.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
diff --git a/tempest/api_schema/compute/v2/quotas.py b/tempest/api_schema/response/compute/v2/quotas.py
similarity index 97%
rename from tempest/api_schema/compute/v2/quotas.py
rename to tempest/api_schema/response/compute/v2/quotas.py
index 31c0458..630b227 100644
--- a/tempest/api_schema/compute/v2/quotas.py
+++ b/tempest/api_schema/response/compute/v2/quotas.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import quotas
+from tempest.api_schema.response.compute import quotas
quota_set = copy.deepcopy(quotas.common_quota_set)
quota_set['response_body']['properties']['quota_set']['properties'][
diff --git a/tempest/api_schema/compute/v2/security_groups.py b/tempest/api_schema/response/compute/v2/security_groups.py
similarity index 100%
rename from tempest/api_schema/compute/v2/security_groups.py
rename to tempest/api_schema/response/compute/v2/security_groups.py
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
similarity index 88%
rename from tempest/api_schema/compute/v2/servers.py
rename to tempest/api_schema/response/compute/v2/servers.py
index 95c5760..5fc2008 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -14,8 +14,8 @@
import copy
-from tempest.api_schema.compute import parameter_types
-from tempest.api_schema.compute import servers
+from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute import servers
create_server = {
'status_code': [202],
@@ -28,14 +28,11 @@
'id': {'type': 'string'},
'security_groups': {'type': 'array'},
'links': parameter_types.links,
- 'adminPass': {'type': 'string'},
'OS-DCF:diskConfig': {'type': 'string'}
},
# NOTE: OS-DCF:diskConfig is API extension, and some
# environments return a response without the attribute.
# So it is not 'required'.
- # NOTE: adminPass is not required because it can be deactivated
- # with nova API flag enable_instance_password=False
'required': ['id', 'security_groups', 'links']
}
},
@@ -43,6 +40,12 @@
}
}
+create_server_with_admin_pass = copy.deepcopy(create_server)
+create_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'adminPass': {'type': 'string'}})
+create_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('adminPass')
+
update_server = copy.deepcopy(servers.base_update_get_server)
update_server['response_body']['properties']['server']['properties'].update({
'hostId': {'type': 'string'},
@@ -270,3 +273,25 @@
# without these attributes. So they are not 'required'.
list_servers_detail['response_body']['properties']['servers']['items'][
'required'].append('hostId')
+
+rebuild_server = copy.deepcopy(update_server)
+rebuild_server['status_code'] = [202]
+del rebuild_server['response_body']['properties']['server'][
+ 'properties']['OS-DCF:diskConfig']
+
+rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'adminPass': {'type': 'string'}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('adminPass')
+
+rescue_server = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'adminPass': {'type': 'string'}
+ },
+ 'required': ['adminPass']
+ }
+}
diff --git a/tempest/api_schema/compute/v2/tenant_usages.py b/tempest/api_schema/response/compute/v2/tenant_usages.py
similarity index 100%
rename from tempest/api_schema/compute/v2/tenant_usages.py
rename to tempest/api_schema/response/compute/v2/tenant_usages.py
diff --git a/tempest/api_schema/compute/v2/volumes.py b/tempest/api_schema/response/compute/v2/volumes.py
similarity index 100%
rename from tempest/api_schema/compute/v2/volumes.py
rename to tempest/api_schema/response/compute/v2/volumes.py
diff --git a/tempest/api_schema/compute/v3/__init__.py b/tempest/api_schema/response/compute/v3/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/v3/__init__.py
rename to tempest/api_schema/response/compute/v3/__init__.py
diff --git a/tempest/api_schema/compute/v3/agents.py b/tempest/api_schema/response/compute/v3/agents.py
similarity index 93%
rename from tempest/api_schema/compute/v3/agents.py
rename to tempest/api_schema/response/compute/v3/agents.py
index 597a089..9ef05df 100644
--- a/tempest/api_schema/compute/v3/agents.py
+++ b/tempest/api_schema/response/compute/v3/agents.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import agents
+from tempest.api_schema.response.compute import agents
create_agent = {
'status_code': [201],
diff --git a/tempest/api_schema/compute/v3/aggregates.py b/tempest/api_schema/response/compute/v3/aggregates.py
similarity index 94%
rename from tempest/api_schema/compute/v3/aggregates.py
rename to tempest/api_schema/response/compute/v3/aggregates.py
index 0272641..e3bae13 100644
--- a/tempest/api_schema/compute/v3/aggregates.py
+++ b/tempest/api_schema/response/compute/v3/aggregates.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import aggregates
+from tempest.api_schema.response.compute import aggregates
delete_aggregate = {
'status_code': [204]
diff --git a/tempest/api_schema/compute/v3/availability_zone.py b/tempest/api_schema/response/compute/v3/availability_zone.py
similarity index 95%
rename from tempest/api_schema/compute/v3/availability_zone.py
rename to tempest/api_schema/response/compute/v3/availability_zone.py
index 5f36c33..dbb1d41 100644
--- a/tempest/api_schema/compute/v3/availability_zone.py
+++ b/tempest/api_schema/response/compute/v3/availability_zone.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import availability_zone as common
+from tempest.api_schema.response.compute import availability_zone as common
base = {
diff --git a/tempest/api_schema/compute/v3/certificates.py b/tempest/api_schema/response/compute/v3/certificates.py
similarity index 92%
rename from tempest/api_schema/compute/v3/certificates.py
rename to tempest/api_schema/response/compute/v3/certificates.py
index 0723a16..c768391 100644
--- a/tempest/api_schema/compute/v3/certificates.py
+++ b/tempest/api_schema/response/compute/v3/certificates.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import certificates
+from tempest.api_schema.response.compute import certificates
create_certificate = copy.deepcopy(certificates._common_schema)
create_certificate['status_code'] = [201]
diff --git a/tempest/api_schema/compute/v3/extensions.py b/tempest/api_schema/response/compute/v3/extensions.py
similarity index 100%
rename from tempest/api_schema/compute/v3/extensions.py
rename to tempest/api_schema/response/compute/v3/extensions.py
diff --git a/tempest/api_schema/compute/v3/flavors.py b/tempest/api_schema/response/compute/v3/flavors.py
similarity index 95%
rename from tempest/api_schema/compute/v3/flavors.py
rename to tempest/api_schema/response/compute/v3/flavors.py
index 52010f5..d6c2c85 100644
--- a/tempest/api_schema/compute/v3/flavors.py
+++ b/tempest/api_schema/response/compute/v3/flavors.py
@@ -14,8 +14,8 @@
import copy
-from tempest.api_schema.compute import flavors
-from tempest.api_schema.compute import flavors_extra_specs
+from tempest.api_schema.response.compute import flavors
+from tempest.api_schema.response.compute import flavors_extra_specs
list_flavors_details = copy.deepcopy(flavors.common_flavor_list_details)
diff --git a/tempest/api_schema/compute/v3/hosts.py b/tempest/api_schema/response/compute/v3/hosts.py
similarity index 96%
rename from tempest/api_schema/compute/v3/hosts.py
rename to tempest/api_schema/response/compute/v3/hosts.py
index eb689d1..f356371 100644
--- a/tempest/api_schema/compute/v3/hosts.py
+++ b/tempest/api_schema/response/compute/v3/hosts.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import hosts
+from tempest.api_schema.response.compute import hosts
startup_host = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/hypervisors.py b/tempest/api_schema/response/compute/v3/hypervisors.py
similarity index 96%
rename from tempest/api_schema/compute/v3/hypervisors.py
rename to tempest/api_schema/response/compute/v3/hypervisors.py
index aa31827..9a9a9f7 100644
--- a/tempest/api_schema/compute/v3/hypervisors.py
+++ b/tempest/api_schema/response/compute/v3/hypervisors.py
@@ -13,7 +13,7 @@
# under the License.
import copy
-from tempest.api_schema.compute import hypervisors
+from tempest.api_schema.response.compute import hypervisors
list_hypervisors_detail = copy.deepcopy(
hypervisors.common_list_hypervisors_detail)
diff --git a/tempest/api_schema/compute/v3/interfaces.py b/tempest/api_schema/response/compute/v3/interfaces.py
similarity index 92%
rename from tempest/api_schema/compute/v3/interfaces.py
rename to tempest/api_schema/response/compute/v3/interfaces.py
index 5e1cee2..7f716ee 100644
--- a/tempest/api_schema/compute/v3/interfaces.py
+++ b/tempest/api_schema/response/compute/v3/interfaces.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import interfaces as common_schema
list_interfaces = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/keypairs.py b/tempest/api_schema/response/compute/v3/keypairs.py
similarity index 95%
rename from tempest/api_schema/compute/v3/keypairs.py
rename to tempest/api_schema/response/compute/v3/keypairs.py
index de5f4ba..ea15405 100644
--- a/tempest/api_schema/compute/v3/keypairs.py
+++ b/tempest/api_schema/response/compute/v3/keypairs.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import keypairs
+from tempest.api_schema.response.compute import keypairs
get_keypair = {
'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/quotas.py b/tempest/api_schema/response/compute/v3/quotas.py
similarity index 97%
rename from tempest/api_schema/compute/v3/quotas.py
rename to tempest/api_schema/response/compute/v3/quotas.py
index a3212ed..85ed3b3 100644
--- a/tempest/api_schema/compute/v3/quotas.py
+++ b/tempest/api_schema/response/compute/v3/quotas.py
@@ -14,7 +14,7 @@
import copy
-from tempest.api_schema.compute import quotas
+from tempest.api_schema.response.compute import quotas
quota_set = copy.deepcopy(quotas.common_quota_set)
quota_set['response_body']['properties']['quota_set']['properties'][
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/response/compute/v3/servers.py
similarity index 83%
rename from tempest/api_schema/compute/v3/servers.py
rename to tempest/api_schema/response/compute/v3/servers.py
index dc800cd..230de5f 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/response/compute/v3/servers.py
@@ -14,8 +14,8 @@
import copy
-from tempest.api_schema.compute import parameter_types
-from tempest.api_schema.compute import servers
+from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute import servers
create_server = {
'status_code': [202],
@@ -28,7 +28,6 @@
'id': {'type': 'string'},
'os-security-groups:security_groups': {'type': 'array'},
'links': parameter_types.links,
- 'admin_password': {'type': 'string'},
'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
'os-access-ips:access_ip_v6': parameter_types.access_ip_v6
},
@@ -36,13 +35,19 @@
# and some environments return a response without these
# attributes. So they are not 'required'.
'required': ['id', 'os-security-groups:security_groups',
- 'links', 'admin_password']
+ 'links']
}
},
'required': ['server']
}
}
+create_server_with_admin_pass = copy.deepcopy(create_server)
+create_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'admin_password': {'type': 'string'}})
+create_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('admin_password')
+
addresses_v3 = copy.deepcopy(parameter_types.addresses)
addresses_v3['patternProperties']['^[a-zA-Z0-9-_.]+$']['items'][
'properties'].update({
@@ -181,3 +186,27 @@
# attributes. So they are not 'required'.
list_servers_detail['response_body']['properties']['servers']['items'][
'required'].append('host_id')
+
+rebuild_server = copy.deepcopy(update_server)
+rebuild_server['status_code'] = [202]
+
+rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'properties'].update({'admin_password': {'type': 'string'}})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+ 'required'].append('admin_password')
+
+rescue_server_with_admin_pass = {
+ 'status_code': [202],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'admin_password': {'type': 'string'}
+ },
+ 'required': ['admin_password']
+ }
+}
+
+rescue_server = copy.deepcopy(rescue_server_with_admin_pass)
+del rescue_server['response_body']['properties']
+del rescue_server['response_body']['required']
diff --git a/tempest/api_schema/compute/version.py b/tempest/api_schema/response/compute/version.py
similarity index 100%
rename from tempest/api_schema/compute/version.py
rename to tempest/api_schema/response/compute/version.py
diff --git a/tempest/api_schema/queuing/__init__.py b/tempest/api_schema/response/queuing/__init__.py
similarity index 100%
rename from tempest/api_schema/queuing/__init__.py
rename to tempest/api_schema/response/queuing/__init__.py
diff --git a/tempest/api_schema/queuing/v1/__init__.py b/tempest/api_schema/response/queuing/v1/__init__.py
similarity index 100%
rename from tempest/api_schema/queuing/v1/__init__.py
rename to tempest/api_schema/response/queuing/v1/__init__.py
diff --git a/tempest/api_schema/queuing/v1/queues.py b/tempest/api_schema/response/queuing/v1/queues.py
similarity index 100%
rename from tempest/api_schema/queuing/v1/queues.py
rename to tempest/api_schema/response/queuing/v1/queues.py
diff --git a/tempest/auth.py b/tempest/auth.py
index 830dca9..5df6224 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+import abc
import copy
import datetime
import exceptions
import re
+import six
import urlparse
from tempest import config
@@ -31,6 +33,7 @@
LOG = logging.getLogger(__name__)
+@six.add_metaclass(abc.ABCMeta)
class AuthProvider(object):
"""
Provide authentication
@@ -70,18 +73,21 @@
interface=self.interface, cache=self.cache
)
+ @abc.abstractmethod
def _decorate_request(self, filters, method, url, headers=None, body=None,
auth_data=None):
"""
Decorate request with authentication data
"""
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _get_auth(self):
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _fill_credentials(self, auth_data_body):
- raise NotImplementedError
+ return
def fill_credentials(self):
"""
@@ -130,8 +136,9 @@
self.cache = None
self.credentials.reset()
+ @abc.abstractmethod
def is_expired(self, auth_data):
- raise NotImplementedError
+ return
def auth_request(self, method, url, headers=None, body=None, filters=None):
"""
@@ -188,11 +195,12 @@
self.alt_part = request_part
self.alt_auth_data = auth_data
+ @abc.abstractmethod
def base_url(self, filters, auth_data=None):
"""
Extracts the base_url based on provided filters
"""
- raise NotImplementedError
+ return
class KeystoneAuthProvider(AuthProvider):
@@ -225,11 +233,13 @@
# no change to method or body
return str(_url), _headers, body
+ @abc.abstractmethod
def _auth_client(self):
- raise NotImplementedError
+ return
+ @abc.abstractmethod
def _auth_params(self):
- raise NotImplementedError
+ return
def _get_auth(self):
# Bypasses the cache
@@ -321,7 +331,7 @@
if noversion_path != "":
path += "/" + noversion_path
_base_url = _base_url.replace(parts.path, path)
- if filters.get('skip_path', None) is not None:
+ if filters.get('skip_path', None) is not None and parts.path != '':
_base_url = _base_url.replace(parts.path, "/")
return _base_url
diff --git a/tempest/cli/simple_read_only/test_glance.py b/tempest/cli/simple_read_only/test_glance.py
index 90cdc55..2fd8212 100644
--- a/tempest/cli/simple_read_only/test_glance.py
+++ b/tempest/cli/simple_read_only/test_glance.py
@@ -77,7 +77,7 @@
wanted_commands = set(('image-create', 'image-delete', 'help',
'image-download', 'image-show', 'image-update',
'member-create', 'member-delete',
- 'member-list'))
+ 'member-list', 'image-list'))
self.assertFalse(wanted_commands - commands)
# Optional arguments:
diff --git a/tempest/clients.py b/tempest/clients.py
index 4e2205e..0edcdf4 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -52,6 +52,8 @@
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_group_default_rules_client import \
+ SecurityGroupDefaultRulesClientJSON
from tempest.services.compute.json.security_groups_client import \
SecurityGroupsClientJSON
from tempest.services.compute.json.servers_client import ServersClientJSON
@@ -179,7 +181,15 @@
ExtensionsClientJSON as VolumeExtensionClientJSON
from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
from tempest.services.volume.json.volumes_client import VolumesClientJSON
+from tempest.services.volume.v2.json.availability_zone_client import \
+ VolumeV2AvailabilityZoneClientJSON
+from tempest.services.volume.v2.json.extensions_client import \
+ ExtensionsV2ClientJSON as VolumeV2ExtensionClientJSON
from tempest.services.volume.v2.json.volumes_client import VolumesV2ClientJSON
+from tempest.services.volume.v2.xml.availability_zone_client import \
+ VolumeV2AvailabilityZoneClientXML
+from tempest.services.volume.v2.xml.extensions_client import \
+ ExtensionsV2ClientXML as VolumeV2ExtensionClientXML
from tempest.services.volume.v2.xml.volumes_client import VolumesV2ClientXML
from tempest.services.volume.xml.admin.volume_hosts_client import \
VolumeHostsClientXML
@@ -268,6 +278,8 @@
self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientXML(
self.auth_provider)
+ self.volumes_v2_extension_client = VolumeV2ExtensionClientXML(
+ self.auth_provider)
if CONF.service_available.ceilometer:
self.telemetry_client = TelemetryClientXML(
self.auth_provider)
@@ -275,6 +287,8 @@
self.token_v3_client = V3TokenClientXML()
self.volume_availability_zone_client = \
VolumeAvailabilityZoneClientXML(self.auth_provider)
+ self.volume_v2_availability_zone_client = \
+ VolumeV2AvailabilityZoneClientXML(self.auth_provider)
elif self.interface == 'json':
self.certificates_client = CertificatesClientJSON(
@@ -360,6 +374,8 @@
self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientJSON(
self.auth_provider)
+ self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
+ self.auth_provider)
self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
self.database_flavors_client = DatabaseFlavorsClientJSON(
self.auth_provider)
@@ -376,6 +392,8 @@
self.negative_client.service = service
self.volume_availability_zone_client = \
VolumeAvailabilityZoneClientJSON(self.auth_provider)
+ self.volume_v2_availability_zone_client = \
+ VolumeV2AvailabilityZoneClientJSON(self.auth_provider)
else:
msg = "Unsupported interface type `%s'" % interface
@@ -406,6 +424,8 @@
self.data_processing_client = DataProcessingClient(
self.auth_provider)
self.migrations_client = MigrationsClientJSON(self.auth_provider)
+ self.security_group_default_rules_client = (
+ SecurityGroupDefaultRulesClientJSON(self.auth_provider))
class AltManager(Manager):
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index c1a2e46..3616a82 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -219,7 +219,7 @@
def check_objects(self):
"""Check that the objects created are still there."""
- if 'objects' not in self.res:
+ if not self.res.get('objects'):
return
LOG.info("checking objects")
for obj in self.res['objects']:
@@ -231,7 +231,7 @@
def check_servers(self):
"""Check that the servers are still up and running."""
- if 'servers' not in self.res:
+ if not self.res.get('servers'):
return
LOG.info("checking servers")
for server in self.res['servers']:
@@ -254,7 +254,7 @@
def check_volumes(self):
"""Check that the volumes are still there and attached."""
- if 'volumes' not in self.res:
+ if not self.res.get('volumes'):
return
LOG.info("checking volumes")
for volume in self.res['volumes']:
@@ -309,6 +309,14 @@
return name, fname
+def _get_image_by_name(client, name):
+ r, body = client.images.image_list()
+ for image in body:
+ if name == image['name']:
+ return image
+ return None
+
+
def create_images(images):
if not images:
return
@@ -317,9 +325,7 @@
client = client_for_user(image['owner'])
# only upload a new image if the name isn't there
- r, body = client.images.image_list()
- names = [x['name'] for x in body]
- if image['name'] in names:
+ if _get_image_by_name(client, image['name']):
LOG.info("Image '%s' already exists" % image['name'])
continue
@@ -345,6 +351,20 @@
client.images.store_image(image_id, open(fname, 'r'))
+def destroy_images(images):
+ if not images:
+ return
+ LOG.info("Destroying images")
+ for image in images:
+ client = client_for_user(image['owner'])
+
+ response = _get_image_by_name(client, image['name'])
+ if not response:
+ LOG.info("Image '%s' does not exists" % image['name'])
+ continue
+ client.images.delete_image(response['id'])
+
+
#######################
#
# SERVERS
@@ -359,14 +379,6 @@
return None
-def _get_image_by_name(client, name):
- r, body = client.images.image_list()
- for image in body:
- if name == image['name']:
- return image
- return None
-
-
def _get_flavor_by_name(client, name):
r, body = client.flavors.list_flavors()
for flavor in body:
@@ -478,13 +490,14 @@
# destroy_volumes
destroy_servers(RES['servers'])
- LOG.warn("Destroy mode incomplete")
- # destroy_images
+ destroy_images(RES['images'])
# destroy_objects
# destroy_users
# destroy_tenants
+ LOG.warn("Destroy mode incomplete")
+
def get_options():
global OPTS
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 4a7921f..996c365 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -69,10 +69,24 @@
elif self.target == 'Object':
if 'etag' not in actual:
return NonExistentHeader('etag')
- elif self.method == 'PUT' or self.method == 'COPY':
+ if 'last-modified' not in actual:
+ return NonExistentHeader('last-modified')
+ elif self.method == 'PUT':
if self.target == 'Object':
if 'etag' not in actual:
return NonExistentHeader('etag')
+ if 'last-modified' not in actual:
+ return NonExistentHeader('last-modified')
+ elif self.method == 'COPY':
+ if self.target == 'Object':
+ if 'etag' not in actual:
+ return NonExistentHeader('etag')
+ if 'last-modified' not in actual:
+ return NonExistentHeader('last-modified')
+ if 'x-copied-from' not in actual:
+ return NonExistentHeader('x-copied-from')
+ if 'x-copied-from-last-modified' not in actual:
+ return NonExistentHeader('x-copied-from-last-modified')
return None
@@ -122,11 +136,17 @@
return InvalidFormat(key, value)
elif key == 'content-type' and not value:
return InvalidFormat(key, value)
+ elif key == 'x-copied-from' and not re.match("\S+/\S+", value):
+ return InvalidFormat(key, value)
+ elif key == 'x-copied-from-last-modified' and not value:
+ return InvalidFormat(key, value)
elif key == 'x-trans-id' and \
not re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", value):
return InvalidFormat(key, value)
elif key == 'date' and not value:
return InvalidFormat(key, value)
+ elif key == 'last-modified' and not value:
+ return InvalidFormat(key, value)
elif key == 'accept-ranges' and not value == 'bytes':
return InvalidFormat(key, value)
elif key == 'etag' and not value.isalnum():
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 98b0116..05d758f 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -330,7 +330,8 @@
# Maintained until tests are ported
LOG.info("Acquired isolated creds:\n credentials: %s"
% credentials)
- if CONF.service_available.neutron:
+ if (CONF.service_available.neutron and
+ not CONF.baremetal.driver_enabled):
network, subnet, router = self._create_network_resources(
credentials.tenant_id)
self.isolated_net_resources[credential_type] = (
diff --git a/tempest/common/utils/data_utils.py b/tempest/common/utils/data_utils.py
index 174e557..5a29ea0 100644
--- a/tempest/common/utils/data_utils.py
+++ b/tempest/common/utils/data_utils.py
@@ -71,3 +71,11 @@
if not base_text:
base_text = 'test'
return ''.join(itertools.islice(itertools.cycle(base_text), size))
+
+
+def random_bytes(size=1024):
+ """
+ Return size randomly selected bytes as a string.
+ """
+ return ''.join([chr(random.randint(0, 255))
+ for i in range(size)])
diff --git a/tempest/config.py b/tempest/config.py
index b4f4e85..3b61700 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -298,6 +298,9 @@
cfg.BoolOpt('pause',
default=True,
help="Does the test environment support pausing?"),
+ cfg.BoolOpt('shelve',
+ default=True,
+ help="Does the test environment support shelving/unshelving?"),
cfg.BoolOpt('suspend',
default=True,
help="Does the test environment support suspend/resume?"),
@@ -328,7 +331,16 @@
cfg.BoolOpt('rescue',
default=True,
help='Does the test environment support instance rescue '
- 'mode?')
+ 'mode?'),
+ cfg.BoolOpt('enable_instance_password',
+ default=True,
+ help='Enables returning of the instance password by the '
+ 'relevant server API calls such as create, rebuild '
+ 'or rescue.'),
+ cfg.BoolOpt('interface_attach',
+ default=True,
+ help='Does the test environment support dynamic network '
+ 'interface attachment?')
]
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index aa24c31..606208e 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -113,6 +113,11 @@
cls.ceilometer_client = cls.manager.ceilometer_client
@classmethod
+ def tearDownClass(cls):
+ cls.isolated_creds.clear_isolated_creds()
+ super(OfficialClientTest, cls).tearDownClass()
+
+ @classmethod
def _get_credentials(cls, get_creds, ctype):
if CONF.compute.allow_tenant_isolation:
creds = get_creds()
@@ -1080,7 +1085,8 @@
try:
source.ping_host(dest)
except exceptions.SSHExecCommandFailed:
- LOG.exception('Failed to ping host via ssh connection')
+ LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
+ % (dest, source.ssh_client.host))
return not should_succeed
return should_succeed
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 7dc817d..8c7af3d 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -14,8 +14,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
-
import re
+import testtools
from tempest.api.network import common as net_common
from tempest.common import debug
@@ -347,6 +347,8 @@
msg="after re-associate "
"floating ip")
+ @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+ 'NIC hotplug not available')
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_hotplug_nic(self):
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 4f6602f..5b76a56 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -15,8 +15,8 @@
import json
import urllib
-from tempest.api_schema.compute import agents as common_schema
-from tempest.api_schema.compute.v2 import agents as schema
+from tempest.api_schema.response.compute import agents as common_schema
+from tempest.api_schema.response.compute.v2 import agents as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 71d6f63..1cb010d 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import aggregates as schema
-from tempest.api_schema.compute.v2 import aggregates as v2_schema
+from tempest.api_schema.response.compute import aggregates as schema
+from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index 1c067e8..00f8330 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v2 import availability_zone as schema
+from tempest.api_schema.response.compute.v2 import availability_zone as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index 1d04628..356ded2 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import certificates as schema
-from tempest.api_schema.compute.v2 import certificates as v2schema
+from tempest.api_schema.response.compute import certificates as schema
+from tempest.api_schema.response.compute.v2 import certificates as v2schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index ed2b14d..41d1c4e 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v2 import extensions as schema
+from tempest.api_schema.response.compute.v2 import extensions as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index f2d5cbe..5903334 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v2 import fixed_ips as schema
+from tempest.api_schema.response.compute.v2 import fixed_ips as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 89cbe1d..5452f3a 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -16,11 +16,11 @@
import json
import urllib
-from tempest.api_schema.compute import flavors as common_schema
-from tempest.api_schema.compute import flavors_access as schema_access
-from tempest.api_schema.compute import flavors_extra_specs \
+from tempest.api_schema.response.compute import flavors as common_schema
+from tempest.api_schema.response.compute import flavors_access as schema_access
+from tempest.api_schema.response.compute import flavors_extra_specs \
as schema_extra_specs
-from tempest.api_schema.compute.v2 import flavors as v2schema
+from tempest.api_schema.response.compute.v2 import flavors as v2schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index cd195f4..8b020d0 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.api_schema.compute.v2 import floating_ips as schema
+from tempest.api_schema.response.compute.v2 import floating_ips as schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 342f946..8644173 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -15,8 +15,8 @@
import json
import urllib
-from tempest.api_schema.compute import hosts as schema
-from tempest.api_schema.compute.v2 import hosts as v2_schema
+from tempest.api_schema.response.compute import hosts as schema
+from tempest.api_schema.response.compute.v2 import hosts as v2_schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 30228b3..8eacf61 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import hypervisors as common_schema
-from tempest.api_schema.compute.v2 import hypervisors as v2schema
+from tempest.api_schema.response.compute import hypervisors as common_schema
+from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index af7752a..9877391 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.api_schema.compute.v2 import images as schema
+from tempest.api_schema.response.compute.v2 import images as schema
from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 4700ca7..4b0362b 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v2 import instance_usage_audit_logs \
+from tempest.api_schema.response.compute.v2 import instance_usage_audit_logs \
as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index cdac8b7..83c253a 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -16,9 +16,9 @@
import json
import time
-from tempest.api_schema.compute import interfaces as common_schema
-from tempest.api_schema.compute import servers as servers_schema
-from tempest.api_schema.compute.v2 import interfaces as schema
+from tempest.api_schema.response.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import servers as servers_schema
+from tempest.api_schema.response.compute.v2 import interfaces as schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index be93789..31c42a5 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import keypairs as common_schema
-from tempest.api_schema.compute.v2 import keypairs as schema
+from tempest.api_schema.response.compute import keypairs as common_schema
+from tempest.api_schema.response.compute.v2 import keypairs as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index e503bef..81c602b 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v2 import limits as schema
+from tempest.api_schema.response.compute.v2 import limits as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index beef5d2..f4abbb2 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -15,7 +15,7 @@
import json
import urllib
-from tempest.api_schema.compute import migrations as schema
+from tempest.api_schema.response.compute import migrations as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 14b7100..b691529 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,8 +15,9 @@
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.api_schema.response.compute.v2\
+ import quota_classes as classes_schema
+from tempest.api_schema.response.compute.v2 import quotas as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/security_group_default_rules_client.py b/tempest/services/compute/json/security_group_default_rules_client.py
new file mode 100644
index 0000000..6d29837
--- /dev/null
+++ b/tempest/services/compute/json/security_group_default_rules_client.py
@@ -0,0 +1,74 @@
+# 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.
+
+import json
+
+from tempest.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class SecurityGroupDefaultRulesClientJSON(rest_client.RestClient):
+
+ def __init__(self, auth_provider):
+ super(SecurityGroupDefaultRulesClientJSON,
+ self).__init__(auth_provider)
+ self.service = CONF.compute.catalog_type
+
+ def create_security_default_group_rule(self, ip_protocol, from_port,
+ to_port, **kwargs):
+ """
+ Creating security group default rules.
+ ip_protocol : ip_protocol (icmp, tcp, udp).
+ from_port: Port at start of range.
+ to_port : Port at end of range.
+ cidr : CIDR for address range.
+ """
+ post_body = {
+ 'ip_protocol': ip_protocol,
+ 'from_port': from_port,
+ 'to_port': to_port,
+ 'cidr': kwargs.get('cidr'),
+ }
+ post_body = json.dumps({'security_group_default_rule': post_body})
+ url = 'os-security-group-default-rules'
+ resp, body = self.post(url, post_body)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return resp, body['security_group_default_rule']
+
+ def delete_security_group_default_rule(self,
+ security_group_default_rule_id):
+ """Deletes the provided Security Group default rule."""
+ resp, body = self.delete('os-security-group-default-rules/%s' % str(
+ security_group_default_rule_id))
+ self.expected_success(204, resp.status)
+ return resp, body
+
+ def list_security_group_default_rules(self):
+ """List all Security Group default rules."""
+ resp, body = self.get('os-security-group-default-rules')
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return resp, body['security_group_default_rules']
+
+ def get_security_group_default_rule(self, security_group_default_rule_id):
+ """Return the details of provided Security Group default rule."""
+ resp, body = self.get('os-security-group-default-rules/%s' % str(
+ security_group_default_rule_id))
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return resp, body['security_group_default_rule']
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index a86f3df..29859a9 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.api_schema.compute.v2 import security_groups as schema
+from tempest.api_schema.response.compute.v2 import security_groups as schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 80bb711..f44be29 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -18,8 +18,8 @@
import time
import urllib
-from tempest.api_schema.compute import servers as common_schema
-from tempest.api_schema.compute.v2 import servers as schema
+from tempest.api_schema.response.compute import servers as common_schema
+from tempest.api_schema.response.compute.v2 import servers as schema
from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
@@ -93,7 +93,11 @@
# with return reservation id set True
if 'reservation_id' in body:
return resp, body
- self.validate_response(schema.create_server, resp, body)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ create_schema = schema.create_server_with_admin_pass
+ else:
+ create_schema = schema.create_server
+ self.validate_response(create_schema, resp, body)
return resp, body['server']
def update_server(self, server_id, name=None, meta=None, accessIPv4=None,
@@ -269,7 +273,12 @@
if 'disk_config' in kwargs:
kwargs['OS-DCF:diskConfig'] = kwargs['disk_config']
del kwargs['disk_config']
- return self.action(server_id, 'rebuild', 'server', None, **kwargs)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ rebuild_schema = schema.rebuild_server_with_admin_pass
+ else:
+ rebuild_schema = schema.rebuild_server
+ return self.action(server_id, 'rebuild', 'server',
+ rebuild_schema, **kwargs)
def resize(self, server_id, flavor_ref, **kwargs):
"""Changes the flavor of a server."""
@@ -450,7 +459,8 @@
def rescue_server(self, server_id, **kwargs):
"""Rescue the provided server."""
- return self.action(server_id, 'rescue', 'adminPass', None, **kwargs)
+ return self.action(server_id, 'rescue', 'adminPass',
+ schema.rescue_server, **kwargs)
def unrescue_server(self, server_id):
"""Unrescue the provided server."""
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index d58ca6f..e56263c 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -17,7 +17,7 @@
import json
import urllib
-from tempest.api_schema.compute import services as schema
+from tempest.api_schema.response.compute import services as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index f8adae7..a0b9b4a 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.api_schema.compute.v2 import tenant_usages as schema
+from tempest.api_schema.response.compute.v2 import tenant_usages as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index d1014af..673e365 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -17,7 +17,7 @@
import time
import urllib
-from tempest.api_schema.compute.v2 import volumes as schema
+from tempest.api_schema.response.compute.v2 import volumes as schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/agents_client.py b/tempest/services/compute/v3/json/agents_client.py
index 31314b7..ffca142 100644
--- a/tempest/services/compute/v3/json/agents_client.py
+++ b/tempest/services/compute/v3/json/agents_client.py
@@ -15,8 +15,8 @@
import json
import urllib
-from tempest.api_schema.compute import agents as common_schema
-from tempest.api_schema.compute.v3 import agents as schema
+from tempest.api_schema.response.compute import agents as common_schema
+from tempest.api_schema.response.compute.v3 import agents as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/aggregates_client.py b/tempest/services/compute/v3/json/aggregates_client.py
index d9b7930..960fe05 100644
--- a/tempest/services/compute/v3/json/aggregates_client.py
+++ b/tempest/services/compute/v3/json/aggregates_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import aggregates as schema
-from tempest.api_schema.compute.v3 import aggregates as v3_schema
+from tempest.api_schema.response.compute import aggregates as schema
+from tempest.api_schema.response.compute.v3 import aggregates as v3_schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/availability_zone_client.py b/tempest/services/compute/v3/json/availability_zone_client.py
index bf74e68..0da78da 100644
--- a/tempest/services/compute/v3/json/availability_zone_client.py
+++ b/tempest/services/compute/v3/json/availability_zone_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v3 import availability_zone as schema
+from tempest.api_schema.response.compute.v3 import availability_zone as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/certificates_client.py b/tempest/services/compute/v3/json/certificates_client.py
index be9b3c3..42e9d5a 100644
--- a/tempest/services/compute/v3/json/certificates_client.py
+++ b/tempest/services/compute/v3/json/certificates_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import certificates as schema
-from tempest.api_schema.compute.v3 import certificates as v3schema
+from tempest.api_schema.response.compute import certificates as schema
+from tempest.api_schema.response.compute.v3 import certificates as v3schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/extensions_client.py b/tempest/services/compute/v3/json/extensions_client.py
index 13292db..f172efd 100644
--- a/tempest/services/compute/v3/json/extensions_client.py
+++ b/tempest/services/compute/v3/json/extensions_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v3 import extensions as schema
+from tempest.api_schema.response.compute.v3 import extensions as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index 5afab5a..d1eee5b 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -16,11 +16,11 @@
import json
import urllib
-from tempest.api_schema.compute import flavors as common_schema
-from tempest.api_schema.compute import flavors_access as schema_access
-from tempest.api_schema.compute import flavors_extra_specs \
+from tempest.api_schema.response.compute import flavors as common_schema
+from tempest.api_schema.response.compute import flavors_access as schema_access
+from tempest.api_schema.response.compute import flavors_extra_specs \
as schema_extra_specs
-from tempest.api_schema.compute.v3 import flavors as v3schema
+from tempest.api_schema.response.compute.v3 import flavors as v3schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/hosts_client.py b/tempest/services/compute/v3/json/hosts_client.py
index d2eb43d..476afad 100644
--- a/tempest/services/compute/v3/json/hosts_client.py
+++ b/tempest/services/compute/v3/json/hosts_client.py
@@ -15,8 +15,8 @@
import json
import urllib
-from tempest.api_schema.compute import hosts as schema
-from tempest.api_schema.compute.v3 import hosts as v3_schema
+from tempest.api_schema.response.compute import hosts as schema
+from tempest.api_schema.response.compute.v3 import hosts as v3_schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/hypervisor_client.py b/tempest/services/compute/v3/json/hypervisor_client.py
index 51468c9..507157a 100644
--- a/tempest/services/compute/v3/json/hypervisor_client.py
+++ b/tempest/services/compute/v3/json/hypervisor_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import hypervisors as common_schema
-from tempest.api_schema.compute.v3 import hypervisors as v3schema
+from tempest.api_schema.response.compute import hypervisors as common_schema
+from tempest.api_schema.response.compute.v3 import hypervisors as v3schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
index e66ccaa..e99c124 100644
--- a/tempest/services/compute/v3/json/interfaces_client.py
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -16,9 +16,9 @@
import json
import time
-from tempest.api_schema.compute import interfaces as common_schema
-from tempest.api_schema.compute import servers as servers_schema
-from tempest.api_schema.compute.v3 import interfaces as schema
+from tempest.api_schema.response.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import servers as servers_schema
+from tempest.api_schema.response.compute.v3 import interfaces as schema
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/keypairs_client.py b/tempest/services/compute/v3/json/keypairs_client.py
index f090d7d..a290acb 100644
--- a/tempest/services/compute/v3/json/keypairs_client.py
+++ b/tempest/services/compute/v3/json/keypairs_client.py
@@ -15,8 +15,8 @@
import json
-from tempest.api_schema.compute import keypairs as common_schema
-from tempest.api_schema.compute.v3 import keypairs as schema
+from tempest.api_schema.response.compute import keypairs as common_schema
+from tempest.api_schema.response.compute.v3 import keypairs as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/migration_client.py b/tempest/services/compute/v3/json/migration_client.py
index c821567..bf1ae85 100644
--- a/tempest/services/compute/v3/json/migration_client.py
+++ b/tempest/services/compute/v3/json/migration_client.py
@@ -15,7 +15,7 @@
import json
import urllib
-from tempest.api_schema.compute import migrations as schema
+from tempest.api_schema.response.compute import migrations as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index 37a8906..f9aa9e9 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute.v3 import quotas as schema
+from tempest.api_schema.response.compute.v3 import quotas as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index a5b31d3..89e282d 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -19,8 +19,8 @@
import time
import urllib
-from tempest.api_schema.compute import servers as common_schema
-from tempest.api_schema.compute.v3 import servers as schema
+from tempest.api_schema.response.compute import servers as common_schema
+from tempest.api_schema.response.compute.v3 import servers as schema
from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
@@ -96,7 +96,11 @@
# with return reservation id set True
if 'servers_reservation' in body:
return resp, body['servers_reservation']
- self.validate_response(schema.create_server, resp, body)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ create_schema = schema.create_server_with_admin_pass
+ else:
+ create_schema = schema.create_server
+ self.validate_response(create_schema, resp, body)
return resp, body['server']
def update_server(self, server_id, name=None, meta=None, access_ip_v4=None,
@@ -272,7 +276,12 @@
if 'disk_config' in kwargs:
kwargs['os-disk-config:disk_config'] = kwargs['disk_config']
del kwargs['disk_config']
- return self.action(server_id, 'rebuild', 'server', None, **kwargs)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ rebuild_schema = schema.rebuild_server_with_admin_pass
+ else:
+ rebuild_schema = schema.rebuild_server
+ return self.action(server_id, 'rebuild', 'server',
+ rebuild_schema, **kwargs)
def resize(self, server_id, flavor_ref, **kwargs):
"""Changes the flavor of a server."""
@@ -445,8 +454,16 @@
def rescue_server(self, server_id, **kwargs):
"""Rescue the provided server."""
- return self.action(server_id, 'rescue', 'admin_password',
- None, **kwargs)
+ post_body = json.dumps({'rescue': kwargs})
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ if CONF.compute_feature_enabled.enable_instance_password:
+ rescue_schema = schema.rescue_server_with_admin_pass
+ else:
+ rescue_schema = schema.rescue_server
+ body = json.loads(body)
+ self.validate_response(rescue_schema, resp, body)
+ return resp, body
def unrescue_server(self, server_id):
"""Unrescue the provided server."""
diff --git a/tempest/services/compute/v3/json/services_client.py b/tempest/services/compute/v3/json/services_client.py
index 96ff580..0645287 100644
--- a/tempest/services/compute/v3/json/services_client.py
+++ b/tempest/services/compute/v3/json/services_client.py
@@ -17,7 +17,7 @@
import json
import urllib
-from tempest.api_schema.compute import services as schema
+from tempest.api_schema.response.compute import services as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/compute/v3/json/version_client.py b/tempest/services/compute/v3/json/version_client.py
index 568678d..bc4f58c 100644
--- a/tempest/services/compute/v3/json/version_client.py
+++ b/tempest/services/compute/v3/json/version_client.py
@@ -15,7 +15,7 @@
import json
-from tempest.api_schema.compute import version as schema
+from tempest.api_schema.response.compute import version as schema
from tempest.common import rest_client
from tempest import config
diff --git a/tempest/services/data_processing/v1_1/client.py b/tempest/services/data_processing/v1_1/client.py
index 1fe0cf1..7acbae7 100644
--- a/tempest/services/data_processing/v1_1/client.py
+++ b/tempest/services/data_processing/v1_1/client.py
@@ -258,3 +258,38 @@
uri = 'job-binaries/%s/data' % job_binary_id
return self._request_and_check_resp(self.get, uri, 200)
+
+ def list_jobs(self):
+ """List all jobs for a user."""
+
+ uri = 'jobs'
+ return self._request_check_and_parse_resp(self.get, uri, 200, 'jobs')
+
+ def get_job(self, job_id):
+ """Returns the details of a single job."""
+
+ uri = 'jobs/%s' % job_id
+ return self._request_check_and_parse_resp(self.get, uri, 200, 'job')
+
+ def create_job(self, name, job_type, mains, libs=None, **kwargs):
+ """Creates job with specified params.
+
+ It supports passing additional params using kwargs and returns created
+ object.
+ """
+ uri = 'jobs'
+ body = kwargs.copy()
+ body.update({
+ 'name': name,
+ 'type': job_type,
+ 'mains': mains,
+ 'libs': libs or list(),
+ })
+ return self._request_check_and_parse_resp(self.post, uri, 202,
+ 'job', body=json.dumps(body))
+
+ def delete_job(self, job_id):
+ """Deletes the specified job by id."""
+
+ uri = 'jobs/%s' % job_id
+ return self._request_and_check_resp(self.delete, uri, 204)
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 0188c2a..d57b931 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -135,8 +135,11 @@
body = json.loads(body)
return resp, body['project']
- def list_projects(self):
- resp, body = self.get("projects")
+ def list_projects(self, params=None):
+ url = "projects"
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return resp, body['projects']
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index f3e084e..c2bd77e 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -197,9 +197,12 @@
body = self._parse_body(etree.fromstring(body))
return resp, body
- def list_projects(self):
+ def list_projects(self, params=None):
"""Get the list of projects."""
- resp, body = self.get("projects")
+ url = 'projects'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
self.expected_success(200, resp.status)
body = self._parse_projects(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/queuing/json/queuing_client.py b/tempest/services/queuing/json/queuing_client.py
index 031c9c6..14960ad 100644
--- a/tempest/services/queuing/json/queuing_client.py
+++ b/tempest/services/queuing/json/queuing_client.py
@@ -16,7 +16,7 @@
import json
import urllib
-from tempest.api_schema.queuing.v1 import queues as queues_schema
+from tempest.api_schema.response.queuing.v1 import queues as queues_schema
from tempest.common import rest_client
from tempest.common.utils import data_utils
from tempest import config
diff --git a/tempest/services/volume/json/availability_zone_client.py b/tempest/services/volume/json/availability_zone_client.py
index 6839d3a..f2e7c5c 100644
--- a/tempest/services/volume/json/availability_zone_client.py
+++ b/tempest/services/volume/json/availability_zone_client.py
@@ -21,10 +21,10 @@
CONF = config.CONF
-class VolumeAvailabilityZoneClientJSON(rest_client.RestClient):
+class BaseVolumeAvailabilityZoneClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
- super(VolumeAvailabilityZoneClientJSON, self).__init__(
+ super(BaseVolumeAvailabilityZoneClientJSON, self).__init__(
auth_provider)
self.service = CONF.volume.catalog_type
@@ -32,3 +32,9 @@
resp, body = self.get('os-availability-zone')
body = json.loads(body)
return resp, body['availabilityZoneInfo']
+
+
+class VolumeAvailabilityZoneClientJSON(BaseVolumeAvailabilityZoneClientJSON):
+ """
+ Volume V1 availability zone client.
+ """
diff --git a/tempest/services/volume/json/extensions_client.py b/tempest/services/volume/json/extensions_client.py
index 9e182ea..e3ff00b 100644
--- a/tempest/services/volume/json/extensions_client.py
+++ b/tempest/services/volume/json/extensions_client.py
@@ -21,10 +21,10 @@
CONF = config.CONF
-class ExtensionsClientJSON(rest_client.RestClient):
+class BaseExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
- super(ExtensionsClientJSON, self).__init__(auth_provider)
+ super(BaseExtensionsClientJSON, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
def list_extensions(self):
@@ -32,3 +32,9 @@
resp, body = self.get(url)
body = json.loads(body)
return resp, body['extensions']
+
+
+class ExtensionsClientJSON(BaseExtensionsClientJSON):
+ """
+ Volume V1 extensions client.
+ """
diff --git a/tempest/services/volume/v2/json/availability_zone_client.py b/tempest/services/volume/v2/json/availability_zone_client.py
new file mode 100644
index 0000000..047ba1b
--- /dev/null
+++ b/tempest/services/volume/v2/json/availability_zone_client.py
@@ -0,0 +1,26 @@
+# Copyright 2014 IBM Corp.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.services.volume.json import availability_zone_client
+
+
+class VolumeV2AvailabilityZoneClientJSON(
+ availability_zone_client.BaseVolumeAvailabilityZoneClientJSON):
+
+ def __init__(self, auth_provider):
+ super(VolumeV2AvailabilityZoneClientJSON, self).__init__(
+ auth_provider)
+
+ self.api_version = "v2"
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/services/volume/v2/json/extensions_client.py
similarity index 63%
copy from tempest/api_schema/compute/v2/agents.py
copy to tempest/services/volume/v2/json/extensions_client.py
index 30f999f..cc5244c 100644
--- a/tempest/api_schema/compute/v2/agents.py
+++ b/tempest/services/volume/v2/json/extensions_client.py
@@ -1,4 +1,5 @@
-# Copyright 2014 NEC Corporation. All rights reserved.
+# Copyright 2014 IBM Corp.
+# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -12,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import agents
+from tempest.services.volume.json import extensions_client
-create_agent = {
- 'status_code': [200],
- 'response_body': agents.common_create_agent
-}
-delete_agent = {
- 'status_code': [200]
-}
+class ExtensionsV2ClientJSON(extensions_client.BaseExtensionsClientJSON):
+
+ def __init__(self, auth_provider):
+ super(ExtensionsV2ClientJSON, self).__init__(auth_provider)
+
+ self.api_version = "v2"
diff --git a/tempest/services/volume/v2/xml/availability_zone_client.py b/tempest/services/volume/v2/xml/availability_zone_client.py
new file mode 100644
index 0000000..68ca39b
--- /dev/null
+++ b/tempest/services/volume/v2/xml/availability_zone_client.py
@@ -0,0 +1,26 @@
+# Copyright 2014 IBM Corp.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.services.volume.xml import availability_zone_client
+
+
+class VolumeV2AvailabilityZoneClientXML(
+ availability_zone_client.BaseVolumeAvailabilityZoneClientXML):
+
+ def __init__(self, auth_provider):
+ super(VolumeV2AvailabilityZoneClientXML, self).__init__(
+ auth_provider)
+
+ self.api_version = "v2"
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/services/volume/v2/xml/extensions_client.py
similarity index 63%
copy from tempest/api_schema/compute/v2/agents.py
copy to tempest/services/volume/v2/xml/extensions_client.py
index 30f999f..13f333c 100644
--- a/tempest/api_schema/compute/v2/agents.py
+++ b/tempest/services/volume/v2/xml/extensions_client.py
@@ -1,4 +1,5 @@
-# Copyright 2014 NEC Corporation. All rights reserved.
+# Copyright 2014 IBM Corp.
+# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -12,13 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api_schema.compute import agents
+from tempest.services.volume.xml import extensions_client
-create_agent = {
- 'status_code': [200],
- 'response_body': agents.common_create_agent
-}
-delete_agent = {
- 'status_code': [200]
-}
+class ExtensionsV2ClientXML(extensions_client.BaseExtensionsClientXML):
+
+ def __init__(self, auth_provider):
+ super(ExtensionsV2ClientXML, self).__init__(auth_provider)
+
+ self.api_version = "v2"
diff --git a/tempest/services/volume/xml/availability_zone_client.py b/tempest/services/volume/xml/availability_zone_client.py
index e4a004a..a883ef5 100644
--- a/tempest/services/volume/xml/availability_zone_client.py
+++ b/tempest/services/volume/xml/availability_zone_client.py
@@ -22,11 +22,11 @@
CONF = config.CONF
-class VolumeAvailabilityZoneClientXML(rest_client.RestClient):
+class BaseVolumeAvailabilityZoneClientXML(rest_client.RestClient):
TYPE = "xml"
def __init__(self, auth_provider):
- super(VolumeAvailabilityZoneClientXML, self).__init__(
+ super(BaseVolumeAvailabilityZoneClientXML, self).__init__(
auth_provider)
self.service = CONF.volume.catalog_type
@@ -37,3 +37,9 @@
resp, body = self.get('os-availability-zone')
availability_zone = self._parse_array(etree.fromstring(body))
return resp, availability_zone
+
+
+class VolumeAvailabilityZoneClientXML(BaseVolumeAvailabilityZoneClientXML):
+ """
+ Volume V1 availability zone client.
+ """
diff --git a/tempest/services/volume/xml/extensions_client.py b/tempest/services/volume/xml/extensions_client.py
index 2986fcd..fe8b7cb 100644
--- a/tempest/services/volume/xml/extensions_client.py
+++ b/tempest/services/volume/xml/extensions_client.py
@@ -22,11 +22,11 @@
CONF = config.CONF
-class ExtensionsClientXML(rest_client.RestClient):
+class BaseExtensionsClientXML(rest_client.RestClient):
TYPE = "xml"
def __init__(self, auth_provider):
- super(ExtensionsClientXML, self).__init__(auth_provider)
+ super(BaseExtensionsClientXML, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
def _parse_array(self, node):
@@ -40,3 +40,9 @@
resp, body = self.get(url)
body = self._parse_array(etree.fromstring(body))
return resp, body
+
+
+class ExtensionsClientXML(BaseExtensionsClientXML):
+ """
+ Volume V1 extensions client.
+ """
diff --git a/tempest/test.py b/tempest/test.py
index 5b7330b..95ae23f 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -623,7 +623,6 @@
while now < timeout:
if func():
return True
- LOG.debug("Sleeping for %d seconds", sleep_for)
time.sleep(sleep_for)
now = time.time()
return False
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
index 1dcddad..6a2e335 100644
--- a/tempest/tests/test_auth.py
+++ b/tempest/tests/test_auth.py
@@ -59,12 +59,24 @@
obviously don't test not implemented method or the ones which strongly
depends on them.
"""
- _auth_provider_class = auth.AuthProvider
- def test_check_credentials_class(self):
- self.assertRaises(NotImplementedError,
- self.auth_provider.check_credentials,
- auth.Credentials())
+ class FakeAuthProviderImpl(auth.AuthProvider):
+ def _decorate_request():
+ pass
+
+ def _fill_credentials():
+ pass
+
+ def _get_auth():
+ pass
+
+ def base_url():
+ pass
+
+ def is_expired():
+ pass
+
+ _auth_provider_class = FakeAuthProviderImpl
def test_check_credentials_bad_type(self):
self.assertFalse(self.auth_provider.check_credentials([]))
@@ -74,16 +86,6 @@
auth_provider = self._auth(credentials={})
self.assertIsInstance(auth_provider.credentials, auth.Credentials)
- def test_instantiate_with_bad_credentials_type(self):
- """
- Assure that credentials with bad type fail with TypeError
- """
- self.assertRaises(TypeError, self._auth, [])
-
- def test_auth_data_property(self):
- self.assertRaises(NotImplementedError, getattr, self.auth_provider,
- 'auth_data')
-
def test_auth_data_property_when_cache_exists(self):
self.auth_provider.cache = 'foo'
self.useFixture(mockpatch.PatchObject(self.auth_provider,
@@ -110,9 +112,10 @@
self.assertIsNone(self.auth_provider.alt_part)
self.assertIsNone(self.auth_provider.alt_auth_data)
- def test_fill_credentials(self):
- self.assertRaises(NotImplementedError,
- self.auth_provider.fill_credentials)
+ def test_auth_class(self):
+ self.assertRaises(TypeError,
+ auth.AuthProvider,
+ fake_credentials.FakeCredentials)
class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
diff --git a/tox.ini b/tox.ini
index 4f2465a..9c32121 100644
--- a/tox.ini
+++ b/tox.ini
@@ -6,23 +6,28 @@
[testenv]
setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/test_discover
+ PYTHONHASHSEED=0
usedevelop = True
install_command = pip install -U {opts} {packages}
[testenv:py26]
setenv = OS_TEST_PATH=./tempest/tests
+ PYTHONHASHSEED=0
commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
[testenv:py33]
setenv = OS_TEST_PATH=./tempest/tests
+ PYTHONHASHSEED=0
commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
[testenv:py27]
setenv = OS_TEST_PATH=./tempest/tests
+ PYTHONHASHSEED=0
commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
[testenv:cover]
setenv = OS_TEST_PATH=./tempest/tests
+ PYTHONHASHSEED=0
commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
[testenv:all]