Merge "Fix setup_test_v3_user method in identity base.py"
diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample
index 3b468f1..cdeedef 100644
--- a/etc/logging.conf.sample
+++ b/etc/logging.conf.sample
@@ -1,46 +1,40 @@
[loggers]
-keys=root,tempest,tempest_stress
+keys=root,tempest_stress
[handlers]
-keys=file,syslog,devel
+keys=file,devel,syslog
[formatters]
-keys=default,tests
+keys=simple,tests
[logger_root]
-level=NOTSET
-handlers=syslog
-
-[logger_tempest]
level=DEBUG
handlers=file
-qualname=tempest
[logger_tempest_stress]
-level=INFO
+level=DEBUG
handlers=file,devel
qualname=tempest.stress
[handler_file]
class=FileHandler
level=DEBUG
+args=('tempest.log', 'w+')
formatter=tests
-args=('tempest.log', 'w')
[handler_syslog]
class=handlers.SysLogHandler
level=ERROR
-formatter = default
args = ('/dev/log', handlers.SysLogHandler.LOG_USER)
[handler_devel]
class=StreamHandler
level=DEBUG
-formatter=default
args=(sys.stdout,)
-
-[formatter_default]
-format=%(name)s: %(levelname)s: %(message)s
+formatter=simple
[formatter_tests]
-class = tempest.common.log.TestsFormatter
+class = tempest.openstack.common.log.ContextFormatter
+
+[formatter_simple]
+format=%(asctime)s.%(msecs)03d %(process)d %(levelname)s: %(message)s
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 1d571c0..eb2340a 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -105,6 +105,10 @@
# value)
#catalog_type=baremetal
+# The endpoint type to use for the baremetal provisioning
+# service. (string value)
+#endpoint_type=publicURL
+
[boto]
@@ -355,6 +359,10 @@
# iSCSI volumes (boolean value)
#block_migrate_cinder_iscsi=false
+# Enable VNC console. This configuration value should be same
+# as [nova.vnc]->vnc_enabled in nova.conf (boolean value)
+#vnc_console=false
+
[dashboard]
@@ -378,6 +386,24 @@
# Catalog type of the data processing service. (string value)
#catalog_type=data_processing
+# The endpoint type to use for the data processing service.
+# (string value)
+#endpoint_type=publicURL
+
+
+[database]
+
+#
+# Options defined in tempest.config
+#
+
+# Catalog type of the Database service. (string value)
+#catalog_type=database
+
+# Valid primary flavor to use in database tests. (string
+# value)
+#db_flavor_ref=1
+
[debug]
@@ -536,6 +562,16 @@
#ssh_user_regex=[["^.*[Cc]irros.*$", "root"]]
+[negative]
+
+#
+# Options defined in tempest.config
+#
+
+# Test generator class for all negative tests (string value)
+#test_generator=tempest.common.generator.negative_generator.NegativeTestGenerator
+
+
[network]
#
@@ -562,9 +598,6 @@
# The mask bits for tenant ipv4 subnets (integer value)
#tenant_network_mask_bits=28
-# Allow the execution of IPv6 tests (boolean value)
-#ipv6_enabled=true
-
# The cidr block to allocate tenant ipv6 subnets from (string
# value)
#tenant_network_v6_cidr=2003::/64
@@ -591,6 +624,9 @@
# Options defined in tempest.config
#
+# Allow the execution of IPv6 tests (boolean value)
+#ipv6=true
+
# A list of enabled network extensions with a special entry
# all which indicates every extension is enabled (list value)
#api_extensions=all
@@ -627,6 +663,9 @@
# creating containers (string value)
#operator_role=Member
+# User role that has reseller admin (string value)
+#reseller_admin_role=ResellerAdmin
+
[object-storage-feature-enabled]
@@ -664,7 +703,7 @@
# Timeout in seconds to wait for a stack to build. (integer
# value)
-#build_timeout=300
+#build_timeout=600
# Instance type for tests. Needs to be big enough for a full
# OS plus the test workload (string value)
@@ -758,6 +797,10 @@
# value)
#ironic=false
+# Whether or not Trove is expected to be available (boolean
+# value)
+#trove=false
+
[stress]
@@ -816,6 +859,10 @@
# Catalog type of the Telemetry service. (string value)
#catalog_type=metering
+# The endpoint type to use for the telemetry service. (string
+# value)
+#endpoint_type=publicURL
+
[volume]
diff --git a/requirements.txt b/requirements.txt
index a08a437..48d1b12 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-pbr>=0.5.21,<1.0
+pbr>=0.6,<1.0
anyjson>=0.3.3
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
@@ -8,18 +8,18 @@
paramiko>=1.9.0
netaddr>=0.7.6
python-glanceclient>=0.9.0
-python-keystoneclient>=0.4.2
-python-novaclient>=2.15.0
-python-neutronclient>=2.3.3,<3
+python-keystoneclient>=0.6.0
+python-novaclient>=2.17.0
+python-neutronclient>=2.3.4,<3
python-cinderclient>=1.0.6
python-heatclient>=0.2.3
-python-savannaclient>=0.4.1
-python-swiftclient>=1.5
+python-savannaclient>=0.5.0
+python-swiftclient>=1.6
testresources>=0.2.4
keyring>=1.6.1,<2.0,>=2.1
-testrepository>=0.0.17
+testrepository>=0.0.18
oslo.config>=1.2.0
-six>=1.4.1
+six>=1.5.2
iso8601>=0.1.8
fixtures>=0.3.14
testscenarios>=0.4
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 08d8a0d..6797005 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -26,7 +26,6 @@
"""
_host_key = 'OS-EXT-SRV-ATTR:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -47,7 +46,7 @@
resp, aggregate = self.client.create_aggregate(name=aggregate_name)
self.assertEqual(200, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
- self.assertEqual(None, aggregate['availability_zone'])
+ self.assertIsNone(aggregate['availability_zone'])
resp, _ = self.client.delete_aggregate(aggregate['id'])
self.assertEqual(200, resp.status)
@@ -175,7 +174,7 @@
self.assertEqual(1, len(aggs))
agg = aggs[0]
self.assertEqual(aggregate_name, agg['name'])
- self.assertEqual(None, agg['availability_zone'])
+ self.assertIsNone(agg['availability_zone'])
self.assertIn(self.host, agg['hosts'])
@attr(type='gate')
@@ -190,7 +189,7 @@
resp, body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, body['name'])
- self.assertEqual(None, body['availability_zone'])
+ self.assertIsNone(body['availability_zone'])
self.assertIn(self.host, body['hosts'])
@attr(type='gate')
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 7d92532..3d34d47 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -26,8 +26,6 @@
Tests Aggregates API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AggregatesAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 283a45a..1387261 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
index d13618c..8cc8bce 100644
--- a/tempest/api/compute/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index cfb2f0e..00bb9c3 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -21,7 +21,6 @@
class FixedIPsTestJson(base.BaseV2ComputeAdminTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index def9810..0faedb2 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -21,7 +21,6 @@
class FixedIPsNegativeTestJson(base.BaseV2ComputeAdminTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 3e13bf8..05b763a 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index da11ab5..4804ce4 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -25,8 +25,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index c4d54b6..8fe3331 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -28,8 +28,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 1afa693..91145ec 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -26,8 +26,6 @@
GET Flavor Extra specs can be performed even by without admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index cdf97cc..a139c2f 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -27,8 +27,6 @@
SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index ad4ceeb..49d49ef 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index a3b4b47..b4b3139 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -23,8 +23,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index cb034c9..0f26e84 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -24,8 +24,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 989c0d8..4e1b289 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -23,8 +23,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index e41bd18..be0153b 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -27,8 +27,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index c617178..13f504f 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -22,8 +22,6 @@
class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(InstanceUsageAuditLogTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index 10bb1aa..e128d0c 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -23,8 +23,6 @@
class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(InstanceUsageAuditLogNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 81b0328..5af091e 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -19,7 +19,6 @@
class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index 4c4acd4..5b2b5fd 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -22,7 +22,6 @@
class QuotasAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 0cfa344..69ba2c2 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -24,7 +24,6 @@
class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 8a5f1a5..40a4df7 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -25,7 +25,6 @@
"""
_host_key = 'OS-EXT-SRV-ATTR:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -175,6 +174,16 @@
rebuilt_image_id = server['image']['id']
self.assertEqual(self.image_ref_alt, rebuilt_image_id)
+ @test.attr(type='gate')
+ def test_reset_network_inject_network_info(self):
+ # Reset Network of a Server
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, server_body = self.client.reset_network(server['id'])
+ self.assertEqual(202, resp.status)
+ # Inject the Network Info into Server
+ resp, server_body = self.client.inject_network_info(server['id'])
+ self.assertEqual(202, resp.status)
+
class ServersAdminTestXML(ServersAdminTestJSON):
_host_key = (
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 9580a06..dff4aaa 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -26,8 +26,6 @@
Tests Servers API using admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServersAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index ac800fb..3e45d65 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -24,8 +24,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index a1809c4..a4bf754 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -23,8 +23,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index dcb9aed..2f1391b 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -22,8 +22,6 @@
class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(TenantUsagesTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
index 2a30348..4ad3e1a 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -22,8 +22,6 @@
class TenantUsagesNegativeTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(TenantUsagesNegativeTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 72bb723..398297d 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -206,6 +206,8 @@
class BaseV2ComputeTest(BaseComputeTest):
+ _interface = "json"
+
@classmethod
def setUpClass(cls):
# By default compute tests do not create network resources
@@ -303,6 +305,8 @@
class BaseV3ComputeTest(BaseComputeTest):
+ _interface = "json"
+
@classmethod
def setUpClass(cls):
# By default compute tests do not create network resources
@@ -311,14 +315,14 @@
"%s will be removed shortly" % cls.__name__)
raise cls.skipException(skip_msg)
- cls.set_network_resources()
- super(BaseV3ComputeTest, cls).setUpClass()
if not CONF.compute_feature_enabled.api_v3:
- cls.tearDownClass()
skip_msg = ("%s skipped as nova v3 api is not available" %
cls.__name__)
raise cls.skipException(skip_msg)
+ cls.set_network_resources()
+ super(BaseV3ComputeTest, cls).setUpClass()
+
cls.servers_client = cls.os.servers_v3_client
cls.images_client = cls.os.image_client
cls.flavors_client = cls.os.flavors_v3_client
diff --git a/tempest/api/compute/certificates/test_certificates.py b/tempest/api/compute/certificates/test_certificates.py
index 79619bc..01fdc7c 100644
--- a/tempest/api/compute/certificates/test_certificates.py
+++ b/tempest/api/compute/certificates/test_certificates.py
@@ -18,7 +18,6 @@
class CertificatesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@attr(type='gate')
def test_create_and_get_root_certificate(self):
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index b0a7fed..98a8e29 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -18,7 +18,6 @@
class FlavorsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index 8ac6182..4ba5023 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -24,7 +24,6 @@
class FlavorsListNegativeTestJSON(base.BaseV2ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'compute'
_schema_file = 'compute/flavors/flavors_list.json'
@@ -37,7 +36,6 @@
class FlavorDetailsNegativeTestJSON(base.BaseV2ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'compute'
_schema_file = 'compute/flavors/flavor_details.json'
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index ea785b3..c0f7af0 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -20,7 +20,6 @@
class FloatingIPsTestJSON(base.BaseFloatingIPsTest):
- _interface = 'json'
server_id = None
floating_ip = None
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index f24343b..0c3663e 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -25,7 +25,6 @@
class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest):
- _interface = 'json'
server_id = None
@classmethod
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index fa2d558..d69e33c 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -18,7 +18,6 @@
class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index 8d60e7d..5701be8 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -25,7 +25,6 @@
class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 4115d65..ad211ce 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -22,7 +22,6 @@
class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 4878936..7776c57 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -20,7 +20,6 @@
class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 8964dcf..ed316ef 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -22,7 +22,6 @@
class ImagesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 7d5593d..b152c3c 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -26,7 +26,6 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 82955d8..41a0590 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -27,7 +27,6 @@
class ImagesOneServerNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
def tearDown(self):
"""Terminate test instances created after a test is executed."""
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 9cff3a8..86ee4a4 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -24,7 +24,6 @@
class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py
index 3b19d3c..80d59a7 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -22,7 +22,6 @@
class ListImageFiltersNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index ed38442..4074a7a 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -21,7 +21,6 @@
class ListImagesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index d4554bc..67fafed 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -19,7 +19,6 @@
class KeyPairsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 93b0692..a91a9c2 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -21,7 +21,6 @@
class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 0e234fb..d64fd57 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -18,7 +18,6 @@
class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index ac8af3b..f88699b 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -19,7 +19,6 @@
class AbsoluteLimitsNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 17bb489..b04ab8a 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -21,7 +21,6 @@
class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 680bc2f..0b53037 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
from tempest import config
@@ -24,22 +22,26 @@
CONF = config.CONF
+def not_existing_id():
+ if CONF.service_available.neutron:
+ return data_utils.rand_uuid()
+ else:
+ return data_utils.rand_int_id(start=999)
+
+
class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
super(SecurityGroupRulesNegativeTestJSON, cls).setUpClass()
cls.client = cls.security_groups_client
- @test.skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_non_existent_id(self):
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
# Adding rules to the non existent Security Group id
- parent_group_id = data_utils.rand_int_id(start=999)
+ parent_group_id = not_existing_id()
ip_protocol = 'tcp'
from_port = 22
to_port = 22
@@ -47,8 +49,6 @@
self.client.create_security_group_rule,
parent_group_id, ip_protocol, from_port, to_port)
- @testtools.skipIf(CONF.service_available.neutron,
- "Neutron not check the security_group_id")
@test.attr(type=['negative', 'smoke'])
def test_create_security_group_rule_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
@@ -146,13 +146,11 @@
self.client.create_security_group_rule,
secgroup_id, ip_protocol, from_port, to_port)
- @test.skip_because(bug="1182384",
- condition=CONF.service_available.neutron)
@test.attr(type=['negative', 'smoke'])
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
- non_existent_rule_id = data_utils.rand_int_id(start=999)
+ non_existent_rule_id = not_existing_id()
self.assertRaises(exceptions.NotFound,
self.client.delete_security_group_rule,
non_existent_rule_id)
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index b376edc..538ebc6 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -20,14 +20,13 @@
class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
super(SecurityGroupsTestJSON, cls).setUpClass()
cls.client = cls.security_groups_client
- @test.attr(type='gate')
+ @test.attr(type='smoke')
def test_security_groups_create_list_delete(self):
# Positive test:Should return the list of Security Groups
# Create 3 Security Groups
@@ -59,7 +58,7 @@
"list" % ', '.join(m_group['name']
for m_group in deleted_sgs))
- @test.attr(type='gate')
+ @test.attr(type='smoke')
def test_security_group_create_get_delete(self):
# Security Group should be created, fetched and deleted
s_name = data_utils.rand_name('securitygroup-')
@@ -77,7 +76,7 @@
"The fetched Security Group is different "
"from the created Group")
- @test.attr(type='gate')
+ @test.attr(type='smoke')
def test_server_security_groups(self):
# Checks that security groups may be added and linked to a server
# and not deleted if the server is active.
@@ -123,7 +122,7 @@
self.client.delete_security_group(sg2['id'])
self.assertEqual(202, resp.status)
- @test.attr(type='gate')
+ @test.attr(type='smoke')
def test_update_security_groups(self):
# Update security group name and description
# Create a security group
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index edf38e9..aa2d32e 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -25,7 +25,6 @@
class SecurityGroupsNegativeTestJSON(base.BaseSecurityGroupsTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -57,7 +56,7 @@
@test.skip_because(bug="1161411",
condition=CONF.service_available.neutron)
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_security_group_create_with_invalid_group_name(self):
# Negative test: Security Group should not be created with group name
# as an empty string/with white spaces/chars more than 255
@@ -77,7 +76,7 @@
@test.skip_because(bug="1161411",
condition=CONF.service_available.neutron)
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_security_group_create_with_invalid_group_description(self):
# Negative test:Security Group should not be created with description
# as an empty string/with white spaces/chars more than 255
@@ -96,7 +95,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron allows duplicate names for security groups")
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_security_group_create_with_duplicate_name(self):
# Negative test:Security Group with duplicate name should not
# be created
@@ -110,7 +109,7 @@
self.client.create_security_group, s_name,
s_description)
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_delete_the_default_security_group(self):
# Negative test:Deletion of the "default" Security Group should Fail
default_security_group_id = None
@@ -131,7 +130,7 @@
self.assertRaises(exceptions.NotFound,
self.client.delete_security_group, non_exist_id)
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_delete_security_group_without_passing_id(self):
# Negative test:Deletion of a Security Group with out passing ID
# should Fail
@@ -140,7 +139,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_id")
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_update_security_group_with_invalid_sg_id(self):
# Update security_group with invalid sg_id should fail
s_name = data_utils.rand_name('sg-')
@@ -153,7 +152,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_name")
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_update_security_group_with_invalid_sg_name(self):
# Update security_group with invalid sg_name should fail
resp, securitygroup = self.create_security_group()
@@ -168,7 +167,7 @@
@testtools.skipIf(CONF.service_available.neutron,
"Neutron not check the security_group_description")
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_update_security_group_with_invalid_sg_des(self):
# Update security_group with invalid sg_des should fail
resp, securitygroup = self.create_security_group()
@@ -181,7 +180,7 @@
self.client.update_security_group,
securitygroup_id, description=s_new_des)
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'smoke'])
def test_update_non_existent_security_group(self):
# Update a non-existent Security Group should Fail
non_exist_id = self._generate_a_non_existent_security_group_id()
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 9cdac55..a21c411 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -24,7 +24,6 @@
class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -48,6 +47,7 @@
def _create_server_get_interfaces(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, ifs = self.client.list_interfaces(server['id'])
+ self.assertEqual(200, resp.status)
resp, body = self.client.wait_for_interface_status(
server['id'], ifs[0]['port_id'], 'ACTIVE')
ifs[0]['port_state'] = body['port_state']
@@ -55,6 +55,7 @@
def _test_create_interface(self, server):
resp, iface = self.client.create_interface(server['id'])
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface)
@@ -64,6 +65,7 @@
network_id = ifs[0]['net_id']
resp, iface = self.client.create_interface(server['id'],
network_id=network_id)
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
@@ -73,12 +75,14 @@
iface = ifs[0]
resp, _iface = self.client.show_interface(server['id'],
iface['port_id'])
+ self.assertEqual(200, resp.status)
self.assertEqual(iface, _iface)
def _test_delete_interface(self, server, ifs):
# NOTE(danms): delete not the first or last, but one in the middle
iface = ifs[1]
- self.client.delete_interface(server['id'], iface['port_id'])
+ resp, _ = self.client.delete_interface(server['id'], iface['port_id'])
+ self.assertEqual(202, resp.status)
_ifs = self.client.list_interfaces(server['id'])[1]
start = int(time.time())
@@ -123,6 +127,33 @@
_ifs = self._test_delete_interface(server, ifs)
self.assertEqual(len(ifs) - 1, len(_ifs))
+ @attr(type='gate')
+ def test_add_remove_fixed_ip(self):
+ # Add and Remove the fixed IP to server.
+ server, ifs = self._create_server_get_interfaces()
+ interface_count = len(ifs)
+ self.assertTrue(interface_count > 0)
+ self._check_interface(ifs[0])
+ network_id = ifs[0]['net_id']
+ resp, body = self.client.add_fixed_ip(server['id'],
+ network_id)
+ self.assertEqual(202, resp.status)
+ # Remove the fixed IP from server.
+ server_resp, server_detail = self.os.servers_client.get_server(
+ server['id'])
+ # Get the Fixed IP from server.
+ fixed_ip = None
+ for ip_set in server_detail['addresses']:
+ for ip in server_detail['addresses'][ip_set]:
+ if ip['OS-EXT-IPS:type'] == 'fixed':
+ fixed_ip = ip['addr']
+ break
+ if fixed_ip is not None:
+ break
+ resp, body = self.client.remove_fixed_ip(server['id'],
+ fixed_ip)
+ self.assertEqual(202, resp.status)
+
class AttachInterfacesTestXML(AttachInterfacesTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 748ba41..7b12555 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index f705308..ddf37ce 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -28,7 +28,6 @@
class ServersTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
@@ -110,7 +109,6 @@
class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index ec40ce0..5e011dd 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -13,6 +13,8 @@
# 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 test
@@ -23,7 +25,6 @@
class DeleteServersTestJSON(base.BaseV2ComputeTest):
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances"
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -36,6 +37,7 @@
resp, server = self.create_test_server(wait_until='BUILD')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_active_server(self):
@@ -43,6 +45,7 @@
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shutoff_state(self):
@@ -52,6 +55,7 @@
self.client.wait_for_server_status(server['id'], 'SHUTOFF')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_pause_state(self):
@@ -61,6 +65,7 @@
self.client.wait_for_server_status(server['id'], 'PAUSED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
@@ -79,12 +84,25 @@
'SHELVED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
+
+ @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+ 'Resize not available.')
+ @test.attr(type='gate')
+ def test_delete_server_while_in_verify_resize_state(self):
+ # Delete a server while it's VM state is VERIFY_RESIZE
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances".
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -103,6 +121,8 @@
self.assertEqual(server['status'], 'ERROR')
resp, _ = self.non_admin_client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'],
+ ignore_error=True)
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index 0d79161..75a1234 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -23,7 +23,6 @@
class ServerDiskConfigTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index 667b84f..dd31165 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -18,7 +18,6 @@
class InstanceActionsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index 2503eb2..e67b69d 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -20,7 +20,6 @@
class InstanceActionsNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index fc0bb9f..837114c 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -24,7 +24,6 @@
class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index a0aefd8..26c5887 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,13 +15,14 @@
import datetime
+from six import moves
+
from tempest.api.compute import base
from tempest import exceptions
from tempest.test import attr
class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
@@ -36,7 +37,7 @@
cls.existing_fixtures = []
cls.deleted_fixtures = []
cls.start_time = datetime.datetime.utcnow()
- for x in xrange(2):
+ for x in moves.xrange(2):
resp, srv = cls.create_test_server()
cls.existing_fixtures.append(srv)
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index cf4d646..40b9c16 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -19,7 +19,6 @@
class MultipleCreateTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
_name = 'multiple-create-test'
def _generate_name(self):
diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py
index e289717..3dea521 100644
--- a/tempest/api/compute/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/servers/test_multiple_create_negative.py
@@ -20,7 +20,6 @@
class MultipleCreateNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
_name = 'multiple-create-test'
def _generate_name(self):
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index adf522b..bde0f57 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -29,7 +29,6 @@
class ServerActionsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
resize_available = CONF.compute_feature_enabled.resize
run_ssh = CONF.compute.run_ssh
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d5528c4..0c14dc2 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -21,7 +21,6 @@
class ServerAddressesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index c69c5eb..d37f7fa 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -19,7 +19,6 @@
class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index ad4931c..448b8ff 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -18,7 +18,6 @@
class ServerMetadataTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index e52ea4a..8b69c78 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -20,7 +20,6 @@
class ServerMetadataNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index 06697a5..ad78f65 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -19,7 +19,6 @@
class ServerPasswordTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index bb14a4c..b581faf 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -21,7 +21,6 @@
class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 826317d..48f2e14 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -19,7 +19,6 @@
class ServerRescueTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index ffd79fa..277f28f 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -20,7 +20,6 @@
class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 7167a8b..9674463 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -19,7 +19,6 @@
class ServersTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index e0181b9..4cccbd6 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -27,7 +27,6 @@
class ServersNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
def setUp(self):
super(ServersNegativeTestJSON, self).setUp()
diff --git a/tempest/api/compute/servers/test_servers_negative_new.py b/tempest/api/compute/servers/test_servers_negative_new.py
index 2b2fcf1..42ace76 100644
--- a/tempest/api/compute/servers/test_servers_negative_new.py
+++ b/tempest/api/compute/servers/test_servers_negative_new.py
@@ -24,7 +24,6 @@
class GetConsoleOutputNegativeTestJSON(base.BaseV2ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'compute'
_schema_file = 'compute/servers/get_console_output.json'
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 95703d4..6354996 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -23,7 +23,6 @@
class VirtualInterfacesTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index f73218c..87289d8 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -21,7 +21,6 @@
class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index ed72061..fd73cc5 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -27,7 +27,6 @@
class AuthorizationTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 55146e5..674ca9a 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -26,7 +26,6 @@
class ExtensionsTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@test.attr(type='gate')
def test_list_extensions(self):
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index 1df4159..1319f68 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -25,7 +25,6 @@
class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index da0e4c4..c10818e 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -25,7 +25,6 @@
class LiveBlockMigrationNegativeTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -38,7 +37,7 @@
def _migrate_server_to(self, server_id, dest_host):
_resp, body = self.admin_servers_client.live_migrate_server(
server_id, dest_host,
- self.config.compute_feature_enabled.
+ CONF.compute_feature_enabled.
block_migration_for_live_migration)
return body
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index 112e4fb..b97ab2c 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -18,7 +18,6 @@
class QuotasTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/admin/test_aggregates.py b/tempest/api/compute/v3/admin/test_aggregates.py
index 20093e4..e5ec08b 100644
--- a/tempest/api/compute/v3/admin/test_aggregates.py
+++ b/tempest/api/compute/v3/admin/test_aggregates.py
@@ -26,7 +26,6 @@
"""
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -47,7 +46,7 @@
resp, aggregate = self.client.create_aggregate(name=aggregate_name)
self.assertEqual(201, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
- self.assertEqual(None, aggregate['availability_zone'])
+ self.assertIsNone(aggregate['availability_zone'])
resp, _ = self.client.delete_aggregate(aggregate['id'])
self.assertEqual(204, resp.status)
@@ -176,7 +175,7 @@
self.assertEqual(1, len(aggs))
agg = aggs[0]
self.assertEqual(aggregate_name, agg['name'])
- self.assertEqual(None, agg['availability_zone'])
+ self.assertIsNone(agg['availability_zone'])
self.assertIn(self.host, agg['hosts'])
@test.attr(type='gate')
@@ -191,7 +190,7 @@
resp, body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, body['name'])
- self.assertEqual(None, body['availability_zone'])
+ self.assertIsNone(body['availability_zone'])
self.assertIn(self.host, body['hosts'])
@test.attr(type='gate')
diff --git a/tempest/api/compute/v3/admin/test_aggregates_negative.py b/tempest/api/compute/v3/admin/test_aggregates_negative.py
index 5700460..1505f74 100644
--- a/tempest/api/compute/v3/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/v3/admin/test_aggregates_negative.py
@@ -26,8 +26,6 @@
Tests Aggregates API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AggregatesAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index 176751f..9ca8953 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_availability_zone_negative.py b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
index 180f298..f3af6df 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
@@ -24,8 +24,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 597c99b..401eb85 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index 43dc726..03305ff 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -25,8 +25,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 6a2e826..334d124 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -28,8 +28,6 @@
Add and remove Flavor Access require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAccessNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
index 4d22027..29cd8db 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -26,8 +26,6 @@
GET Flavor Extra specs can be performed even by without admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
index 98e6e3d..e9c04a3 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -27,8 +27,6 @@
SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsExtraSpecsNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index f54de79..3f8a2da 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -27,8 +27,6 @@
Tests Flavors API Create and Delete that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(FlavorsAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hosts.py b/tempest/api/compute/v3/admin/test_hosts.py
index 2c9369f..8cb1f23 100644
--- a/tempest/api/compute/v3/admin/test_hosts.py
+++ b/tempest/api/compute/v3/admin/test_hosts.py
@@ -23,8 +23,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hosts_negative.py b/tempest/api/compute/v3/admin/test_hosts_negative.py
index ac5d7de..79cd97f 100644
--- a/tempest/api/compute/v3/admin/test_hosts_negative.py
+++ b/tempest/api/compute/v3/admin/test_hosts_negative.py
@@ -24,8 +24,6 @@
Tests hosts API using admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HostsAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
index 0f96bba..93d4441 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -23,8 +23,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_hypervisor_negative.py b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
index aee354a..45642b7 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
@@ -27,8 +27,6 @@
Tests Hypervisors API that require admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(HypervisorAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index b388b70..0c138bb 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -22,7 +22,6 @@
class QuotasAdminV3Test(base.BaseV3ComputeAdminTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
index c9f14f8..d138e80 100644
--- a/tempest/api/compute/v3/admin/test_quotas_negative.py
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -20,7 +20,6 @@
class QuotasAdminNegativeV3Test(base.BaseV3ComputeAdminTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 0dc3dbc..fb8afe4 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -25,7 +25,6 @@
"""
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -175,3 +174,13 @@
resp, server = self.non_admin_client.get_server(rebuilt_server['id'])
rebuilt_image_id = server['image']['id']
self.assertEqual(self.image_ref_alt, rebuilt_image_id)
+
+ @test.attr(type='gate')
+ def test_reset_network_inject_network_info(self):
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ # Reset Network of a Server
+ resp, server_body = self.client.reset_network(server['id'])
+ self.assertEqual(202, resp.status)
+ # Inject the Network Info into Server
+ resp, server = self.client.inject_network_info(server['id'])
+ self.assertEqual(202, resp.status)
diff --git a/tempest/api/compute/v3/admin/test_servers_negative.py b/tempest/api/compute/v3/admin/test_servers_negative.py
index a6a5736..cc1be4e 100644
--- a/tempest/api/compute/v3/admin/test_servers_negative.py
+++ b/tempest/api/compute/v3/admin/test_servers_negative.py
@@ -26,8 +26,6 @@
Tests Servers API using admin privileges
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServersAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_services.py b/tempest/api/compute/v3/admin/test_services.py
index 8d6e549..914a2a4 100644
--- a/tempest/api/compute/v3/admin/test_services.py
+++ b/tempest/api/compute/v3/admin/test_services.py
@@ -24,8 +24,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_services_negative.py b/tempest/api/compute/v3/admin/test_services_negative.py
index c270842..3168af2 100644
--- a/tempest/api/compute/v3/admin/test_services_negative.py
+++ b/tempest/api/compute/v3/admin/test_services_negative.py
@@ -25,8 +25,6 @@
Tests Services API. List and Enable/Disable require admin privileges.
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(ServicesAdminNegativeV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/certificates/test_certificates.py b/tempest/api/compute/v3/certificates/test_certificates.py
index 5c980c0..ce025fc 100644
--- a/tempest/api/compute/v3/certificates/test_certificates.py
+++ b/tempest/api/compute/v3/certificates/test_certificates.py
@@ -18,7 +18,6 @@
class CertificatesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@attr(type='gate')
def test_create_and_get_root_certificate(self):
diff --git a/tempest/api/compute/v3/flavors/test_flavors.py b/tempest/api/compute/v3/flavors/test_flavors.py
index 812358f..a0bbba6 100644
--- a/tempest/api/compute/v3/flavors/test_flavors.py
+++ b/tempest/api/compute/v3/flavors/test_flavors.py
@@ -18,7 +18,6 @@
class FlavorsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/flavors/test_flavors_negative.py b/tempest/api/compute/v3/flavors/test_flavors_negative.py
index 3d4100a..346f6d6 100644
--- a/tempest/api/compute/v3/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/v3/flavors/test_flavors_negative.py
@@ -24,7 +24,6 @@
class FlavorsListNegativeV3Test(base.BaseV3ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'computev3'
_schema_file = 'compute/flavors/flavors_list_v3.json'
@@ -37,7 +36,6 @@
class FlavorDetailsNegativeV3Test(base.BaseV3ComputeTest,
test.NegativeAutoTest):
- _interface = 'json'
_service = 'computev3'
_schema_file = 'compute/flavors/flavor_details_v3.json'
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index b045630..bb81626 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -15,14 +15,12 @@
from tempest.api.compute import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
from tempest import test
CONF = config.CONF
class ImagesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -31,42 +29,8 @@
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
cls.client = cls.images_client
- cls.servers_client = cls.servers_client
- def __create_image__(self, server_id, name, meta=None):
- resp, body = self.servers_client.create_image(server_id, name, meta)
- image_id = data_utils.parse_image_id(resp['location'])
- self.addCleanup(self.client.delete_image, image_id)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
- return resp, body
-
- @test.attr(type=['negative', 'gate'])
- def test_create_image_from_deleted_server(self):
- # An image should not be created if the server instance is removed
- resp, server = self.create_test_server(wait_until='ACTIVE')
-
- # Delete server before trying to create server
- self.servers_client.delete_server(server['id'])
- self.servers_client.wait_for_server_termination(server['id'])
- # Create a new image after server is deleted
- name = data_utils.rand_name('image')
- meta = {'image_type': 'test'}
- self.assertRaises(exceptions.NotFound,
- self.__create_image__,
- server['id'], name, meta)
-
- @test.attr(type=['negative', 'gate'])
- def test_create_image_from_invalid_server(self):
- # An image should not be created with invalid server id
- # Create a new image with invalid server id
- name = data_utils.rand_name('image')
- meta = {'image_type': 'test'}
- resp = {}
- resp['status'] = None
- self.assertRaises(exceptions.NotFound, self.__create_image__,
- '!@#$%^&*()', name, meta)
-
- @test.attr(type=['negative', 'gate'])
+ @test.attr(type='gate')
def test_create_image_from_stopped_server(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
self.servers_client.stop(server['id'])
@@ -90,21 +54,3 @@
wait_until='queued')
resp, body = self.client.delete_image(image['id'])
self.assertEqual('200', resp['status'])
-
- @test.attr(type=['negative', 'gate'])
- def test_create_image_specify_uuid_35_characters_or_less(self):
- # Return an error if Image ID passed is 35 characters or less
- snapshot_name = data_utils.rand_name('test-snap-')
- test_uuid = ('a' * 35)
- self.assertRaises(exceptions.NotFound,
- self.servers_client.create_image,
- test_uuid, snapshot_name)
-
- @test.attr(type=['negative', 'gate'])
- def test_create_image_specify_uuid_37_characters_or_more(self):
- # Return an error if Image ID passed is 37 characters or more
- snapshot_name = data_utils.rand_name('test-snap-')
- test_uuid = ('a' * 37)
- self.assertRaises(exceptions.NotFound,
- self.servers_client.create_image,
- test_uuid, snapshot_name)
diff --git a/tempest/api/compute/v3/images/test_images_negative.py b/tempest/api/compute/v3/images/test_images_negative.py
new file mode 100644
index 0000000..c38373f
--- /dev/null
+++ b/tempest/api/compute/v3/images/test_images_negative.py
@@ -0,0 +1,82 @@
+# Copyright 2014 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+from tempest import test
+
+CONF = config.CONF
+
+
+class ImagesNegativeV3Test(base.BaseV3ComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(ImagesNegativeV3Test, cls).setUpClass()
+ if not CONF.service_available.glance:
+ skip_msg = ("%s skipped as glance is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+ cls.client = cls.images_client
+
+ def __create_image__(self, server_id, name, meta=None):
+ resp, body = self.servers_client.create_image(server_id, name, meta)
+ image_id = data_utils.parse_image_id(resp['location'])
+ self.addCleanup(self.client.delete_image, image_id)
+ self.client.wait_for_image_status(image_id, 'ACTIVE')
+ return resp, body
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_image_from_deleted_server(self):
+ # An image should not be created if the server instance is removed
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+
+ # Delete server before trying to create server
+ self.servers_client.delete_server(server['id'])
+ self.servers_client.wait_for_server_termination(server['id'])
+ # Create a new image after server is deleted
+ name = data_utils.rand_name('image')
+ meta = {'image_type': 'test'}
+ self.assertRaises(exceptions.NotFound,
+ self.__create_image__,
+ server['id'], name, meta)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_image_from_nonexistent_server(self):
+ # An image should not be created with invalid server id
+ # Create a new image with invalid server id
+ nonexistent_server_id = data_utils.rand_uuid()
+ name = data_utils.rand_name('image')
+ meta = {'image_type': 'test'}
+ self.assertRaises(exceptions.NotFound, self.__create_image__,
+ nonexistent_server_id, name, meta)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_image_specify_uuid_35_characters_or_less(self):
+ # Return an error if Image ID passed is 35 characters or less
+ snapshot_name = data_utils.rand_name('test-snap-')
+ test_uuid = ('a' * 35)
+ self.assertRaises(exceptions.NotFound,
+ self.servers_client.create_image,
+ test_uuid, snapshot_name)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_create_image_specify_uuid_37_characters_or_more(self):
+ # Return an error if Image ID passed is 37 characters or more
+ snapshot_name = data_utils.rand_name('test-snap-')
+ test_uuid = ('a' * 37)
+ self.assertRaises(exceptions.NotFound,
+ self.servers_client.create_image,
+ test_uuid, snapshot_name)
diff --git a/tempest/api/compute/v3/images/test_images_oneserver.py b/tempest/api/compute/v3/images/test_images_oneserver.py
index 1ded4e4..48a885e 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver.py
@@ -26,7 +26,6 @@
class ImagesOneServerV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def setUp(self):
# NOTE(afazekas): Normally we use the same server with all test cases,
diff --git a/tempest/api/compute/v3/images/test_images_oneserver_negative.py b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
index 8d2517e..7679eee 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
@@ -27,7 +27,6 @@
class ImagesOneServerNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def tearDown(self):
"""Terminate test instances created after a test is executed."""
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs.py b/tempest/api/compute/v3/keypairs/test_keypairs.py
index 8eef811..668a295 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs.py
@@ -19,7 +19,6 @@
class KeyPairsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
index ae22ccc..e426b85 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
@@ -21,7 +21,6 @@
class KeyPairsNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index 272cb53..e1c69d9 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -24,7 +24,6 @@
class AttachInterfacesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -48,6 +47,7 @@
def _create_server_get_interfaces(self):
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, ifs = self.client.list_interfaces(server['id'])
+ self.assertEqual(200, resp.status)
resp, body = self.client.wait_for_interface_status(
server['id'], ifs[0]['port_id'], 'ACTIVE')
ifs[0]['port_state'] = body['port_state']
@@ -55,6 +55,7 @@
def _test_create_interface(self, server):
resp, iface = self.client.create_interface(server['id'])
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface)
@@ -64,6 +65,7 @@
network_id = ifs[0]['net_id']
resp, iface = self.client.create_interface(server['id'],
network_id=network_id)
+ self.assertEqual(200, resp.status)
resp, iface = self.client.wait_for_interface_status(
server['id'], iface['port_id'], 'ACTIVE')
self._check_interface(iface, network_id=network_id)
@@ -73,12 +75,14 @@
iface = ifs[0]
resp, _iface = self.client.show_interface(server['id'],
iface['port_id'])
+ self.assertEqual(200, resp.status)
self.assertEqual(iface, _iface)
def _test_delete_interface(self, server, ifs):
# NOTE(danms): delete not the first or last, but one in the middle
iface = ifs[1]
- self.client.delete_interface(server['id'], iface['port_id'])
+ resp, _ = self.client.delete_interface(server['id'], iface['port_id'])
+ self.assertEqual(202, resp.status)
_ifs = self.client.list_interfaces(server['id'])[1]
start = int(time.time())
@@ -122,3 +126,30 @@
_ifs = self._test_delete_interface(server, ifs)
self.assertEqual(len(ifs) - 1, len(_ifs))
+
+ @attr(type='gate')
+ def test_add_remove_fixed_ip(self):
+ # Add and Remove the fixed IP to server.
+ server, ifs = self._create_server_get_interfaces()
+ interface_count = len(ifs)
+ self.assertGreater(interface_count, 0)
+ self._check_interface(ifs[0])
+ network_id = ifs[0]['net_id']
+ resp, body = self.client.add_fixed_ip(server['id'],
+ network_id)
+ self.assertEqual(202, resp.status)
+ server_resp, server_detail = self.servers_client.get_server(
+ server['id'])
+ # Get the Fixed IP from server.
+ fixed_ip = None
+ for ip_set in server_detail['addresses']:
+ for ip in server_detail['addresses'][ip_set]:
+ if ip['type'] == 'fixed':
+ fixed_ip = ip['addr']
+ break
+ if fixed_ip is not None:
+ break
+ # Remove the fixed IP from server.
+ resp, body = self.client.remove_fixed_ip(server['id'],
+ fixed_ip)
+ self.assertEqual(202, resp.status)
diff --git a/tempest/api/compute/v3/servers/test_attach_volume.py b/tempest/api/compute/v3/servers/test_attach_volume.py
index 2edf934..8577aab 100644
--- a/tempest/api/compute/v3/servers/test_attach_volume.py
+++ b/tempest/api/compute/v3/servers/test_attach_volume.py
@@ -24,7 +24,6 @@
class AttachVolumeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
def __init__(self, *args, **kwargs):
diff --git a/tempest/api/compute/v3/servers/test_availability_zone.py b/tempest/api/compute/v3/servers/test_availability_zone.py
index feac9a1..5a1e07e 100644
--- a/tempest/api/compute/v3/servers/test_availability_zone.py
+++ b/tempest/api/compute/v3/servers/test_availability_zone.py
@@ -23,8 +23,6 @@
Tests Availability Zone API List
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(AZV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
index 0825381..a212ca5 100644
--- a/tempest/api/compute/v3/servers/test_create_server.py
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -28,7 +28,6 @@
class ServersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
@@ -119,7 +118,6 @@
class ServersWithSpecificFlavorV3Test(base.BaseV3ComputeAdminTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
disk_config = 'AUTO'
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index f53ab6e..d694a33 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -12,6 +12,8 @@
# 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 test
@@ -22,7 +24,6 @@
class DeleteServersV3Test(base.BaseV3ComputeTest):
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances".
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -35,6 +36,7 @@
resp, server = self.create_test_server(wait_until='BUILD')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_active_server(self):
@@ -42,6 +44,7 @@
resp, server = self.create_test_server(wait_until='ACTIVE')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shutoff_state(self):
@@ -51,6 +54,7 @@
self.client.wait_for_server_status(server['id'], 'SHUTOFF')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_pause_state(self):
@@ -60,6 +64,7 @@
self.client.wait_for_server_status(server['id'], 'PAUSED')
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
@test.attr(type='gate')
def test_delete_server_while_in_shelved_state(self):
@@ -79,12 +84,25 @@
resp, _ = self.client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
+
+ @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+ 'Resize not available.')
+ @test.attr(type='gate')
+ def test_delete_server_while_in_verify_resize_state(self):
+ # Delete a server while it's VM state is VERIFY_RESIZE
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
class DeleteServersAdminV3Test(base.BaseV3ComputeAdminTest):
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances".
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -103,6 +121,8 @@
self.assertEqual(server['status'], 'ERROR')
resp, _ = self.non_admin_client.delete_server(server['id'])
self.assertEqual('204', resp['status'])
+ self.servers_client.wait_for_server_termination(server['id'],
+ ignore_error=True)
@test.attr(type='gate')
def test_admin_delete_servers_of_others(self):
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index c4f6e14..7d25100 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -18,14 +18,13 @@
class InstanceActionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
super(InstanceActionsV3Test, cls).setUpClass()
cls.client = cls.servers_client
resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.request_id = resp['x-compute-request-id']
+ cls.resp = resp
cls.server_id = server['id']
@test.attr(type='gate')
@@ -41,10 +40,12 @@
self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
@test.attr(type='gate')
+ @test.skip_because(bug="1281915")
def test_get_instance_action(self):
# Get the action details of the provided server
+ request_id = self.resp['x-compute-request-id']
resp, body = self.client.get_instance_action(self.server_id,
- self.request_id)
+ request_id)
self.assertEqual(200, resp.status)
self.assertEqual(self.server_id, body['instance_uuid'])
self.assertEqual('create', body['action'])
diff --git a/tempest/api/compute/v3/servers/test_instance_actions_negative.py b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
index bd741e0..b0a7050 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
@@ -20,7 +20,6 @@
class InstanceActionsNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_list_server_filters.py b/tempest/api/compute/v3/servers/test_list_server_filters.py
index e08125b..ec31e8e 100644
--- a/tempest/api/compute/v3/servers/test_list_server_filters.py
+++ b/tempest/api/compute/v3/servers/test_list_server_filters.py
@@ -24,7 +24,6 @@
class ListServerFiltersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_list_servers_negative.py b/tempest/api/compute/v3/servers/test_list_servers_negative.py
index 09e1bb6..92f44fe 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -15,13 +15,14 @@
import datetime
+from six import moves
+
from tempest.api.compute import base
from tempest import exceptions
from tempest.test import attr
class ListServersNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
force_tenant_isolation = True
@classmethod
@@ -36,7 +37,7 @@
cls.existing_fixtures = []
cls.deleted_fixtures = []
cls.start_time = datetime.datetime.utcnow()
- for x in xrange(2):
+ for x in moves.xrange(2):
resp, srv = cls.create_test_server()
cls.existing_fixtures.append(srv)
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
index dee4407..23e0854 100644
--- a/tempest/api/compute/v3/servers/test_multiple_create.py
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -19,7 +19,6 @@
class MultipleCreateV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
_name = 'multiple-create-test'
def _generate_name(self):
diff --git a/tempest/api/compute/v3/servers/test_multiple_create_negative.py b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
index 57bb807..f208bc0 100644
--- a/tempest/api/compute/v3/servers/test_multiple_create_negative.py
+++ b/tempest/api/compute/v3/servers/test_multiple_create_negative.py
@@ -20,7 +20,6 @@
class MultipleCreateV3NegativeTest(base.BaseV3ComputeTest):
- _interface = 'json'
_name = 'multiple-create-negative-test'
def _generate_name(self):
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 6584b93..406c45a 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -28,7 +28,6 @@
class ServerActionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
resize_available = CONF.compute_feature_enabled.resize
run_ssh = CONF.compute.run_ssh
@@ -411,3 +410,16 @@
resp, server = self.servers_client.start(self.server_id)
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
+ @testtools.skipUnless(CONF.compute_feature_enabled.vnc_console,
+ 'VNC Console feature is disabled')
+ @test.attr(type='gate')
+ def test_get_vnc_console(self):
+ # Get the VNC console
+ console_types = ['novnc', 'xvpvnc']
+ for console_type in console_types:
+ resp, body = self.servers_client.get_vnc_console(self.server_id,
+ console_type)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(console_type, body['type'])
+ self.assertNotEqual('', body['url'])
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index 038e254..efd7500 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -15,14 +15,12 @@
from tempest.api.compute import base
from tempest import config
-from tempest import exceptions
from tempest import test
CONF = config.CONF
class ServerAddressesV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -33,19 +31,6 @@
resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
- @test.attr(type=['negative', 'gate'])
- def test_list_server_addresses_invalid_server_id(self):
- # List addresses request should fail if server id not in system
- self.assertRaises(exceptions.NotFound, self.client.list_addresses,
- '999')
-
- @test.attr(type=['negative', 'gate'])
- def test_list_server_addresses_by_network_neg(self):
- # List addresses by network should fail if network name not valid
- self.assertRaises(exceptions.NotFound,
- self.client.list_addresses_by_network,
- self.server['id'], 'invalid')
-
@test.skip_because(bug="1210483",
condition=CONF.service_available.neutron)
@test.attr(type='smoke')
diff --git a/tempest/api/compute/v3/servers/test_server_addresses_negative.py b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
new file mode 100644
index 0000000..8a9877b
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
@@ -0,0 +1,46 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerAddressesV3NegativeTest(base.BaseV3ComputeTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ # This test module might use a network and a subnet
+ cls.set_network_resources(network=True, subnet=True)
+ super(ServerAddressesV3NegativeTest, cls).setUpClass()
+ cls.client = cls.servers_client
+
+ resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_server_addresses_nonexistent_server_id(self):
+ # List addresses request should fail if server id not in system
+ non_existent_server_id = data_utils.rand_uuid()
+ self.assertRaises(exceptions.NotFound, self.client.list_addresses,
+ non_existent_server_id)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_list_server_addresses_by_network_neg(self):
+ # List addresses by network should fail if network name not valid
+ self.assertRaises(exceptions.NotFound,
+ self.client.list_addresses_by_network,
+ self.server['id'], 'invalid')
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index 13c82dd..0e4ef07 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -18,7 +18,6 @@
class ServerMetadataV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_metadata_negative.py b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
index ce6c340..ec2bc8c 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
@@ -19,7 +19,6 @@
class ServerMetadataV3NegativeTest(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_password.py b/tempest/api/compute/v3/servers/test_server_password.py
index 579a8a5..fc0b145 100644
--- a/tempest/api/compute/v3/servers/test_server_password.py
+++ b/tempest/api/compute/v3/servers/test_server_password.py
@@ -19,7 +19,6 @@
class ServerPasswordV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_rescue.py b/tempest/api/compute/v3/servers/test_server_rescue.py
index fa7def0..b3dcb51 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue.py
@@ -14,67 +14,22 @@
# under the License.
from tempest.api.compute import base
-from tempest.common.utils import data_utils
-from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ServerRescueV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
super(ServerRescueV3Test, cls).setUpClass()
- cls.device = 'vdf'
-
- # Create a volume and wait for it to become ready for attach
- resp, cls.volume = cls.volumes_client.create_volume(
- 1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
- cls.volumes_client.wait_for_volume_status(
- cls.volume['id'], 'available')
# Server for positive tests
resp, server = cls.create_test_server(wait_until='BUILD')
- resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
cls.server_id = server['id']
cls.password = server['admin_password']
cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
- # Server for negative tests
- cls.rescue_id = resc_server['id']
- cls.rescue_password = resc_server['admin_password']
-
- cls.servers_client.rescue_server(
- cls.rescue_id, admin_password=cls.rescue_password)
- cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
-
- def setUp(self):
- super(ServerRescueV3Test, self).setUp()
-
- @classmethod
- def tearDownClass(cls):
- cls.delete_volume(cls.volume['id'])
- super(ServerRescueV3Test, cls).tearDownClass()
-
- def tearDown(self):
- super(ServerRescueV3Test, self).tearDown()
-
- def _detach(self, server_id, volume_id):
- self.servers_client.detach_volume(server_id, volume_id)
- self.volumes_client.wait_for_volume_status(volume_id,
- 'available')
-
- def _unrescue(self, server_id):
- resp, body = self.servers_client.unrescue_server(server_id)
- self.assertEqual(202, resp.status)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
-
- def _unpause(self, server_id):
- resp, body = self.servers_client.unpause_server(server_id)
- self.assertEqual(202, resp.status)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
-
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_rescue_unrescue_instance(self):
resp, body = self.servers_client.rescue_server(
self.server_id, admin_password=self.password)
@@ -83,71 +38,3 @@
resp, body = self.servers_client.unrescue_server(self.server_id)
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
-
- @attr(type=['negative', 'gate'])
- def test_rescue_paused_instance(self):
- # Rescue a paused server
- resp, body = self.servers_client.pause_server(
- self.server_id)
- self.addCleanup(self._unpause, self.server_id)
- self.assertEqual(202, resp.status)
- self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
- self.assertRaises(exceptions.Conflict,
- self.servers_client.rescue_server,
- self.server_id)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_reboot(self):
- self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
- self.rescue_id, 'HARD')
-
- @attr(type=['negative', 'gate'])
- def test_rescue_non_existent_server(self):
- # Rescue a non-existing server
- self.assertRaises(exceptions.NotFound,
- self.servers_client.rescue_server,
- '999erra43')
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_rebuild(self):
- self.assertRaises(exceptions.Conflict,
- self.servers_client.rebuild,
- self.rescue_id,
- self.image_ref_alt)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_attach_volume(self):
- # Rescue the server
- self.servers_client.rescue_server(self.server_id,
- admin_password=self.password)
- self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
- # Attach the volume to the server
- self.assertRaises(exceptions.Conflict,
- self.servers_client.attach_volume,
- self.server_id,
- self.volume['id'],
- device='/dev/%s' % self.device)
-
- @attr(type=['negative', 'gate'])
- def test_rescued_vm_detach_volume(self):
- # Attach the volume to the server
- self.servers_client.attach_volume(self.server_id,
- self.volume['id'],
- device='/dev/%s' % self.device)
- self.volumes_client.wait_for_volume_status(self.volume['id'], 'in-use')
-
- # Rescue the server
- self.servers_client.rescue_server(self.server_id,
- admin_password=self.password)
- self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- # addCleanup is a LIFO queue
- self.addCleanup(self._detach, self.server_id, self.volume['id'])
- self.addCleanup(self._unrescue, self.server_id)
-
- # Detach the volume from the server expecting failure
- self.assertRaises(exceptions.Conflict,
- self.servers_client.detach_volume,
- self.server_id,
- self.volume['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
new file mode 100644
index 0000000..6e09376
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -0,0 +1,133 @@
+# Copyright 2013 Hewlett-Packard Development Company, L.P.
+# Copyright 2014 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerRescueNegativeV3Test(base.BaseV3ComputeTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(ServerRescueNegativeV3Test, cls).setUpClass()
+ cls.device = 'vdf'
+
+ # Create a volume and wait for it to become ready for attach
+ resp, cls.volume = cls.volumes_client.create_volume(
+ 1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
+ cls.volumes_client.wait_for_volume_status(
+ cls.volume['id'], 'available')
+
+ # Server for negative tests
+ resp, server = cls.create_test_server(wait_until='BUILD')
+ resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
+ cls.password = server['admin_password']
+ cls.rescue_id = resc_server['id']
+ cls.rescue_password = resc_server['admin_password']
+
+ cls.servers_client.rescue_server(
+ cls.rescue_id, admin_password=cls.rescue_password)
+ cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.delete_volume(cls.volume['id'])
+ super(ServerRescueNegativeV3Test, cls).tearDownClass()
+
+ def _detach(self, server_id, volume_id):
+ self.servers_client.detach_volume(server_id, volume_id)
+ self.volumes_client.wait_for_volume_status(volume_id,
+ 'available')
+
+ def _unrescue(self, server_id):
+ resp, body = self.servers_client.unrescue_server(server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+ def _unpause(self, server_id):
+ resp, body = self.servers_client.unpause_server(server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescue_paused_instance(self):
+ # Rescue a paused server
+ resp, body = self.servers_client.pause_server(
+ self.server_id)
+ self.addCleanup(self._unpause, self.server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.rescue_server,
+ self.server_id)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_reboot(self):
+ self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
+ self.rescue_id, 'HARD')
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescue_non_existent_server(self):
+ # Rescue a non-existing server
+ self.assertRaises(exceptions.NotFound,
+ self.servers_client.rescue_server,
+ data_utils.rand_uuid())
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_rebuild(self):
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.rebuild,
+ self.rescue_id,
+ self.image_ref_alt)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_attach_volume(self):
+ # Rescue the server
+ self.servers_client.rescue_server(self.server_id,
+ admin_password=self.password)
+ self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+ self.addCleanup(self._unrescue, self.server_id)
+
+ # Attach the volume to the server
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.attach_volume,
+ self.server_id,
+ self.volume['id'],
+ device='/dev/%s' % self.device)
+
+ @test.attr(type=['negative', 'gate'])
+ def test_rescued_vm_detach_volume(self):
+ # Attach the volume to the server
+ self.servers_client.attach_volume(self.server_id,
+ self.volume['id'],
+ device='/dev/%s' % self.device)
+ self.volumes_client.wait_for_volume_status(self.volume['id'], 'in-use')
+
+ # Rescue the server
+ self.servers_client.rescue_server(self.server_id,
+ admin_password=self.password)
+ self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+ # addCleanup is a LIFO queue
+ self.addCleanup(self._detach, self.server_id, self.volume['id'])
+ self.addCleanup(self._unrescue, self.server_id)
+
+ # Detach the volume from the server expecting failure
+ self.assertRaises(exceptions.Conflict,
+ self.servers_client.detach_volume,
+ self.server_id,
+ self.volume['id'])
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
index 5480e31..426ee8d 100644
--- a/tempest/api/compute/v3/servers/test_servers.py
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -19,7 +19,6 @@
class ServersV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 12e0ad8..cb5e93d 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -27,7 +27,6 @@
class ServersNegativeV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
def setUp(self):
super(ServersNegativeV3Test, self).setUp()
diff --git a/tempest/api/compute/v3/test_extensions.py b/tempest/api/compute/v3/test_extensions.py
index 09f5ab4..3c612df 100644
--- a/tempest/api/compute/v3/test_extensions.py
+++ b/tempest/api/compute/v3/test_extensions.py
@@ -25,7 +25,6 @@
class ExtensionsV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@test.attr(type='gate')
def test_list_extensions(self):
diff --git a/tempest/api/compute/v3/test_live_block_migration.py b/tempest/api/compute/v3/test_live_block_migration.py
index 43b4e2b..33d2bd9 100644
--- a/tempest/api/compute/v3/test_live_block_migration.py
+++ b/tempest/api/compute/v3/test_live_block_migration.py
@@ -24,7 +24,6 @@
class LiveBlockMigrationV3Test(base.BaseV3ComputeAdminTest):
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/test_live_block_migration_negative.py b/tempest/api/compute/v3/test_live_block_migration_negative.py
index 4d820d8..b4ec505 100644
--- a/tempest/api/compute/v3/test_live_block_migration_negative.py
+++ b/tempest/api/compute/v3/test_live_block_migration_negative.py
@@ -25,7 +25,6 @@
class LiveBlockMigrationV3NegativeTest(base.BaseV3ComputeAdminTest):
_host_key = 'os-extended-server-attributes:host'
- _interface = 'json'
@classmethod
def setUpClass(cls):
@@ -39,7 +38,7 @@
def _migrate_server_to(self, server_id, dest_host):
_resp, body = self.admin_servers_client.live_migrate_server(
server_id, dest_host,
- self.config.compute_feature_enabled.
+ CONF.compute_feature_enabled.
block_migration_for_live_migration)
return body
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index 33b90ff..b53d9be 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -18,7 +18,6 @@
class QuotasV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/compute/v3/test_version.py b/tempest/api/compute/v3/test_version.py
index 9161d4d..1a74e35 100644
--- a/tempest/api/compute/v3/test_version.py
+++ b/tempest/api/compute/v3/test_version.py
@@ -19,7 +19,6 @@
class VersionV3Test(base.BaseV3ComputeTest):
- _interface = 'json'
@test.attr(type='gate')
def test_version(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 7a60196..3c5feed 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -24,7 +24,6 @@
class AttachVolumeTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
run_ssh = CONF.compute.run_ssh
def __init__(self, *args, **kwargs):
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 73e3b3a..c3d6ba6 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -24,8 +24,6 @@
class VolumesGetTestJSON(base.BaseV2ComputeTest):
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(VolumesGetTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 48b1b7e..9867c64 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -31,8 +31,6 @@
VOLUME_BACKING_FILE_SIZE is atleast 4G in your localrc
"""
- _interface = 'json'
-
@classmethod
def setUpClass(cls):
super(VolumesTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 85b30e2..cecaf62 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -25,7 +25,6 @@
class VolumesNegativeTest(base.BaseV2ComputeTest):
- _interface = 'json'
@classmethod
def setUpClass(cls):
diff --git a/tempest/api/database/__init__.py b/tempest/api/database/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/api/database/__init__.py
diff --git a/tempest/api/database/base.py b/tempest/api/database/base.py
new file mode 100644
index 0000000..8add9ba
--- /dev/null
+++ b/tempest/api/database/base.py
@@ -0,0 +1,42 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest import config
+from tempest.openstack.common import log as logging
+import tempest.test
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class BaseDatabaseTest(tempest.test.BaseTestCase):
+ """Base test case class for all Database API tests."""
+
+ _interface = 'json'
+ force_tenant_isolation = False
+
+ @classmethod
+ def setUpClass(cls):
+ super(BaseDatabaseTest, cls).setUpClass()
+ if not CONF.service_available.trove:
+ skip_msg = ("%s skipped as trove is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
+ cls.catalog_type = CONF.database.catalog_type
+ cls.db_flavor_ref = CONF.database.db_flavor_ref
+
+ os = cls.get_client_manager()
+ cls.os = os
+ cls.database_flavors_client = cls.os.database_flavors_client
diff --git a/tempest/api/database/flavors/__init__.py b/tempest/api/database/flavors/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/api/database/flavors/__init__.py
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
new file mode 100644
index 0000000..a591e8e
--- /dev/null
+++ b/tempest/api/database/flavors/test_flavors.py
@@ -0,0 +1,41 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.database import base
+from tempest import test
+
+
+class DatabaseFlavorsTest(base.BaseDatabaseTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(DatabaseFlavorsTest, cls).setUpClass()
+ cls.client = cls.database_flavors_client
+
+ @test.attr(type='smoke')
+ def test_get_db_flavor(self):
+ # The expected flavor details should be returned
+ resp, flavor = self.client.get_db_flavor_details(self.db_flavor_ref)
+ self.assertEqual(self.db_flavor_ref, str(flavor['id']))
+ self.assertIn('ram', flavor)
+ self.assertIn('links', flavor)
+ self.assertIn('name', flavor)
+
+ @test.attr(type='smoke')
+ def test_list_db_flavors(self):
+ resp, flavor = self.client.get_db_flavor_details(self.db_flavor_ref)
+ # List of all flavors should contain the expected flavor
+ resp, flavors = self.client.list_db_flavors()
+ self.assertIn(flavor, flavors)
diff --git a/tempest/api/database/flavors/test_flavors_negative.py b/tempest/api/database/flavors/test_flavors_negative.py
new file mode 100644
index 0000000..202dc48
--- /dev/null
+++ b/tempest/api/database/flavors/test_flavors_negative.py
@@ -0,0 +1,32 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.database import base
+from tempest import exceptions
+from tempest import test
+
+
+class DatabaseFlavorsNegativeTest(base.BaseDatabaseTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super(DatabaseFlavorsNegativeTest, cls).setUpClass()
+ cls.client = cls.database_flavors_client
+
+ @test.attr(type=['negative', 'gate'])
+ def test_get_non_existent_db_flavor(self):
+ # flavor details are not returned for non-existent flavors
+ self.assertRaises(exceptions.NotFound,
+ self.client.get_db_flavor_details, -1)
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index aa64969..5e78cce 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -13,6 +13,8 @@
# 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.test import attr
@@ -24,7 +26,7 @@
@classmethod
def setUpClass(cls):
super(RolesTestJSON, cls).setUpClass()
- for _ in xrange(5):
+ for _ in moves.xrange(5):
role_name = data_utils.rand_name(name='role-')
resp, role = cls.client.create_role(role_name)
cls.data.roles.append(role)
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index cbf6b58..459c44c 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -13,6 +13,7 @@
# 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
@@ -69,7 +70,7 @@
def test_list_services(self):
# Create, List, Verify and Delete Services
services = []
- for _ in xrange(3):
+ for _ in moves.xrange(3):
name = data_utils.rand_name('service-')
type = data_utils.rand_name('type--')
description = data_utils.rand_name('description-')
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index c7cacb4..257a6d7 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -13,6 +13,8 @@
# 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.test import attr
@@ -25,7 +27,7 @@
def test_tenant_list_delete(self):
# Create several tenants and delete them
tenants = []
- for _ in xrange(3):
+ for _ in moves.xrange(3):
tenant_name = data_utils.rand_name(name='tenant-new')
resp, tenant = self.client.create_tenant(tenant_name)
self.assertEqual(200, resp.status)
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 78ecf93..05b704f 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -125,7 +125,7 @@
self.assertEqual(interface2, endpoint['interface'])
self.assertEqual(url2, endpoint['url'])
self.assertEqual(region2, endpoint['region'])
- self.assertEqual('False', str(endpoint['enabled']))
+ self.assertEqual('false', str(endpoint['enabled']).lower())
self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id'])
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index be03a03..31a0ddd 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,6 +13,8 @@
# 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
@@ -31,7 +33,7 @@
@test.attr(type='gate')
def test_project_list_delete(self):
# Create several projects and delete them
- for _ in xrange(3):
+ for _ in moves.xrange(3):
resp, project = self.client.create_project(
data_utils.rand_name('project-new'))
self.addCleanup(self._delete_project, project['id'])
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index e6a078e..4cbb62f 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -14,12 +14,12 @@
from tempest.api.image import base
-from tempest.test import attr
+from tempest import test
class ImageMembersTest(base.BaseV1ImageMembersTest):
- @attr(type='gate')
+ @test.attr(type='gate')
def test_add_image_member(self):
image = self._create_image()
resp = self.client.add_member(self.alt_tenant_id, image)
@@ -33,7 +33,7 @@
resp, body = self.alt_img_cli.get_image(image)
self.assertEqual(200, resp.status)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_shared_images(self):
image = self._create_image()
resp = self.client.add_member(self.alt_tenant_id, image)
@@ -48,7 +48,7 @@
self.assertIn(share_image, images)
self.assertIn(image, images)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_remove_member(self):
image_id = self._create_image()
resp = self.client.add_member(self.alt_tenant_id, image_id)
diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py
index d68ef03..aac63b4 100644
--- a/tempest/api/image/v1/test_image_members_negative.py
+++ b/tempest/api/image/v1/test_image_members_negative.py
@@ -16,26 +16,26 @@
from tempest.api.image import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ImageMembersNegativeTest(base.BaseV1ImageMembersTest):
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_add_member_with_non_existing_image(self):
# Add member with non existing image.
non_exist_image = data_utils.rand_uuid()
self.assertRaises(exceptions.NotFound, self.client.add_member,
self.alt_tenant_id, non_exist_image)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_member_with_non_existing_image(self):
# Delete member with non existing image.
non_exist_image = data_utils.rand_uuid()
self.assertRaises(exceptions.NotFound, self.client.delete_member,
self.alt_tenant_id, non_exist_image)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_member_with_non_existing_tenant(self):
# Delete member with non existing tenant.
image_id = self._create_image()
@@ -43,7 +43,7 @@
self.assertRaises(exceptions.NotFound, self.client.delete_member,
non_exist_tenant, image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_image_without_membership(self):
# Image is hidden from another tenants.
image_id = self._create_image()
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index 5695884..66556e0 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -15,30 +15,30 @@
from tempest.api.image import base
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class CreateDeleteImagesNegativeTest(base.BaseV1ImageTest):
"""Here are negative tests for the deletion and creation of images."""
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_register_with_invalid_container_format(self):
# Negative tests for invalid data supplied to POST /images
self.assertRaises(exceptions.BadRequest, self.client.create_image,
'test', 'wrong', 'vhd')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_register_with_invalid_disk_format(self):
self.assertRaises(exceptions.BadRequest, self.client.create_image,
'test', 'bare', 'wrong')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_with_invalid_image_id(self):
# An image should not be deleted with invalid image id
self.assertRaises(exceptions.NotFound, self.client.delete_image,
'!@$%^&*()')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_non_existent_image(self):
# Return an error while trying to delete a non-existent image
@@ -46,24 +46,24 @@
self.assertRaises(exceptions.NotFound, self.client.delete_image,
non_existent_image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_blank_id(self):
# Return an error while trying to delete an image with blank Id
self.assertRaises(exceptions.NotFound, self.client.delete_image, '')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_non_hex_string_id(self):
# Return an error while trying to delete an image with non hex id
image_id = '11a22b9-120q-5555-cc11-00ab112223gj'
self.assertRaises(exceptions.NotFound, self.client.delete_image,
image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_negative_image_id(self):
# Return an error while trying to delete an image with negative id
self.assertRaises(exceptions.NotFound, self.client.delete_image, -1)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_id_is_over_35_character_limit(self):
# Return an error while trying to delete image with id over limit
self.assertRaises(exceptions.NotFound, self.client.delete_image,
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 2a5401f..ce11911 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -19,7 +19,7 @@
from tempest.api.image import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class BasicOperationsImagesTest(base.BaseV2ImageTest):
@@ -27,7 +27,7 @@
Here we test the basic operations of images
"""
- @attr(type='gate')
+ @test.attr(type='gate')
def test_register_upload_get_image_file(self):
"""
@@ -68,9 +68,9 @@
self.assertEqual(200, resp.status)
self.assertEqual(file_content, body)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_image(self):
- # Deletes a image by image_id
+ # Deletes an image by image_id
# Create image
image_name = data_utils.rand_name('image')
@@ -90,6 +90,43 @@
self.assertEqual(resp.status, 200)
self.assertNotIn(image_id, images)
+ @test.attr(type='gate')
+ def test_update_image(self):
+ # Updates an image by image_id
+
+ # Create image
+ image_name = data_utils.rand_name('image')
+ resp, body = self.client.create_image(name=image_name,
+ container_format='bare',
+ disk_format='iso',
+ visibility='public')
+ self.assertEqual(201, resp.status)
+ self.assertEqual('queued', body['status'])
+ image_id = body['id']
+
+ # Now try uploading an image file
+ file_content = '*' * 1024
+ image_file = StringIO.StringIO(file_content)
+ resp, body = self.client.store_image(image_id, image_file)
+ self.assertEqual(204, resp.status)
+
+ # Update Image
+ new_image_name = data_utils.rand_name('new-image')
+ new_visibility = 'private'
+ resp, body = self.client.update_image(image_id, [
+ dict(replace='/name', value=new_image_name),
+ dict(replace='/visibility', value=new_visibility)])
+
+ self.assertEqual(200, resp.status)
+
+ # Verifying updating
+
+ resp, body = self.client.get_image(image_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(image_id, body['id'])
+ self.assertEqual(new_image_name, body['name'])
+ self.assertEqual(new_visibility, body['visibility'])
+
class ListImagesTest(base.BaseV2ImageTest):
"""
@@ -139,7 +176,7 @@
msg = "Failed to list images by %s" % key
self.assertEqual(params[key], image[key], msg)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_index_no_params(self):
# Simple test to see all fixture images returned
resp, images_list = self.client.image_list()
@@ -149,25 +186,25 @@
for image in self.created_images:
self.assertIn(image, image_list)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_container_format(self):
# Test to get all images with container_format='bare'
params = {"container_format": "bare"}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_disk_format(self):
# Test to get all images with disk_format = raw
params = {"disk_format": "raw"}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_visibility(self):
# Test to get all images with visibility = public
params = {"visibility": "public"}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_size(self):
# Test to get all images by size
image_id = self.created_images[1]
@@ -178,7 +215,7 @@
params = {"size": image['size']}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_min_max_size(self):
# Test to get all images with size between 2000 to 3000
image_id = self.created_images[1]
@@ -197,13 +234,13 @@
image_size <= params['size_max'],
"Failed to get images by size_min and size_max")
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_status(self):
# Test to get all active images
params = {"status": "active"}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_images_param_limit(self):
# Test to get images by limit
params = {"limit": 2}
@@ -212,3 +249,19 @@
self.assertEqual(len(images_list), params['limit'],
"Failed to get images by limit")
+
+ @test.attr(type='gate')
+ def test_get_image_schema(self):
+ # Test to get image schema
+ schema = "image"
+ resp, body = self.client.get_schema(schema)
+ self.assertEqual(200, resp.status)
+ self.assertEqual("image", body['name'])
+
+ @test.attr(type='gate')
+ def test_get_images_schema(self):
+ # Test to get images schema
+ schema = "images"
+ resp, body = self.client.get_schema(schema)
+ self.assertEqual(200, resp.status)
+ self.assertEqual("images", body['name'])
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index 41fc49d..e6c5b61 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -11,17 +11,18 @@
# under the License.
from tempest.api.image import base
-from tempest.test import attr
+from tempest import test
class ImagesMemberTest(base.BaseV2MemberImageTest):
_interface = 'json'
- @attr(type='gate')
+ @test.attr(type='gate')
def test_image_share_accept(self):
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
@@ -30,7 +31,8 @@
self.alt_tenant_id,
'accepted')
self.assertIn(image_id, self._list_image_ids_as_alt())
- _, body = self.os_img_client.get_image_membership(image_id)
+ resp, body = self.os_img_client.get_image_membership(image_id)
+ self.assertEqual(200, resp.status)
members = body['members']
member = members[0]
self.assertEqual(len(members), 1, str(members))
@@ -38,16 +40,49 @@
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'accepted')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_image_share_reject(self):
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
self.assertEqual(member['member_id'], self.alt_tenant_id)
self.assertEqual(member['image_id'], image_id)
self.assertEqual(member['status'], 'pending')
self.assertNotIn(image_id, self._list_image_ids_as_alt())
+ resp, _ = self.alt_img_client.update_member_status(image_id,
+ self.alt_tenant_id,
+ 'rejected')
+ self.assertEqual(200, resp.status)
+ self.assertNotIn(image_id, self._list_image_ids_as_alt())
+
+ @test.attr(type='gate')
+ def test_get_image_member(self):
+ image_id = self._create_image()
+ self.os_img_client.add_member(image_id,
+ self.alt_tenant_id)
self.alt_img_client.update_member_status(image_id,
self.alt_tenant_id,
- 'rejected')
+ 'accepted')
+
+ self.assertIn(image_id, self._list_image_ids_as_alt())
+ resp, member = self.os_img_client.get_member(image_id,
+ self.alt_tenant_id)
+ self.assertEqual(200, resp.status)
+ self.assertEqual(self.alt_tenant_id, member['member_id'])
+ self.assertEqual(image_id, member['image_id'])
+ self.assertEqual('accepted', member['status'])
+
+ @test.attr(type='gate')
+ def test_remove_image_member(self):
+ image_id = self._create_image()
+ self.os_img_client.add_member(image_id,
+ self.alt_tenant_id)
+ self.alt_img_client.update_member_status(image_id,
+ self.alt_tenant_id,
+ 'accepted')
+
+ self.assertIn(image_id, self._list_image_ids_as_alt())
+ resp = self.os_img_client.remove_member(image_id, self.alt_tenant_id)
+ self.assertEqual(204, resp.status)
self.assertNotIn(image_id, self._list_image_ids_as_alt())
diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py
index 4c7cc5a..98ef649 100644
--- a/tempest/api/image/v2/test_images_member_negative.py
+++ b/tempest/api/image/v2/test_images_member_negative.py
@@ -12,13 +12,13 @@
from tempest.api.image import base
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ImagesMemberNegativeTest(base.BaseV2MemberImageTest):
_interface = 'json'
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_image_share_invalid_status(self):
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
@@ -28,7 +28,7 @@
self.alt_img_client.update_member_status,
image_id, self.alt_tenant_id, 'notavalidstatus')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_image_share_owner_cannot_accept(self):
image_id = self._create_image()
resp, member = self.os_img_client.add_member(image_id,
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index b8ba868..27ba39c 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -18,7 +18,7 @@
from tempest.api.image import base
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ImagesNegativeTest(base.BaseV2ImageTest):
@@ -35,20 +35,20 @@
** delete the deleted image
"""
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_non_existent_image(self):
# get the non-existent image
non_existent_id = str(uuid.uuid4())
self.assertRaises(exceptions.NotFound, self.client.get_image,
non_existent_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_image_null_id(self):
# get image with image_id = NULL
image_id = ""
self.assertRaises(exceptions.NotFound, self.client.get_image, image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_delete_deleted_image(self):
# get and delete the deleted image
# create and delete image
@@ -67,27 +67,27 @@
self.assertRaises(exceptions.NotFound, self.client.delete_image,
image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_non_existing_image(self):
# delete non-existent image
non_existent_image_id = str(uuid.uuid4())
self.assertRaises(exceptions.NotFound, self.client.delete_image,
non_existent_image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_image_null_id(self):
# delete image with image_id=NULL
image_id = ""
self.assertRaises(exceptions.NotFound, self.client.delete_image,
image_id)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_register_with_invalid_container_format(self):
# Negative tests for invalid data supplied to POST /images
self.assertRaises(exceptions.BadRequest, self.client.create_image,
'test', 'wrong', 'vhd')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_register_with_invalid_disk_format(self):
self.assertRaises(exceptions.BadRequest, self.client.create_image,
'test', 'bare', 'wrong')
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index f0e343d..504c0e8 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -14,12 +14,12 @@
from tempest.api.image import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class ImagesTagsTest(base.BaseV2ImageTest):
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_delete_tags_for_image(self):
resp, body = self.create_image(container_format='bare',
disk_format='raw',
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
index 0628d29..3233db7 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -17,12 +17,12 @@
from tempest.api.image import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ImagesTagsNegativeTest(base.BaseV2ImageTest):
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_update_tags_for_non_existing_image(self):
# Update tag with non existing image.
tag = data_utils.rand_name('tag-')
@@ -30,7 +30,7 @@
self.assertRaises(exceptions.NotFound, self.client.add_image_tag,
non_exist_image, tag)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_non_existing_tag(self):
# Delete non existing tag.
resp, body = self.create_image(container_format='bare',
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index dd888a6..93335e7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -53,15 +53,12 @@
# Default to ipv4.
_ip_version = 4
- _tenant_network_cidr = CONF.network.tenant_network_cidr
- _tenant_network_mask_bits = CONF.network.tenant_network_mask_bits
@classmethod
def setUpClass(cls):
# Create no network resources for these test.
cls.set_network_resources()
super(BaseNetworkTest, cls).setUpClass()
- os = clients.Manager(interface=cls._interface)
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
@@ -147,11 +144,13 @@
def create_subnet(cls, network):
"""Wrapper utility that returns a test subnet."""
# The cidr and mask_bits depend on the ip version.
- cidr = netaddr.IPNetwork(cls._tenant_network_cidr)
- mask_bits = cls._tenant_network_mask_bits
+ if cls._ip_version == 4:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+ mask_bits = CONF.network.tenant_network_mask_bits
+ elif cls._ip_version == 6:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
+ mask_bits = CONF.network.tenant_network_v6_mask_bits
# Find a cidr that is not in use yet and create a subnet with it
- body = None
- failure = None
for subnet_cidr in cidr.subnet(mask_bits):
try:
resp, body = cls.client.create_subnet(
@@ -163,12 +162,9 @@
is_overlapping_cidr = 'overlaps with another subnet' in str(e)
if not is_overlapping_cidr:
raise
- # save the failure in case all of the CIDRs are overlapping
- failure = e
-
- if not body and failure:
- raise failure
-
+ else:
+ message = 'Available CIDR for subnet creation could not be found'
+ raise exceptions.BuildErrorException(message)
subnet = body['subnet']
cls.subnets.append(subnet)
return subnet
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index 304b2ca..b278002 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -38,11 +38,13 @@
self.assertNotIn(router_id, routers_list)
def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- resp, _ = self.client.remove_router_interface_with_subnet_id(
+ resp, body = self.client.remove_router_interface_with_subnet_id(
router_id, subnet_id)
self.assertEqual('200', resp['status'])
+ self.assertEqual(subnet_id, body['subnet_id'])
def _remove_router_interface_with_port_id(self, router_id, port_id):
- resp, _ = self.client.remove_router_interface_with_port_id(
+ resp, body = self.client.remove_router_interface_with_port_id(
router_id, port_id)
self.assertEqual('200', resp['status'])
+ self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
index d68ff1a..97e120f 100644
--- a/tempest/api/network/common.py
+++ b/tempest/api/network/common.py
@@ -61,6 +61,11 @@
super(DeletableSubnet, self).__init__(*args, **kwargs)
self._router_ids = set()
+ def update(self, *args, **kwargs):
+ body = dict(subnet=dict(*args, **kwargs))
+ result = self.client.update_subnet(subnet=self.id, body=body)
+ super(DeletableSubnet, self).update(**result['subnet'])
+
def add_to_router(self, router_id):
self._router_ids.add(router_id)
body = dict(subnet_id=self.id)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index aba2c8e..1155257 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -18,7 +18,6 @@
from tempest.api.network import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
from tempest.test import attr
CONF = config.CONF
@@ -85,21 +84,7 @@
updated_net = body['network']
self.assertEqual(updated_net['name'], new_name)
# Find a cidr that is not in use yet and create a subnet with it
- cidr = netaddr.IPNetwork(self._tenant_network_cidr)
- mask_bits = self._tenant_network_mask_bits
- for subnet_cidr in cidr.subnet(mask_bits):
- try:
- resp, body = self.client.create_subnet(
- network_id=net_id,
- cidr=str(subnet_cidr),
- ip_version=self._ip_version)
- break
- except exceptions.BadRequest as e:
- is_overlapping_cidr = 'overlaps with another subnet' in str(e)
- if not is_overlapping_cidr:
- raise
- self.assertEqual('201', resp['status'])
- subnet = body['subnet']
+ subnet = self.create_subnet(network)
subnet_id = subnet['id']
# Verification of subnet update
new_subnet = "New_subnet"
@@ -111,6 +96,8 @@
# Delete subnet and network
resp, body = self.client.delete_subnet(subnet_id)
self.assertEqual('204', resp['status'])
+ # Remove subnet from cleanup list
+ self.subnets.pop()
resp, body = self.client.delete_network(net_id)
self.assertEqual('204', resp['status'])
@@ -464,13 +451,11 @@
class NetworksIpV6TestJSON(NetworksTestJSON):
_ip_version = 6
- _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
- _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
@classmethod
def setUpClass(cls):
super(NetworksIpV6TestJSON, cls).setUpClass()
- if not CONF.network.ipv6_enabled:
+ if not CONF.network_feature_enabled.ipv6:
cls.tearDownClass()
skip_msg = "IPv6 Tests are disabled."
raise cls.skipException(skip_msg)
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 0ff91ab..2657031 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -256,3 +256,48 @@
def _delete_extra_routes(self, router_id):
resp, _ = self.client.delete_extra_routes(router_id)
+
+ @test.attr(type='smoke')
+ def test_update_router_admin_state(self):
+ self.router = self.create_router(data_utils.rand_name('router-'))
+ self.assertFalse(self.router['admin_state_up'])
+ # Update router admin state
+ resp, update_body = self.client.update_router(self.router['id'],
+ admin_state_up=True)
+ self.assertEqual('200', resp['status'])
+ self.assertTrue(update_body['router']['admin_state_up'])
+ resp, show_body = self.client.show_router(self.router['id'])
+ self.assertEqual('200', resp['status'])
+ self.assertTrue(show_body['router']['admin_state_up'])
+
+ @test.attr(type='smoke')
+ def test_add_multiple_router_interfaces(self):
+ network = self.create_network()
+ subnet01 = self.create_subnet(network)
+ subnet02 = self.create_subnet(network)
+ router = self.create_router(data_utils.rand_name('router-'))
+ interface01 = self._add_router_interface_with_subnet_id(router['id'],
+ subnet01['id'])
+ self._verify_router_interface(router['id'], subnet01['id'],
+ interface01['port_id'])
+ interface02 = self._add_router_interface_with_subnet_id(router['id'],
+ subnet02['id'])
+ self._verify_router_interface(router['id'], subnet02['id'],
+ interface02['port_id'])
+
+ def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+ resp, interface = self.client.add_router_interface_with_subnet_id(
+ router_id, subnet_id)
+ self.assertEqual('200', resp['status'])
+ self.addCleanup(self._remove_router_interface_with_subnet_id,
+ router_id, subnet_id)
+ self.assertEqual(subnet_id, interface['subnet_id'])
+ return interface
+
+ def _verify_router_interface(self, router_id, subnet_id, port_id):
+ resp, show_port_body = self.client.show_port(port_id)
+ self.assertEqual('200', resp['status'])
+ interface_port = show_port_body['port']
+ self.assertEqual(router_id, interface_port['device_id'])
+ self.assertEqual(subnet_id,
+ interface_port['fixed_ips'][0]['subnet_id'])
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 1d41cc9..3e26f46 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -14,6 +14,7 @@
# under the License.
from tempest.api.network import base_security_groups as base
+from tempest.common.utils import data_utils
from tempest import test
@@ -41,15 +42,9 @@
self.assertIsNotNone(found, msg)
@test.attr(type='smoke')
- def test_create_show_delete_security_group(self):
+ def test_create_list_update_show_delete_security_group(self):
group_create_body, name = self._create_security_group()
- # Show details of the created security group
- resp, show_body = self.client.show_security_group(
- group_create_body['security_group']['id'])
- self.assertEqual('200', resp['status'])
- self.assertEqual(show_body['security_group']['name'], name)
-
# List security groups and verify if created group is there in response
resp, list_body = self.client.list_security_groups()
self.assertEqual('200', resp['status'])
@@ -57,6 +52,24 @@
for secgroup in list_body['security_groups']:
secgroup_list.append(secgroup['id'])
self.assertIn(group_create_body['security_group']['id'], secgroup_list)
+ # Update the security group
+ new_name = data_utils.rand_name('security-')
+ new_description = data_utils.rand_name('security-description')
+ resp, update_body = self.client.update_security_group(
+ group_create_body['security_group']['id'],
+ name=new_name,
+ description=new_description)
+ # Verify if security group is updated
+ self.assertEqual('200', resp['status'])
+ self.assertEqual(update_body['security_group']['name'], new_name)
+ self.assertEqual(update_body['security_group']['description'],
+ new_description)
+ # Show details of the updated security group
+ resp, show_body = self.client.show_security_group(
+ group_create_body['security_group']['id'])
+ self.assertEqual(show_body['security_group']['name'], new_name)
+ self.assertEqual(show_body['security_group']['description'],
+ new_description)
@test.attr(type='smoke')
def test_create_show_delete_security_group_rule(self):
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 788292d..b14adc0 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -17,9 +17,12 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
+from tempest import config
from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
class AccountQuotasTest(base.BaseObjectTest):
@@ -41,7 +44,7 @@
try:
_, roles = cls.os_admin.identity_client.list_roles()
reseller_role_id = next(r['id'] for r in roles if r['name']
- == 'ResellerAdmin')
+ == CONF.object_storage.reseller_admin_role)
except StopIteration:
msg = "No ResellerAdmin role found"
raise exceptions.NotFound(msg)
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index cab307d..402cd90 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -17,9 +17,12 @@
from tempest.api.object_storage import base
from tempest import clients
from tempest.common.utils import data_utils
+from tempest import config
from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
class AccountQuotasNegativeTest(base.BaseObjectTest):
@@ -41,7 +44,7 @@
try:
_, roles = cls.os_admin.identity_client.list_roles()
reseller_role_id = next(r['id'] for r in roles if r['name']
- == 'ResellerAdmin')
+ == CONF.object_storage.reseller_admin_role)
except StopIteration:
msg = "No ResellerAdmin role found"
raise exceptions.NotFound(msg)
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 5456768..4b895d8 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -15,18 +15,25 @@
import random
+from six import moves
+
from tempest.api.object_storage import base
+from tempest import clients
from tempest.common import custom_matchers
from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
from tempest import test
+CONF = config.CONF
+
class AccountTest(base.BaseObjectTest):
@classmethod
def setUpClass(cls):
super(AccountTest, cls).setUpClass()
cls.containers = []
- for i in xrange(ord('a'), ord('f') + 1):
+ for i in moves.xrange(ord('a'), ord('f') + 1):
name = data_utils.rand_name(name='%s-' % chr(i))
cls.container_client.create_container(name)
cls.containers.append(name)
@@ -35,20 +42,109 @@
@classmethod
def tearDownClass(cls):
cls.delete_containers(cls.containers)
+ cls.data.teardown_all()
super(AccountTest, cls).tearDownClass()
@test.attr(type='smoke')
def test_list_containers(self):
# list of all containers should not be empty
- params = {'format': 'json'}
- resp, container_list = \
- self.account_client.list_account_containers(params=params)
+ resp, container_list = self.account_client.list_account_containers()
self.assertHeaders(resp, 'Account', 'GET')
self.assertIsNotNone(container_list)
- container_names = [c['name'] for c in container_list]
for container_name in self.containers:
- self.assertIn(container_name, container_names)
+ self.assertIn(container_name, container_list)
+
+ @test.attr(type='smoke')
+ def test_list_no_containers(self):
+ # List request to empty account
+
+ # To test listing no containers, create new user other than
+ # the base user of this instance.
+ self.data.setup_test_user()
+
+ os_test_user = clients.Manager(
+ self.data.test_user,
+ self.data.test_password,
+ self.data.test_tenant)
+
+ # Retrieve the id of an operator role of object storage
+ test_role_id = None
+ swift_role = CONF.object_storage.operator_role
+ try:
+ _, roles = self.os_admin.identity_client.list_roles()
+ test_role_id = next(r['id'] for r in roles if r['name']
+ == swift_role)
+ except StopIteration:
+ msg = "%s role found" % swift_role
+ raise exceptions.NotFound(msg)
+
+ # Retrieve the test_user id
+ _, users = self.os_admin.identity_client.get_users()
+ test_user_id = next(usr['id'] for usr in users if usr['name']
+ == self.data.test_user)
+
+ # Retrieve the test_tenant id
+ _, tenants = self.os_admin.identity_client.list_tenants()
+ test_tenant_id = next(tnt['id'] for tnt in tenants if tnt['name']
+ == self.data.test_tenant)
+
+ # Assign the newly created user the appropriate operator role
+ self.os_admin.identity_client.assign_user_role(
+ test_tenant_id,
+ test_user_id,
+ test_role_id)
+
+ resp, container_list = \
+ os_test_user.account_client.list_account_containers()
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+
+ # When sending a request to an account which has not received a PUT
+ # container request, the response does not contain 'accept-ranges'
+ # header. This is a special case, therefore the existence of response
+ # headers is checked without custom matcher.
+ self.assertIn('content-length', resp)
+ self.assertIn('x-timestamp', resp)
+ self.assertIn('x-account-bytes-used', resp)
+ self.assertIn('x-account-container-count', resp)
+ self.assertIn('x-account-object-count', resp)
+ self.assertIn('content-type', resp)
+ self.assertIn('x-trans-id', resp)
+ self.assertIn('date', resp)
+
+ # Check only the format of common headers with custom matcher
+ self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
+ self.assertEqual(len(container_list), 0)
+
+ @test.attr(type='smoke')
+ def test_list_containers_with_format_json(self):
+ # list containers setting format parameter to 'json'
+ params = {'format': 'json'}
+ resp, container_list = self.account_client.list_account_containers(
+ params=params)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'GET')
+ self.assertIsNotNone(container_list)
+ self.assertTrue([c['name'] for c in container_list])
+ self.assertTrue([c['count'] for c in container_list])
+ self.assertTrue([c['bytes'] for c in container_list])
+
+ @test.attr(type='smoke')
+ def test_list_containers_with_format_xml(self):
+ # list containers setting format parameter to 'xml'
+ params = {'format': 'xml'}
+ resp, container_list = self.account_client.list_account_containers(
+ params=params)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'GET')
+ self.assertIsNotNone(container_list)
+ self.assertEqual(container_list.tag, 'account')
+ self.assertTrue('name' in container_list.keys())
+ self.assertEqual(container_list.find(".//container").tag, 'container')
+ self.assertEqual(container_list.find(".//name").tag, 'name')
+ self.assertEqual(container_list.find(".//count").tag, 'count')
+ self.assertEqual(container_list.find(".//bytes").tag, 'bytes')
@test.attr(type='smoke')
def test_list_extensions(self):
@@ -107,6 +203,17 @@
self.assertEqual(len(container_list), self.containers_count / 2)
@test.attr(type='smoke')
+ def test_list_containers_with_marker_and_end_marker(self):
+ # list containers combining marker and end_marker param
+ params = {'marker': self.containers[0],
+ 'end_marker': self.containers[self.containers_count - 1]}
+ resp, container_list = self.account_client.list_account_containers(
+ params=params)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'GET')
+ self.assertEqual(len(container_list), self.containers_count - 2)
+
+ @test.attr(type='smoke')
def test_list_containers_with_limit_and_marker(self):
# list containers combining marker and limit param
# result are always limitated by the limit whatever the marker
@@ -121,34 +228,125 @@
self.assertTrue(len(container_list) <= limit, str(container_list))
@test.attr(type='smoke')
- def test_list_account_metadata(self):
- # list all account metadata
- resp, metadata = self.account_client.list_account_metadata()
+ def test_list_containers_with_limit_and_end_marker(self):
+ # list containers combining limit and end_marker param
+ limit = random.randint(1, self.containers_count)
+ params = {'limit': limit,
+ 'end_marker': self.containers[self.containers_count / 2]}
+ resp, container_list = self.account_client.list_account_containers(
+ params=params)
self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
- self.assertHeaders(resp, 'Account', 'HEAD')
+ self.assertHeaders(resp, 'Account', 'GET')
+ self.assertEqual(len(container_list),
+ min(limit, self.containers_count / 2))
@test.attr(type='smoke')
- def test_create_and_delete_account_metadata(self):
- header = 'test-account-meta'
- data = 'Meta!'
+ def test_list_containers_with_limit_and_marker_and_end_marker(self):
+ # list containers combining limit, marker and end_marker param
+ limit = random.randint(1, self.containers_count)
+ params = {'limit': limit,
+ 'marker': self.containers[0],
+ 'end_marker': self.containers[self.containers_count - 1]}
+ resp, container_list = self.account_client.list_account_containers(
+ params=params)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'GET')
+ self.assertEqual(len(container_list),
+ min(limit, self.containers_count - 2))
+
+ @test.attr(type='smoke')
+ def test_list_account_metadata(self):
+ # list all account metadata
+
+ # set metadata to account
+ metadata = {'test-account-meta1': 'Meta1',
+ 'test-account-meta2': 'Meta2'}
+ resp, _ = self.account_client.create_account_metadata(metadata)
+
+ resp, _ = self.account_client.list_account_metadata()
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'HEAD')
+ self.assertIn('x-account-meta-test-account-meta1', resp)
+ self.assertIn('x-account-meta-test-account-meta2', resp)
+ self.account_client.delete_account_metadata(metadata)
+
+ @test.attr(type='smoke')
+ def test_list_no_account_metadata(self):
+ # list no account metadata
+ resp, _ = self.account_client.list_account_metadata()
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'HEAD')
+ self.assertNotIn('x-account-meta-', str(resp))
+
+ @test.attr(type='smoke')
+ def test_update_account_metadata_with_create_metadata(self):
# add metadata to account
- resp, _ = self.account_client.create_account_metadata(
- metadata={header: data})
+ metadata = {'test-account-meta1': 'Meta1'}
+ resp, _ = self.account_client.create_account_metadata(metadata)
self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
- resp, _ = self.account_client.list_account_metadata()
- self.assertHeaders(resp, 'Account', 'HEAD')
+ resp, body = self.account_client.list_account_metadata()
+ self.assertIn('x-account-meta-test-account-meta1', resp)
+ self.assertEqual(resp['x-account-meta-test-account-meta1'],
+ metadata['test-account-meta1'])
- self.assertIn('x-account-meta-' + header, resp)
- self.assertEqual(resp['x-account-meta-' + header], data)
+ self.account_client.delete_account_metadata(metadata)
+ @test.attr(type='smoke')
+ def test_update_account_metadata_with_delete_matadata(self):
# delete metadata from account
- resp, _ = \
- self.account_client.delete_account_metadata(metadata=[header])
+ metadata = {'test-account-meta1': 'Meta1'}
+ self.account_client.create_account_metadata(metadata)
+ resp, _ = self.account_client.delete_account_metadata(metadata)
self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
self.assertHeaders(resp, 'Account', 'POST')
resp, _ = self.account_client.list_account_metadata()
- self.assertHeaders(resp, 'Account', 'HEAD')
- self.assertNotIn('x-account-meta-' + header, resp)
+ self.assertNotIn('x-account-meta-test-account-meta1', resp)
+
+ @test.attr(type='smoke')
+ def test_update_account_metadata_with_create_matadata_key(self):
+ # if the value of metadata is not set, the metadata is not
+ # registered at a server
+ metadata = {'test-account-meta1': ''}
+ resp, _ = self.account_client.create_account_metadata(metadata)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'POST')
+
+ resp, _ = self.account_client.list_account_metadata()
+ self.assertNotIn('x-account-meta-test-account-meta1', resp)
+
+ @test.attr(type='smoke')
+ def test_update_account_metadata_with_delete_matadata_key(self):
+ # Although the value of metadata is not set, the feature of
+ # deleting metadata is valid
+ metadata_1 = {'test-account-meta1': 'Meta1'}
+ self.account_client.create_account_metadata(metadata_1)
+ metadata_2 = {'test-account-meta1': ''}
+ resp, _ = self.account_client.delete_account_metadata(metadata_2)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'POST')
+
+ resp, _ = self.account_client.list_account_metadata()
+ self.assertNotIn('x-account-meta-test-account-meta1', resp)
+
+ @test.attr(type='smoke')
+ def test_update_account_metadata_with_create_and_delete_metadata(self):
+ # Send a request adding and deleting metadata requests simultaneously
+ metadata_1 = {'test-account-meta1': 'Meta1'}
+ self.account_client.create_account_metadata(metadata_1)
+ metadata_2 = {'test-account-meta2': 'Meta2'}
+ resp, body = self.account_client.create_and_delete_account_metadata(
+ metadata_2,
+ metadata_1)
+ self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+ self.assertHeaders(resp, 'Account', 'POST')
+
+ resp, _ = self.account_client.list_account_metadata()
+ self.assertNotIn('x-account-meta-test-account-meta1', resp)
+ self.assertIn('x-account-meta-test-account-meta2', resp)
+ self.assertEqual(resp['x-account-meta-test-account-meta2'],
+ metadata_2['test-account-meta2'])
+
+ self.account_client.delete_account_metadata(metadata_2)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 33f3299..91df292 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -14,6 +14,7 @@
# under the License.
import hashlib
+from six import moves
from tempest.api.object_storage import base
from tempest.common import custom_matchers
@@ -242,9 +243,9 @@
object_name = data_utils.rand_name(name='LObject')
data = data_utils.arbitrary_string()
segments = 10
- data_segments = [data + str(i) for i in xrange(segments)]
+ data_segments = [data + str(i) for i in moves.xrange(segments)]
# uploading segments
- for i in xrange(segments):
+ for i in 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/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 47c270e..c597255 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -40,9 +40,9 @@
# update account metadata
cls.key = 'Meta'
cls.metadatas = []
- cls.metadata = {'Temp-URL-Key': cls.key}
- cls.metadatas.append(cls.metadata)
- cls.account_client.create_account_metadata(metadata=cls.metadata)
+ metadata = {'Temp-URL-Key': cls.key}
+ cls.metadatas.append(metadata)
+ cls.account_client.create_account_metadata(metadata=metadata)
# create an object
cls.object_name = data_utils.rand_name(name='ObjectTemp')
@@ -53,7 +53,7 @@
@classmethod
def tearDownClass(cls):
- for metadata in cls.metadata:
+ for metadata in cls.metadatas:
cls.account_client.delete_account_metadata(
metadata=metadata)
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 3e621f4..18ba37b 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -73,7 +73,7 @@
subnet_id: {get_resource: Subnet}
Server:
type: AWS::EC2::Instance
- Metadata:
+ metadata:
Name: SmokeServerNeutron
properties:
ImageId: {get_param: ImageId}
@@ -93,7 +93,7 @@
type: AWS::CloudFormation::WaitConditionHandle
WaitCondition:
type: AWS::CloudFormation::WaitCondition
- DependsOn: Server
+ depends_on: Server
properties:
Handle: {get_resource: WaitHandleNeutron}
Timeout: '600'
@@ -135,7 +135,7 @@
# the cause of the server not signalling the waitcondition
# to heat.
resp, body = cls.client.get_resource(cls.stack_identifier,
- 'SmokeServerNeutron')
+ 'Server')
server_id = body['physical_resource_id']
LOG.debug('Console output for %s', server_id)
resp, output = cls.servers_client.get_console_output(
diff --git a/tempest/api/orchestration/stacks/test_server_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
index 5130f87..7e8bc2d 100644
--- a/tempest/api/orchestration/stacks/test_server_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -154,8 +154,8 @@
sid = self.stack_identifier
rid = 'SmokeServer'
- # wait for server resource create to complete.
- self.client.wait_for_resource_status(sid, rid, 'CREATE_COMPLETE')
+ # wait for create to complete.
+ self.client.wait_for_stack_status(sid, 'CREATE_COMPLETE')
resp, body = self.client.get_resource(sid, rid)
self.assertEqual('CREATE_COMPLETE', body['resource_status'])
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
new file mode 100644
index 0000000..713cfd4
--- /dev/null
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Chmouel Boudjnah <chmouel@enovance.com>
+#
+# 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.orchestration import base
+from tempest import clients
+from tempest.common.utils import data_utils
+from tempest import config
+
+
+CONF = config.CONF
+
+
+class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
+ _interface = 'json'
+ template = """
+heat_template_version: 2013-05-23
+description: Template which creates a Swift container resource
+
+resources:
+ SwiftContainerWebsite:
+ deletion_policy: "Delete"
+ type: OS::Swift::Container
+ properties:
+ X-Container-Read: ".r:*"
+ X-Container-Meta:
+ web-index: "index.html"
+ web-error: "error.html"
+
+ SwiftContainer:
+ type: OS::Swift::Container
+
+outputs:
+ WebsiteURL:
+ description: "URL for website hosted on S3"
+ value: { get_attr: [SwiftContainer, WebsiteURL] }
+ DomainName:
+ description: "Domain of Swift host"
+ value: { get_attr: [SwiftContainer, DomainName] }
+
+"""
+
+ @classmethod
+ def setUpClass(cls):
+ super(SwiftResourcesTestJSON, cls).setUpClass()
+ cls.client = cls.orchestration_client
+ cls.stack_name = data_utils.rand_name('heat')
+ os = clients.Manager()
+ if not CONF.service_available.swift:
+ raise cls.skipException("Swift support is required")
+ cls.account_client = os.account_client
+ cls.container_client = os.container_client
+ # create the stack
+ cls.stack_identifier = cls.create_stack(
+ cls.stack_name,
+ cls.template)
+ cls.stack_id = cls.stack_identifier.split('/')[1]
+ cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
+ cls.test_resources = {}
+ _, resources = cls.client.list_resources(cls.stack_identifier)
+ for resource in resources:
+ cls.test_resources[resource['logical_resource_id']] = resource
+
+ def test_created_resources(self):
+ """Created stack should be on the list of existing stacks."""
+ resources = [('SwiftContainer', 'OS::Swift::Container'),
+ ('SwiftContainerWebsite', 'OS::Swift::Container')]
+ for resource_name, resource_type in resources:
+ resource = self.test_resources.get(resource_name)
+ self.assertIsInstance(resource, dict)
+ self.assertEqual(resource_type, resource['resource_type'])
+ self.assertEqual(resource_name, resource['logical_resource_id'])
+ self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
+
+ def test_created_containers(self):
+ params = {'format': 'json'}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEqual('200', resp['status'])
+ self.assertEqual(2, len(container_list))
+ for cont in container_list:
+ self.assertTrue(cont['name'].startswith(self.stack_name))
+
+ def test_acl(self):
+ acl_headers = ('x-container-meta-web-index', 'x-container-read')
+
+ swcont = self.test_resources.get(
+ 'SwiftContainer')['physical_resource_id']
+ swcont_website = self.test_resources.get(
+ 'SwiftContainerWebsite')['physical_resource_id']
+
+ headers, _ = self.container_client.list_container_metadata(swcont)
+ for h in acl_headers:
+ self.assertNotIn(h, headers)
+ headers, _ = self.container_client.list_container_metadata(
+ swcont_website)
+ for h in acl_headers:
+ self.assertIn(h, headers)
+
+ def test_metadata(self):
+ metadatas = {
+ "web-index": "index.html",
+ "web-error": "error.html"
+ }
+ swcont_website = self.test_resources.get(
+ 'SwiftContainerWebsite')['physical_resource_id']
+ headers, _ = self.container_client.list_container_metadata(
+ swcont_website)
+
+ for meta in metadatas:
+ header_meta = "x-container-meta-%s" % meta
+ self.assertIn(header_meta, headers)
+ self.assertEqual(headers[header_meta], metadatas[meta])
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index b0c878b..6178a1c 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -14,7 +14,7 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -86,7 +86,7 @@
super(VolumeMultiBackendTest, cls).tearDownClass()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_backend_name_reporting(self):
# this test checks if os-vol-attr:host is populated correctly after
# the multi backend feature has been enabled
@@ -100,7 +100,7 @@
self.volume1['id'])
self.assertTrue(len(volume1_host.split("@")) > 1, msg)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_backend_name_distinction(self):
# this test checks that the two volumes created at setUp don't
# belong to the same backend (if they are, than the
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 12fda92..e140ad0 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -15,7 +15,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class SnapshotsActionsTest(base.BaseVolumeV1AdminTest):
@@ -80,7 +80,7 @@
def _get_progress_alias(self):
return 'os-extended-snapshot-attributes:progress'
- @attr(type='gate')
+ @test.attr(type='gate')
def test_reset_snapshot_status(self):
# Reset snapshot status to creating
status = 'creating'
@@ -92,7 +92,7 @@
self.assertEqual(200, resp_get.status)
self.assertEqual(status, snapshot_get['status'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_snapshot_status(self):
# Reset snapshot status to creating
status = 'creating'
@@ -112,22 +112,22 @@
self.assertEqual(status, snapshot_get['status'])
self.assertEqual(progress, snapshot_get[progress_alias])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_force_delete_when_snapshot_is_creating(self):
# test force delete when status of snapshot is creating
self._create_reset_and_force_delete_temp_snapshot('creating')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_force_delete_when_snapshot_is_deleting(self):
# test force delete when status of snapshot is deleting
self._create_reset_and_force_delete_temp_snapshot('deleting')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_force_delete_when_snapshot_is_error(self):
# test force delete when status of snapshot is error
self._create_reset_and_force_delete_temp_snapshot('error')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_force_delete_when_snapshot_is_error_deleting(self):
# test force delete when status of snapshot is error_deleting
self._create_reset_and_force_delete_temp_snapshot('error_deleting')
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 5c311e1..01ba915 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -14,13 +14,13 @@
# under the License.
from tempest.api.volume import base
-from tempest.test import attr
+from tempest import test
class VolumeHostsAdminTestsJSON(base.BaseVolumeV1AdminTest):
_interface = "json"
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_hosts(self):
resp, hosts = self.hosts_client.list_hosts()
self.assertEqual(200, resp.status)
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index d481251..8183999 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -16,7 +16,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -33,14 +33,14 @@
resp, _ = self.client.delete_volume_type(volume_type_id)
self.assertEqual(202, resp.status)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_type_list(self):
# List Volume types.
resp, body = self.client.list_volume_types()
self.assertEqual(200, resp.status)
self.assertIsInstance(body, list)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_get_delete_volume_with_volume_type_and_extra_specs(self):
# Create/get/delete volume with volume_type and extra spec.
volume = {}
@@ -84,7 +84,7 @@
'The fetched Volume is different '
'from the created Volume')
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_type_create_get_delete(self):
# Create/get volume type.
body = {}
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index 99a0826..06a0b34 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -15,7 +15,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
class VolumeTypesExtraSpecsTest(base.BaseVolumeV1AdminTest):
@@ -32,7 +32,7 @@
cls.client.delete_volume_type(cls.volume_type['id'])
super(VolumeTypesExtraSpecsTest, cls).tearDownClass()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_type_extra_specs_list(self):
# List Volume types extra specs.
extra_specs = {"spec1": "val1"}
@@ -47,7 +47,7 @@
self.assertIsInstance(body, dict)
self.assertIn('spec1', body)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_type_extra_specs_update(self):
# Update volume type extra specs
extra_specs = {"spec2": "val1"}
@@ -67,7 +67,7 @@
self.assertEqual(extra_spec['spec2'], body['spec2'],
"Volume type extra spec incorrectly updated")
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_type_extra_spec_create_get_delete(self):
# Create/Get/Delete volume type extra spec.
extra_specs = {"spec3": "val1"}
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 5a1a2cd..d3a052e 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -18,7 +18,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class ExtraSpecsNegativeTest(base.BaseVolumeV1AdminTest):
@@ -38,7 +38,7 @@
cls.client.delete_volume_type(cls.volume_type['id'])
super(ExtraSpecsNegativeTest, cls).tearDownClass()
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_no_body(self):
# Should not update volume type extra specs with no body
extra_spec = {"spec1": "val2"}
@@ -46,7 +46,7 @@
self.client.update_volume_type_extra_specs,
self.volume_type['id'], extra_spec.keys()[0], None)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_nonexistent_extra_spec_id(self):
# Should not update volume type extra specs with nonexistent id.
extra_spec = {"spec1": "val2"}
@@ -55,7 +55,7 @@
self.volume_type['id'], str(uuid.uuid4()),
extra_spec)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_none_extra_spec_id(self):
# Should not update volume type extra specs with none id.
extra_spec = {"spec1": "val2"}
@@ -63,7 +63,7 @@
self.client.update_volume_type_extra_specs,
self.volume_type['id'], None, extra_spec)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_update_multiple_extra_spec(self):
# Should not update volume type extra specs with multiple specs as
# body.
@@ -73,7 +73,7 @@
self.volume_type['id'], extra_spec.keys()[0],
extra_spec)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_nonexistent_type_id(self):
# Should not create volume type extra spec for nonexistent volume
# type id.
@@ -82,21 +82,21 @@
self.client.create_volume_type_extra_specs,
str(uuid.uuid4()), extra_specs)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_none_body(self):
# Should not create volume type extra spec for none POST body.
self.assertRaises(exceptions.BadRequest,
self.client.create_volume_type_extra_specs,
self.volume_type['id'], None)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_invalid_body(self):
# Should not create volume type extra spec for invalid POST body.
self.assertRaises(exceptions.BadRequest,
self.client.create_volume_type_extra_specs,
self.volume_type['id'], ['invalid'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_nonexistent_volume_type_id(self):
# Should not delete volume type extra spec for nonexistent
# type id.
@@ -105,14 +105,14 @@
self.client.delete_volume_type_extra_specs,
str(uuid.uuid4()), extra_specs.keys()[0])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_nonexistent_volume_type_id(self):
# Should not list volume type extra spec for nonexistent type id.
self.assertRaises(exceptions.NotFound,
self.client.list_volume_types_extra_specs,
str(uuid.uuid4()))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_nonexistent_volume_type_id(self):
# Should not get volume type extra spec for nonexistent type id.
extra_specs = {"spec1": "val1"}
@@ -120,7 +120,7 @@
self.client.get_volume_type_extra_specs,
str(uuid.uuid4()), extra_specs.keys()[0])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_nonexistent_extra_spec_id(self):
# Should not get volume type extra spec for nonexistent extra spec
# id.
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 56ad227..c18e15d 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -17,13 +17,13 @@
from tempest.api.volume import base
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class VolumeTypesNegativeTest(base.BaseVolumeV1AdminTest):
_interface = 'json'
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_with_nonexistent_volume_type(self):
# Should not be able to create volume with nonexistent volume_type.
self.assertRaises(exceptions.NotFound,
@@ -31,19 +31,19 @@
display_name=str(uuid.uuid4()),
volume_type=str(uuid.uuid4()))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_with_empty_name(self):
# Should not be able to create volume type with an empty name.
self.assertRaises(exceptions.BadRequest,
self.client.create_volume_type, '')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_get_nonexistent_type_id(self):
# Should not be able to get volume type with nonexistent type id.
self.assertRaises(exceptions.NotFound, self.client.get_volume_type,
str(uuid.uuid4()))
- @attr(type='gate')
+ @test.attr(type='gate')
def test_delete_nonexistent_type_id(self):
# Should not be able to delete volume type with nonexistent type id.
self.assertRaises(exceptions.NotFound, self.client.delete_volume_type,
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 9274fce..aa00700 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -15,7 +15,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils as utils
-from tempest.test import attr
+from tempest import test
class VolumesActionsTest(base.BaseVolumeV1AdminTest):
@@ -75,7 +75,7 @@
self.assertEqual(202, resp_delete.status)
self.client.wait_for_resource_deletion(temp_volume['id'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_reset_status(self):
# test volume reset status : available->error->available
resp, body = self._reset_volume_status(self.volume['id'], 'error')
@@ -84,7 +84,7 @@
self.volume['id'])
self.assertEqual('error', volume_get['status'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_begin_detaching(self):
# test volume begin detaching : available -> detaching -> available
resp, body = self.client.volume_begin_detaching(self.volume['id'])
@@ -92,7 +92,7 @@
resp_get, volume_get = self.client.get_volume(self.volume['id'])
self.assertEqual('detaching', volume_get['status'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_roll_detaching(self):
# test volume roll detaching : detaching -> in-use -> available
resp, body = self.client.volume_begin_detaching(self.volume['id'])
@@ -110,7 +110,7 @@
# test force delete when status of volume is attaching
self._create_reset_and_force_delete_temp_volume('attaching')
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_force_delete_when_volume_is_error(self):
# test force delete when status of volume is error
self._create_reset_and_force_delete_temp_volume('error')
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 47094f0..cd6d7a8 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api.volume.base import BaseVolumeV1AdminTest
+from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
@@ -23,7 +23,7 @@
LOG = logging.getLogger(__name__)
-class VolumesBackupsTest(BaseVolumeV1AdminTest):
+class VolumesBackupsTest(base.BaseVolumeV1AdminTest):
_interface = "json"
@classmethod
@@ -38,7 +38,8 @@
cls.volume = cls.create_volume()
@test.attr(type='smoke')
- def test_volume_backup_create_get_restore_delete(self):
+ def test_volume_backup_create_get_detailed_list_restore_delete(self):
+ # Create backup
backup_name = data_utils.rand_name('Backup')
create_backup = self.backups_adm_client.create_backup
resp, backup = create_backup(self.volume['id'],
@@ -46,21 +47,31 @@
self.assertEqual(202, resp.status)
self.addCleanup(self.backups_adm_client.delete_backup,
backup['id'])
- self.assertEqual(backup['name'], backup_name)
+ self.assertEqual(backup_name, backup['name'])
self.volumes_adm_client.wait_for_volume_status(self.volume['id'],
'available')
self.backups_adm_client.wait_for_backup_status(backup['id'],
'available')
+ # Get a given backup
resp, backup = self.backups_adm_client.get_backup(backup['id'])
self.assertEqual(200, resp.status)
- self.assertEqual(backup['name'], backup_name)
+ self.assertEqual(backup_name, backup['name'])
+ # Get all backups with detail
+ resp, backups = self.backups_adm_client.list_backups_with_detail()
+ self.assertEqual(200, resp.status)
+ self.assertIn((backup['name'], backup['id']),
+ [(m['name'], m['id']) for m in backups])
+
+ # Restore backup
resp, restore = self.backups_adm_client.restore_backup(backup['id'])
self.assertEqual(202, resp.status)
+
+ # Delete backup
self.addCleanup(self.volumes_adm_client.delete_volume,
restore['volume_id'])
- self.assertEqual(restore['backup_id'], backup['id'])
+ self.assertEqual(backup['id'], restore['backup_id'])
self.backups_adm_client.wait_for_backup_status(backup['id'],
'available')
self.volumes_adm_client.wait_for_volume_status(restore['volume_id'],
diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py
index cceffd6..ce019a2 100644
--- a/tempest/api/volume/test_extensions.py
+++ b/tempest/api/volume/test_extensions.py
@@ -17,7 +17,7 @@
from tempest.api.volume import base
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -28,7 +28,7 @@
class ExtensionsTestJSON(base.BaseVolumeV1Test):
_interface = 'json'
- @attr(type='gate')
+ @test.attr(type='gate')
def test_list_extensions(self):
# List of all extensions
resp, extensions = self.volumes_extension_client.list_extensions()
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index f4b2d4c..55a72c1 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -18,7 +18,7 @@
from tempest.api.volume import base
from tempest import clients
from tempest import config
-from tempest.test import attr
+from tempest import test
CONF = config.CONF
@@ -66,7 +66,7 @@
self.assertEqual(202, resp.status)
self.adm_client.wait_for_resource_deletion(volume_id)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_create_get_list_accept_volume_transfer(self):
# Create a volume first
volume = self.create_volume()
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 284c321..82924a5 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -18,7 +18,7 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class VolumesNegativeTest(base.BaseVolumeV1Test):
@@ -33,19 +33,19 @@
cls.volume = cls.create_volume()
cls.mountpoint = "/dev/vdc"
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_get_nonexistent_volume_id(self):
# Should not be able to get a non-existent volume
self.assertRaises(exceptions.NotFound, self.client.get_volume,
str(uuid.uuid4()))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_delete_nonexistent_volume_id(self):
# Should not be able to delete a non-existent Volume
self.assertRaises(exceptions.NotFound, self.client.delete_volume,
str(uuid.uuid4()))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_invalid_size(self):
# Should not be able to create volume with invalid size
# in request
@@ -54,7 +54,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_volume,
size='#$%', display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_out_passing_size(self):
# Should not be able to create volume without passing size
# in request
@@ -63,7 +63,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_volume,
size='', display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_size_zero(self):
# Should not be able to create volume with size zero
v_name = data_utils.rand_name('Volume-')
@@ -71,7 +71,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_volume,
size='0', display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_size_negative(self):
# Should not be able to create volume with size negative
v_name = data_utils.rand_name('Volume-')
@@ -79,7 +79,7 @@
self.assertRaises(exceptions.BadRequest, self.client.create_volume,
size='-1', display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_nonexistent_volume_type(self):
# Should not be able to create volume with non-existent volume type
v_name = data_utils.rand_name('Volume-')
@@ -88,7 +88,7 @@
size='1', volume_type=str(uuid.uuid4()),
display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_nonexistent_snapshot_id(self):
# Should not be able to create volume with non-existent snapshot
v_name = data_utils.rand_name('Volume-')
@@ -97,7 +97,7 @@
size='1', snapshot_id=str(uuid.uuid4()),
display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_volume_with_nonexistent_source_volid(self):
# Should not be able to create volume with non-existent source volume
v_name = data_utils.rand_name('Volume-')
@@ -106,7 +106,7 @@
size='1', source_volid=str(uuid.uuid4()),
display_name=v_name, metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_update_volume_with_nonexistent_volume_id(self):
v_name = data_utils.rand_name('Volume-')
metadata = {'Type': 'work'}
@@ -114,7 +114,7 @@
volume_id=str(uuid.uuid4()), display_name=v_name,
metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_update_volume_with_invalid_volume_id(self):
v_name = data_utils.rand_name('Volume-')
metadata = {'Type': 'work'}
@@ -122,7 +122,7 @@
volume_id='#$%%&^&^', display_name=v_name,
metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_update_volume_with_empty_volume_id(self):
v_name = data_utils.rand_name('Volume-')
metadata = {'Type': 'work'}
@@ -130,29 +130,29 @@
volume_id='', display_name=v_name,
metadata=metadata)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_invalid_volume_id(self):
# Should not be able to get volume with invalid id
self.assertRaises(exceptions.NotFound, self.client.get_volume,
'#$%%&^&^')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_get_volume_without_passing_volume_id(self):
# Should not be able to get volume when empty ID is passed
self.assertRaises(exceptions.NotFound, self.client.get_volume, '')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_invalid_volume_id(self):
# Should not be able to delete volume when invalid ID is passed
self.assertRaises(exceptions.NotFound, self.client.delete_volume,
'!@#$%^&*()')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_delete_volume_without_passing_volume_id(self):
# Should not be able to delete volume when empty ID is passed
self.assertRaises(exceptions.NotFound, self.client.delete_volume, '')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_attach_volumes_with_nonexistent_volume_id(self):
srv_name = data_utils.rand_name('Instance-')
resp, server = self.servers_client.create_server(srv_name,
@@ -166,60 +166,60 @@
server['id'],
self.mountpoint)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_detach_volumes_with_invalid_volume_id(self):
self.assertRaises(exceptions.NotFound,
self.client.detach_volume,
'xxx')
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_extend_with_size_smaller_than_original_size(self):
# Extend volume with smaller size than original size.
extend_size = 0
self.assertRaises(exceptions.BadRequest, self.client.extend_volume,
self.volume['id'], extend_size)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_extend_with_non_number_size(self):
# Extend volume when size is non number.
extend_size = 'abc'
self.assertRaises(exceptions.BadRequest, self.client.extend_volume,
self.volume['id'], extend_size)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_extend_with_None_size(self):
# Extend volume with None size.
extend_size = None
self.assertRaises(exceptions.BadRequest, self.client.extend_volume,
self.volume['id'], extend_size)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_extend_with_nonexistent_volume_id(self):
# Extend volume size when volume is nonexistent.
extend_size = int(self.volume['size']) + 1
self.assertRaises(exceptions.NotFound, self.client.extend_volume,
str(uuid.uuid4()), extend_size)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_volume_extend_without_passing_volume_id(self):
# Extend volume size when passing volume id is None.
extend_size = int(self.volume['size']) + 1
self.assertRaises(exceptions.NotFound, self.client.extend_volume,
None, extend_size)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_reserve_volume_with_nonexistent_volume_id(self):
self.assertRaises(exceptions.NotFound,
self.client.reserve_volume,
str(uuid.uuid4()))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_unreserve_volume_with_nonexistent_volume_id(self):
self.assertRaises(exceptions.NotFound,
self.client.unreserve_volume,
str(uuid.uuid4()))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_reserve_volume_with_negative_volume_status(self):
# Mark volume as reserved.
resp, body = self.client.reserve_volume(self.volume['id'])
@@ -232,7 +232,7 @@
resp, body = self.client.unreserve_volume(self.volume['id'])
self.assertEqual(202, resp.status)
- @attr(type=['negative', 'gate'])
+ @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}
@@ -240,7 +240,7 @@
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
- @attr(type=['negative', 'gate'])
+ @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}
@@ -248,14 +248,14 @@
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_list_volumes_with_invalid_status(self):
params = {'status': 'null'}
resp, fetched_volume = self.client.list_volumes(params)
self.assertEqual(200, resp.status)
self.assertEqual(0, len(fetched_volume))
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_list_volumes_detail_with_invalid_status(self):
params = {'status': 'null'}
resp, fetched_volume = self.client.list_volumes_with_detail(params)
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 56915e6..2701e84 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -14,7 +14,7 @@
from tempest.common.utils import data_utils
from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
+from tempest import test
LOG = logging.getLogger(__name__)
CONF = config.CONF
@@ -63,7 +63,7 @@
('details' if with_detail else '', key)
self.assertEqual(params[key], snap[key], msg)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_create_with_volume_in_use(self):
# Create a snapshot when volume status is in-use
# Create a test instance
@@ -89,7 +89,7 @@
self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
self.snapshots.remove(snapshot)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshot_create_get_list_update_delete(self):
# Create a snapshot
s_name = data_utils.rand_name('snap')
@@ -134,7 +134,7 @@
self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
self.snapshots.remove(snapshot)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshots_list_with_params(self):
"""list snapshots with params."""
# Create a snapshot
@@ -155,7 +155,7 @@
'display_name': snapshot['display_name']}
self._list_by_param_values_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_snapshots_list_details_with_params(self):
"""list snapshot details with params."""
# Create a snapshot
@@ -174,7 +174,7 @@
'display_name': snapshot['display_name']}
self._list_by_param_values_and_assert(params, with_detail=True)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_from_snapshot(self):
# Create a temporary snap using wrapper method from base, then
# create a snap based volume, check resp code and deletes it
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index b24b597..9e47c03 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -15,13 +15,13 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest import exceptions
-from tempest.test import attr
+from tempest import test
class VolumesSnapshotNegativeTest(base.BaseVolumeV1Test):
_interface = "json"
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_snapshot_with_nonexistent_volume_id(self):
# Create a snapshot with nonexistent volume id
s_name = data_utils.rand_name('snap')
@@ -29,7 +29,7 @@
self.snapshots_client.create_snapshot,
str(uuid.uuid4()), display_name=s_name)
- @attr(type=['negative', 'gate'])
+ @test.attr(type=['negative', 'gate'])
def test_create_snapshot_without_passing_volume_id(self):
# Create a snapshot without passing volume id
s_name = data_utils.rand_name('snap')
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index d0e8b99..0e91371 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -18,8 +18,8 @@
from tempest.api.volume import base
from tempest.common.utils import data_utils
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from testtools.matchers import ContainsAll
+from tempest import test
+from testtools import matchers
LOG = logging.getLogger(__name__)
@@ -116,12 +116,12 @@
('details' if with_detail else '', key)
if key == 'metadata':
self.assertThat(volume[key].items(),
- ContainsAll(params[key].items()),
- msg)
+ matchers.ContainsAll(params[key]
+ .items()), msg)
else:
self.assertEqual(params[key], volume[key], msg)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_volume_list(self):
# Get a list of Volumes
# Fetch all volumes
@@ -130,7 +130,7 @@
self.assertVolumesIn(fetched_list, self.volume_list,
fields=VOLUME_FIELDS)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_details(self):
# Get a list of Volumes with details
# Fetch all Volumes
@@ -138,7 +138,7 @@
self.assertEqual(200, resp.status)
self.assertVolumesIn(fetched_list, self.volume_list)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
params = {'name': volume['name']}
@@ -147,7 +147,7 @@
self.assertEqual(1, len(fetched_vol), str(fetched_vol))
self.assertEqual(fetched_vol[0]['name'], volume['name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_details_by_name(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
params = {'name': volume['name']}
@@ -156,43 +156,43 @@
self.assertEqual(1, len(fetched_vol), str(fetched_vol))
self.assertEqual(fetched_vol[0]['name'], volume['name'])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_by_status(self):
params = {'status': 'available'}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_details_by_status(self):
params = {'status': 'available'}
self._list_by_param_value_and_assert(params, with_detail=True)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_by_availability_zone(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
zone = volume['availability_zone']
params = {'availability_zone': zone}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volumes_list_details_by_availability_zone(self):
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
zone = volume['availability_zone']
params = {'availability_zone': zone}
self._list_by_param_value_and_assert(params, with_detail=True)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_param_metadata(self):
# Test to list volumes when metadata param is given
params = {'metadata': self.metadata}
self._list_by_param_value_and_assert(params)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_detail_param_metadata(self):
# Test to list volumes details when metadata param is given
params = {'metadata': self.metadata}
self._list_by_param_value_and_assert(params, with_detail=True)
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_param_display_name_and_status(self):
# Test to list volume when display name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
@@ -200,7 +200,7 @@
'status': 'available'}
self._list_by_param_value_and_assert(params, expected_list=[volume])
- @attr(type='gate')
+ @test.attr(type='gate')
def test_volume_list_with_detail_param_display_name_and_status(self):
# Test to list volume when name and status param is given
volume = self.volume_list[data_utils.rand_int_id(0, 2)]
diff --git a/tempest/auth.py b/tempest/auth.py
index e1ba13b..0e45161 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -14,11 +14,11 @@
# under the License.
import copy
+import datetime
import exceptions
import re
import urlparse
-from datetime import datetime
from tempest import config
from tempest.services.identity.json import identity_client as json_id
from tempest.services.identity.v3.json import identity_client as json_v3id
@@ -291,9 +291,9 @@
def is_expired(self, auth_data):
_, access = auth_data
- expiry = datetime.strptime(access['token']['expires'],
- self.EXPIRY_DATE_FORMAT)
- return expiry <= datetime.now()
+ expiry = datetime.datetime.strptime(access['token']['expires'],
+ self.EXPIRY_DATE_FORMAT)
+ return expiry <= datetime.datetime.now()
class KeystoneV3AuthProvider(KeystoneAuthProvider):
@@ -382,7 +382,7 @@
path = "/" + filters['api_version']
noversion_path = "/".join(parts.path.split("/")[2:])
if noversion_path != "":
- path += noversion_path
+ path += "/" + noversion_path
_base_url = _base_url.replace(parts.path, path)
if filters.get('skip_path', None) is not None:
_base_url = _base_url.replace(parts.path, "/")
@@ -391,6 +391,6 @@
def is_expired(self, auth_data):
_, access = auth_data
- expiry = datetime.strptime(access['expires_at'],
- self.EXPIRY_DATE_FORMAT)
- return expiry <= datetime.now()
+ expiry = datetime.datetime.strptime(access['expires_at'],
+ self.EXPIRY_DATE_FORMAT)
+ return expiry <= datetime.datetime.now()
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/test_nova.py
index b0264d0..d0b6028 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -154,12 +154,18 @@
def test_admin_usage_list(self):
self.nova('usage-list')
+ @testtools.skipIf(not CONF.service_available.cinder,
+ "Skipped as Cinder is not available")
def test_admin_volume_list(self):
self.nova('volume-list')
+ @testtools.skipIf(not CONF.service_available.cinder,
+ "Skipped as Cinder is not available")
def test_admin_volume_snapshot_list(self):
self.nova('volume-snapshot-list')
+ @testtools.skipIf(not CONF.service_available.cinder,
+ "Skipped as Cinder is not available")
def test_admin_volume_type_list(self):
self.nova('volume-type-list')
diff --git a/tempest/clients.py b/tempest/clients.py
index 8db399a..e16d0f4 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -114,6 +114,8 @@
from tempest.services.compute.xml.volumes_extensions_client import \
VolumesExtensionsClientXML
from tempest.services.data_processing.v1_1.client import DataProcessingClient
+from tempest.services.database.json.flavors_client import \
+ DatabaseFlavorsClientJSON
from tempest.services.identity.json.identity_client import IdentityClientJSON
from tempest.services.identity.json.identity_client import TokenClientJSON
from tempest.services.identity.v3.json.credentials_client import \
@@ -330,6 +332,8 @@
self.volumes_extension_client = VolumeExtensionClientJSON(
self.auth_provider)
self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
+ self.database_flavors_client = DatabaseFlavorsClientJSON(
+ self.auth_provider)
if CONF.service_available.ceilometer:
self.telemetry_client = TelemetryClientJSON(
self.auth_provider)
diff --git a/tempest/common/generate_json.py b/tempest/common/generate_json.py
deleted file mode 100644
index c8e86dc..0000000
--- a/tempest/common/generate_json.py
+++ /dev/null
@@ -1,265 +0,0 @@
-# Copyright 2014 Red Hat, Inc. & Deutsche Telekom AG
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import copy
-import jsonschema
-
-from tempest.openstack.common import log as logging
-
-LOG = logging.getLogger(__name__)
-
-
-def generate_valid(schema):
- """
- Create a valid dictionary based on the types in a json schema.
- """
- LOG.debug("generate_valid: %s" % schema)
- schema_type = schema["type"]
- if isinstance(schema_type, list):
- # Just choose the first one since all are valid.
- schema_type = schema_type[0]
- return type_map_valid[schema_type](schema)
-
-
-def generate_valid_string(schema):
- size = schema.get("minLength", 0)
- # TODO(dkr mko): handle format and pattern
- return "x" * size
-
-
-def generate_valid_integer(schema):
- # TODO(dkr mko): handle multipleOf
- if "minimum" in schema:
- minimum = schema["minimum"]
- if "exclusiveMinimum" not in schema:
- return minimum
- else:
- return minimum + 1
- if "maximum" in schema:
- maximum = schema["maximum"]
- if "exclusiveMaximum" not in schema:
- return maximum
- else:
- return maximum - 1
- return 0
-
-
-def generate_valid_object(schema):
- obj = {}
- for k, v in schema["properties"].iteritems():
- obj[k] = generate_valid(v)
- return obj
-
-
-def generate_invalid(schema):
- """
- Generate an invalid json dictionary based on a schema.
- Only one value is mis-generated for each dictionary created.
-
- Any generator must return a list of tuples or a single tuple.
- The values of this tuple are:
- result[0]: Name of the test
- result[1]: json schema for the test
- result[2]: expected result of the test (can be None)
- """
- LOG.debug("generate_invalid: %s" % schema)
- schema_type = schema["type"]
- if isinstance(schema_type, list):
- if "integer" in schema_type:
- schema_type = "integer"
- else:
- raise Exception("non-integer list types not supported")
- result = []
- for generator in type_map_invalid[schema_type]:
- ret = generator(schema)
- if ret is not None:
- if isinstance(ret, list):
- result.extend(ret)
- elif isinstance(ret, tuple):
- result.append(ret)
- else:
- raise Exception("generator (%s) returns invalid result"
- % generator)
- LOG.debug("result: %s" % result)
- return result
-
-
-def _check_for_expected_result(name, schema):
- expected_result = None
- if "results" in schema:
- if name in schema["results"]:
- expected_result = schema["results"][name]
- return expected_result
-
-
-def generator(fn):
- """
- Decorator for simple generators that simply return one value
- """
- def wrapped(schema):
- result = fn(schema)
- if result is not None:
- expected_result = _check_for_expected_result(fn.__name__, schema)
- return (fn.__name__, result, expected_result)
- return
- return wrapped
-
-
-@generator
-def gen_int(_):
- return 4
-
-
-@generator
-def gen_string(_):
- return "XXXXXX"
-
-
-def gen_none(schema):
- # Note(mkoderer): it's not using the decorator otherwise it'd be filtered
- expected_result = _check_for_expected_result('gen_none', schema)
- return ('gen_none', None, expected_result)
-
-
-@generator
-def gen_str_min_length(schema):
- min_length = schema.get("minLength", 0)
- if min_length > 0:
- return "x" * (min_length - 1)
-
-
-@generator
-def gen_str_max_length(schema):
- max_length = schema.get("maxLength", -1)
- if max_length > -1:
- return "x" * (max_length + 1)
-
-
-@generator
-def gen_int_min(schema):
- if "minimum" in schema:
- minimum = schema["minimum"]
- if "exclusiveMinimum" not in schema:
- minimum -= 1
- return minimum
-
-
-@generator
-def gen_int_max(schema):
- if "maximum" in schema:
- maximum = schema["maximum"]
- if "exclusiveMaximum" not in schema:
- maximum += 1
- return maximum
-
-
-def gen_obj_remove_attr(schema):
- invalids = []
- valid = generate_valid(schema)
- required = schema.get("required", [])
- for r in required:
- new_valid = copy.deepcopy(valid)
- del new_valid[r]
- invalids.append(("gen_obj_remove_attr", new_valid, None))
- return invalids
-
-
-@generator
-def gen_obj_add_attr(schema):
- valid = generate_valid(schema)
- if not schema.get("additionalProperties", True):
- new_valid = copy.deepcopy(valid)
- new_valid["$$$$$$$$$$"] = "xxx"
- return new_valid
-
-
-def gen_inv_prop_obj(schema):
- LOG.debug("generate_invalid_object: %s" % schema)
- valid = generate_valid(schema)
- invalids = []
- properties = schema["properties"]
-
- for k, v in properties.iteritems():
- for invalid in generate_invalid(v):
- LOG.debug(v)
- new_valid = copy.deepcopy(valid)
- new_valid[k] = invalid[1]
- name = "prop_%s_%s" % (k, invalid[0])
- invalids.append((name, new_valid, invalid[2]))
-
- LOG.debug("generate_invalid_object return: %s" % invalids)
- return invalids
-
-
-type_map_valid = {
- "string": generate_valid_string,
- "integer": generate_valid_integer,
- "object": generate_valid_object
-}
-
-type_map_invalid = {
- "string": [
- gen_int,
- gen_none,
- gen_str_min_length,
- gen_str_max_length],
- "integer": [
- gen_string,
- gen_none,
- gen_int_min,
- gen_int_max],
- "object": [
- gen_obj_remove_attr,
- gen_obj_add_attr,
- gen_inv_prop_obj]
-}
-
-schema = {
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "http-method": {
- "enum": ["GET", "PUT", "HEAD",
- "POST", "PATCH", "DELETE", 'COPY']
- },
- "url": {"type": "string"},
- "json-schema": jsonschema._utils.load_schema("draft4"),
- "resources": {
- "type": "array",
- "items": {
- "oneOf": [
- {"type": "string"},
- {
- "type": "object",
- "properties": {
- "name": {"type": "string"},
- "expected_result": {"type": "integer"}
- }
- }
- ]
- }
- },
- "results": {
- "type": "object",
- "properties": {}
- }
- },
- "required": ["name", "http-method", "url"],
- "additionalProperties": False,
-}
-
-
-def validate_negative_test_schema(nts):
- jsonschema.validate(nts, schema)
diff --git a/tempest/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
index e1213db..ceb3394 100644
--- a/tempest/common/generate_sample_tempest.py
+++ b/tempest/common/generate_sample_tempest.py
@@ -31,5 +31,5 @@
if __name__ == "__main__":
- CONF = tempest.config.TempestConfigPrivate(False)
+ tempest.config.register_opts()
generator.generate(sys.argv[1:])
diff --git a/tempest/common/generator/__init__.py b/tempest/common/generator/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/common/generator/__init__.py
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
new file mode 100644
index 0000000..35f8158
--- /dev/null
+++ b/tempest/common/generator/base_generator.py
@@ -0,0 +1,141 @@
+# Copyright 2014 Deutsche Telekom AG
+# 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 jsonschema
+
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+def _check_for_expected_result(name, schema):
+ expected_result = None
+ if "results" in schema:
+ if name in schema["results"]:
+ expected_result = schema["results"][name]
+ return expected_result
+
+
+def generator_type(*args):
+ def wrapper(func):
+ func.types = args
+ return func
+ return wrapper
+
+
+def simple_generator(fn):
+ """
+ Decorator for simple generators that return one value
+ """
+ def wrapped(self, schema):
+ result = fn(self, schema)
+ if result is not None:
+ expected_result = _check_for_expected_result(fn.__name__, schema)
+ return (fn.__name__, result, expected_result)
+ return
+ return wrapped
+
+
+class BasicGeneratorSet(object):
+ _instance = None
+
+ schema = {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "http-method": {
+ "enum": ["GET", "PUT", "HEAD",
+ "POST", "PATCH", "DELETE", 'COPY']
+ },
+ "url": {"type": "string"},
+ "json-schema": jsonschema._utils.load_schema("draft4"),
+ "resources": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ {"type": "string"},
+ {
+ "type": "object",
+ "properties": {
+ "name": {"type": "string"},
+ "expected_result": {"type": "integer"}
+ }
+ }
+ ]
+ }
+ },
+ "results": {
+ "type": "object",
+ "properties": {}
+ }
+ },
+ "required": ["name", "http-method", "url"],
+ "additionalProperties": False,
+ }
+
+ def __new__(cls, *args, **kwargs):
+ if not cls._instance:
+ cls._instance = super(BasicGeneratorSet, cls).__new__(cls, *args,
+ **kwargs)
+ return cls._instance
+
+ def __init__(self):
+ self.types_dict = {}
+ for m in dir(self):
+ if callable(getattr(self, m)) and not'__' in m:
+ method = getattr(self, m)
+ if hasattr(method, "types"):
+ for type in method.types:
+ if type not in self.types_dict:
+ self.types_dict[type] = []
+ self.types_dict[type].append(method)
+
+ def validate_schema(self, schema):
+ jsonschema.validate(schema, self.schema)
+
+ def generate(self, schema):
+ """
+ Generate an json dictionary based on a schema.
+ Only one value is mis-generated for each dictionary created.
+
+ Any generator must return a list of tuples or a single tuple.
+ The values of this tuple are:
+ result[0]: Name of the test
+ result[1]: json schema for the test
+ result[2]: expected result of the test (can be None)
+ """
+ LOG.debug("generate_invalid: %s" % schema)
+ schema_type = schema["type"]
+ if isinstance(schema_type, list):
+ if "integer" in schema_type:
+ schema_type = "integer"
+ else:
+ raise Exception("non-integer list types not supported")
+ result = []
+ if schema_type not in self.types_dict:
+ raise Exception("generator (%s) doesn't support type: %s"
+ % (self.__class__.__name__, schema_type))
+ for generator in self.types_dict[schema_type]:
+ ret = generator(schema)
+ if ret is not None:
+ if isinstance(ret, list):
+ result.extend(ret)
+ elif isinstance(ret, tuple):
+ result.append(ret)
+ else:
+ raise Exception("generator (%s) returns invalid result: %s"
+ % (generator, ret))
+ LOG.debug("result: %s" % result)
+ return result
diff --git a/tempest/common/generator/negative_generator.py b/tempest/common/generator/negative_generator.py
new file mode 100644
index 0000000..4f3d2cd
--- /dev/null
+++ b/tempest/common/generator/negative_generator.py
@@ -0,0 +1,111 @@
+# Copyright 2014 Deutsche Telekom AG
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+import tempest.common.generator.base_generator as base
+import tempest.common.generator.valid_generator as valid
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+class NegativeTestGenerator(base.BasicGeneratorSet):
+ @base.generator_type("string")
+ @base.simple_generator
+ def gen_int(self, _):
+ return 4
+
+ @base.generator_type("integer")
+ @base.simple_generator
+ def gen_string(self, _):
+ return "XXXXXX"
+
+ @base.generator_type("integer", "string")
+ def gen_none(self, schema):
+ # Note(mkoderer): it's not using the decorator otherwise it'd be
+ # filtered
+ expected_result = base._check_for_expected_result('gen_none', schema)
+ return ('gen_none', None, expected_result)
+
+ @base.generator_type("string")
+ @base.simple_generator
+ def gen_str_min_length(self, schema):
+ min_length = schema.get("minLength", 0)
+ if min_length > 0:
+ return "x" * (min_length - 1)
+
+ @base.generator_type("string")
+ @base.simple_generator
+ def gen_str_max_length(self, schema):
+ max_length = schema.get("maxLength", -1)
+ if max_length > -1:
+ return "x" * (max_length + 1)
+
+ @base.generator_type("integer")
+ @base.simple_generator
+ def gen_int_min(self, schema):
+ if "minimum" in schema:
+ minimum = schema["minimum"]
+ if "exclusiveMinimum" not in schema:
+ minimum -= 1
+ return minimum
+
+ @base.generator_type("integer")
+ @base.simple_generator
+ def gen_int_max(self, schema):
+ if "maximum" in schema:
+ maximum = schema["maximum"]
+ if "exclusiveMaximum" not in schema:
+ maximum += 1
+ return maximum
+
+ @base.generator_type("object")
+ def gen_obj_remove_attr(self, schema):
+ invalids = []
+ valid_schema = valid.ValidTestGenerator().generate_valid(schema)
+ required = schema.get("required", [])
+ for r in required:
+ new_valid = copy.deepcopy(valid_schema)
+ del new_valid[r]
+ invalids.append(("gen_obj_remove_attr", new_valid, None))
+ return invalids
+
+ @base.generator_type("object")
+ @base.simple_generator
+ def gen_obj_add_attr(self, schema):
+ valid_schema = valid.ValidTestGenerator().generate_valid(schema)
+ if not schema.get("additionalProperties", True):
+ new_valid = copy.deepcopy(valid_schema)
+ new_valid["$$$$$$$$$$"] = "xxx"
+ return new_valid
+
+ @base.generator_type("object")
+ def gen_inv_prop_obj(self, schema):
+ LOG.debug("generate_invalid_object: %s" % schema)
+ valid_schema = valid.ValidTestGenerator().generate_valid(schema)
+ invalids = []
+ properties = schema["properties"]
+
+ for k, v in properties.iteritems():
+ for invalid in self.generate(v):
+ LOG.debug(v)
+ new_valid = copy.deepcopy(valid_schema)
+ new_valid[k] = invalid[1]
+ name = "prop_%s_%s" % (k, invalid[0])
+ invalids.append((name, new_valid, invalid[2]))
+
+ LOG.debug("generate_invalid_object return: %s" % invalids)
+ return invalids
diff --git a/tempest/common/generator/valid_generator.py b/tempest/common/generator/valid_generator.py
new file mode 100644
index 0000000..a99bbc0
--- /dev/null
+++ b/tempest/common/generator/valid_generator.py
@@ -0,0 +1,58 @@
+# Copyright 2014 Deutsche Telekom AG
+# 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 tempest.common.generator.base_generator as base
+from tempest.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
+
+
+class ValidTestGenerator(base.BasicGeneratorSet):
+ @base.generator_type("string")
+ @base.simple_generator
+ def generate_valid_string(self, schema):
+ size = schema.get("minLength", 0)
+ # TODO(dkr mko): handle format and pattern
+ return "x" * size
+
+ @base.generator_type("integer")
+ @base.simple_generator
+ def generate_valid_integer(self, schema):
+ # TODO(dkr mko): handle multipleOf
+ if "minimum" in schema:
+ minimum = schema["minimum"]
+ if "exclusiveMinimum" not in schema:
+ return minimum
+ else:
+ return minimum + 1
+ if "maximum" in schema:
+ maximum = schema["maximum"]
+ if "exclusiveMaximum" not in schema:
+ return maximum
+ else:
+ return maximum - 1
+ return 0
+
+ @base.generator_type("object")
+ @base.simple_generator
+ def generate_valid_object(self, schema):
+ obj = {}
+ for k, v in schema["properties"].iteritems():
+ obj[k] = self.generate_valid(v)
+ return obj
+
+ def generate_valid(self, schema):
+ return self.generate(schema)[0][1]
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index 4503f13..b4ba933 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -21,6 +21,7 @@
import json
import posixpath
import re
+from six import moves
import socket
import StringIO
import struct
@@ -264,7 +265,7 @@
# Also try Subject Alternative Names for a match
san_list = None
- for i in xrange(x509.get_extension_count()):
+ for i in moves.xrange(x509.get_extension_count()):
ext = x509.get_extension(i)
if ext.get_short_name() == 'subjectAltName':
san_list = str(ext)
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 03dccd4..66b6fe7 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -25,7 +25,7 @@
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -299,11 +299,11 @@
# Parse list-like xmls (users, roles, etc)
array = []
for child in element.getchildren():
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
# Parse one-item-like xmls (user, role, etc)
- return xml_to_json(element)
+ return common.xml_to_json(element)
def response_checker(self, method, url, headers, body, resp, resp_body):
if (resp.status in set((204, 205, 304)) or resp.status < 200 or
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index b6fa0a0..531887c 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -16,6 +16,7 @@
import cStringIO
import select
+import six
import socket
import time
import warnings
@@ -39,7 +40,7 @@
self.host = host
self.username = username
self.password = password
- if isinstance(pkey, basestring):
+ if isinstance(pkey, six.string_types):
pkey = paramiko.RSAKey.from_private_key(
cStringIO.StringIO(str(pkey)))
self.pkey = pkey
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 94fc23c..8420ad0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -11,6 +11,7 @@
# under the License.
import re
+import six
import time
from tempest.common import ssh
@@ -28,7 +29,7 @@
network = CONF.compute.network_for_ssh
ip_version = CONF.compute.ip_version_for_ssh
ssh_channel_timeout = CONF.compute.ssh_channel_timeout
- if isinstance(server, basestring):
+ if isinstance(server, six.string_types):
ip_address = server
else:
addresses = server['addresses'][network]
@@ -93,3 +94,18 @@
def get_mac_address(self):
cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
return self.ssh_client.exec_command(cmd)
+
+ def get_ip_list(self):
+ cmd = "/bin/ip address"
+ return self.ssh_client.exec_command(cmd)
+
+ def assign_static_ip(self, nic, addr):
+ cmd = "sudo /bin/ip addr add {ip}/{mask} dev {nic}".format(
+ ip=addr, mask=CONF.network.tenant_network_mask_bits,
+ nic=nic
+ )
+ return self.ssh_client.exec_command(cmd)
+
+ def turn_nic_on(self, nic):
+ cmd = "sudo /bin/ip link set {nic} up".format(nic=nic)
+ return self.ssh_client.exec_command(cmd)
diff --git a/tempest/config.py b/tempest/config.py
index ad91494..db81f6e 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -263,7 +263,11 @@
cfg.BoolOpt('block_migrate_cinder_iscsi',
default=False,
help="Does the test environment block migration support "
- "cinder iSCSI volumes")
+ "cinder iSCSI volumes"),
+ cfg.BoolOpt('vnc_console',
+ default=False,
+ help='Enable VNC console. This configuration value should '
+ 'be same as [nova.vnc]->vnc_enabled in nova.conf')
]
@@ -344,9 +348,6 @@
cfg.IntOpt('tenant_network_mask_bits',
default=28,
help="The mask bits for tenant ipv4 subnets"),
- cfg.BoolOpt('ipv6_enabled',
- default=True,
- help="Allow the execution of IPv6 tests"),
cfg.StrOpt('tenant_network_v6_cidr',
default="2003::/64",
help="The cidr block to allocate tenant ipv6 subnets from"),
@@ -371,6 +372,9 @@
title='Enabled network service features')
NetworkFeaturesGroup = [
+ cfg.BoolOpt('ipv6',
+ default=True,
+ help="Allow the execution of IPv6 tests"),
cfg.ListOpt('api_extensions',
default=['all'],
help='A list of enabled network extensions with a special '
@@ -472,6 +476,9 @@
default='Member',
help="Role to add to users created for swift tests to "
"enable creating containers"),
+ cfg.StrOpt('reseller_admin_role',
+ default='ResellerAdmin',
+ help="User role that has reseller admin"),
]
object_storage_feature_group = cfg.OptGroup(
@@ -486,6 +493,17 @@
"features are expected to be enabled"),
]
+database_group = cfg.OptGroup(name='database',
+ title='Database Service Options')
+
+DatabaseGroup = [
+ cfg.StrOpt('catalog_type',
+ default='database',
+ help="Catalog type of the Database service."),
+ cfg.StrOpt('db_flavor_ref',
+ default="1",
+ help="Valid primary flavor to use in database tests."),
+]
orchestration_group = cfg.OptGroup(name='orchestration',
title='Orchestration Service Options')
@@ -515,7 +533,7 @@
default=1,
help="Time in seconds between build status checks."),
cfg.IntOpt('build_timeout',
- default=300,
+ default=600,
help="Timeout in seconds to wait for a stack to build."),
cfg.StrOpt('instance_type',
default='m1.micro',
@@ -541,6 +559,11 @@
cfg.StrOpt('catalog_type',
default='metering',
help="Catalog type of the Telemetry service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the telemetry service."),
]
@@ -563,7 +586,13 @@
DataProcessingGroup = [
cfg.StrOpt('catalog_type',
default='data_processing',
- help="Catalog type of the data processing service.")
+ help="Catalog type of the data processing service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the data processing "
+ "service."),
]
@@ -721,6 +750,9 @@
cfg.BoolOpt('ironic',
default=False,
help="Whether or not Ironic is expected to be available"),
+ cfg.BoolOpt('trove',
+ default=False,
+ help="Whether or not Trove is expected to be available"),
]
debug_group = cfg.OptGroup(name="debug",
@@ -761,6 +793,12 @@
cfg.StrOpt('catalog_type',
default='baremetal',
help="Catalog type of the baremetal provisioning service."),
+ cfg.StrOpt('endpoint_type',
+ default='publicURL',
+ choices=['public', 'admin', 'internal',
+ 'publicURL', 'adminURL', 'internalURL'],
+ help="The endpoint type to use for the baremetal provisioning "
+ "service."),
]
cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options")
@@ -782,6 +820,52 @@
help="Number of seconds to wait on a CLI timeout"),
]
+negative_group = cfg.OptGroup(name='negative', title="Negative Test Options")
+
+NegativeGroup = [
+ cfg.StrOpt('test_generator',
+ default='tempest.common.' +
+ 'generator.negative_generator.NegativeTestGenerator',
+ help="Test generator class for all negative tests"),
+]
+
+
+def register_opts():
+ register_opt_group(cfg.CONF, compute_group, ComputeGroup)
+ register_opt_group(cfg.CONF, compute_features_group,
+ ComputeFeaturesGroup)
+ register_opt_group(cfg.CONF, identity_group, IdentityGroup)
+ register_opt_group(cfg.CONF, identity_feature_group,
+ IdentityFeatureGroup)
+ register_opt_group(cfg.CONF, image_group, ImageGroup)
+ register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
+ register_opt_group(cfg.CONF, network_group, NetworkGroup)
+ register_opt_group(cfg.CONF, network_feature_group,
+ NetworkFeaturesGroup)
+ register_opt_group(cfg.CONF, volume_group, VolumeGroup)
+ register_opt_group(cfg.CONF, volume_feature_group,
+ VolumeFeaturesGroup)
+ register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
+ register_opt_group(cfg.CONF, object_storage_feature_group,
+ ObjectStoreFeaturesGroup)
+ register_opt_group(cfg.CONF, database_group, DatabaseGroup)
+ register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
+ register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
+ register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
+ register_opt_group(cfg.CONF, data_processing_group,
+ DataProcessingGroup)
+ register_opt_group(cfg.CONF, boto_group, BotoGroup)
+ register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
+ register_opt_group(cfg.CONF, stress_group, StressGroup)
+ register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
+ register_opt_group(cfg.CONF, service_available_group,
+ ServiceAvailableGroup)
+ register_opt_group(cfg.CONF, debug_group, DebugGroup)
+ register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
+ register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
+ register_opt_group(cfg.CONF, cli_group, CLIGroup)
+ register_opt_group(cfg.CONF, negative_group, NegativeGroup)
+
# this should never be called outside of this class
class TempestConfigPrivate(object):
@@ -793,6 +877,40 @@
DEFAULT_CONFIG_FILE = "tempest.conf"
+ def _set_attrs(self):
+ self.compute = cfg.CONF.compute
+ self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
+ self.identity = cfg.CONF.identity
+ self.identity_feature_enabled = cfg.CONF['identity-feature-enabled']
+ self.image = cfg.CONF.image
+ self.image_feature_enabled = cfg.CONF['image-feature-enabled']
+ self.network = cfg.CONF.network
+ self.network_feature_enabled = cfg.CONF['network-feature-enabled']
+ self.volume = cfg.CONF.volume
+ self.volume_feature_enabled = cfg.CONF['volume-feature-enabled']
+ self.object_storage = cfg.CONF['object-storage']
+ self.object_storage_feature_enabled = cfg.CONF[
+ 'object-storage-feature-enabled']
+ self.database = cfg.CONF.database
+ self.orchestration = cfg.CONF.orchestration
+ self.telemetry = cfg.CONF.telemetry
+ self.dashboard = cfg.CONF.dashboard
+ self.data_processing = cfg.CONF.data_processing
+ self.boto = cfg.CONF.boto
+ self.compute_admin = cfg.CONF['compute-admin']
+ self.stress = cfg.CONF.stress
+ self.scenario = cfg.CONF.scenario
+ self.service_available = cfg.CONF.service_available
+ self.debug = cfg.CONF.debug
+ self.baremetal = cfg.CONF.baremetal
+ self.input_scenario = cfg.CONF['input-scenario']
+ self.cli = cfg.CONF.cli
+ self.negative = cfg.CONF.negative
+ if not self.compute_admin.username:
+ self.compute_admin.username = self.identity.admin_username
+ self.compute_admin.password = self.identity.admin_password
+ self.compute_admin.tenant_name = self.identity.admin_tenant_name
+
def __init__(self, parse_conf=True):
"""Initialize a configuration from a conf directory and conf file."""
super(TempestConfigPrivate, self).__init__()
@@ -818,70 +936,8 @@
logging.setup('tempest')
LOG = logging.getLogger('tempest')
LOG.info("Using tempest config file %s" % path)
-
- register_opt_group(cfg.CONF, compute_group, ComputeGroup)
- register_opt_group(cfg.CONF, compute_features_group,
- ComputeFeaturesGroup)
- register_opt_group(cfg.CONF, identity_group, IdentityGroup)
- register_opt_group(cfg.CONF, identity_feature_group,
- IdentityFeatureGroup)
- register_opt_group(cfg.CONF, image_group, ImageGroup)
- register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
- register_opt_group(cfg.CONF, network_group, NetworkGroup)
- register_opt_group(cfg.CONF, network_feature_group,
- NetworkFeaturesGroup)
- register_opt_group(cfg.CONF, volume_group, VolumeGroup)
- register_opt_group(cfg.CONF, volume_feature_group,
- VolumeFeaturesGroup)
- register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
- register_opt_group(cfg.CONF, object_storage_feature_group,
- ObjectStoreFeaturesGroup)
- register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
- register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
- register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
- register_opt_group(cfg.CONF, data_processing_group,
- DataProcessingGroup)
- register_opt_group(cfg.CONF, boto_group, BotoGroup)
- register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
- register_opt_group(cfg.CONF, stress_group, StressGroup)
- register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
- register_opt_group(cfg.CONF, service_available_group,
- ServiceAvailableGroup)
- register_opt_group(cfg.CONF, debug_group, DebugGroup)
- register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
- register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
- register_opt_group(cfg.CONF, cli_group, CLIGroup)
- self.compute = cfg.CONF.compute
- self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
- self.identity = cfg.CONF.identity
- self.identity_feature_enabled = cfg.CONF['identity-feature-enabled']
- self.image = cfg.CONF.image
- self.image_feature_enabled = cfg.CONF['image-feature-enabled']
- self.network = cfg.CONF.network
- self.network_feature_enabled = cfg.CONF['network-feature-enabled']
- self.volume = cfg.CONF.volume
- self.volume_feature_enabled = cfg.CONF['volume-feature-enabled']
- self.object_storage = cfg.CONF['object-storage']
- self.object_storage_feature_enabled = cfg.CONF[
- 'object-storage-feature-enabled']
- self.orchestration = cfg.CONF.orchestration
- self.telemetry = cfg.CONF.telemetry
- self.dashboard = cfg.CONF.dashboard
- self.data_processing = cfg.CONF.data_processing
- self.boto = cfg.CONF.boto
- self.compute_admin = cfg.CONF['compute-admin']
- self.stress = cfg.CONF.stress
- self.scenario = cfg.CONF.scenario
- self.service_available = cfg.CONF.service_available
- self.debug = cfg.CONF.debug
- self.baremetal = cfg.CONF.baremetal
- self.input_scenario = cfg.CONF['input-scenario']
- self.cli = cfg.CONF.cli
- if not self.compute_admin.username:
- self.compute_admin.username = self.identity.admin_username
- self.compute_admin.password = self.identity.admin_password
- self.compute_admin.tenant_name = self.identity.admin_tenant_name
-
+ register_opts()
+ self._set_attrs()
if parse_conf:
cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
deleted file mode 100644
index ac88faa..0000000
--- a/tempest/exceptions.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import testtools
-
-
-class TempestException(Exception):
- """
- Base Tempest Exception
-
- To correctly use this class, inherit from it and define
- a 'message' property. That message will get printf'd
- with the keyword arguments provided to the constructor.
- """
- message = "An unknown exception occurred"
-
- def __init__(self, *args, **kwargs):
- super(TempestException, self).__init__()
- try:
- self._error_string = self.message % kwargs
- except Exception:
- # at least get the core message out if something happened
- self._error_string = self.message
- if len(args) > 0:
- # If there is a non-kwarg parameter, assume it's the error
- # message or reason description and tack it on to the end
- # of the exception message
- # Convert all arguments into their string representations...
- args = ["%s" % arg for arg in args]
- self._error_string = (self._error_string +
- "\nDetails: %s" % '\n'.join(args))
-
- def __str__(self):
- return self._error_string
-
-
-class InvalidConfiguration(TempestException):
- message = "Invalid Configuration"
-
-
-class RestClientException(TempestException,
- testtools.TestCase.failureException):
- pass
-
-
-class InvalidHttpSuccessCode(RestClientException):
- message = "The success code is different than the expected one"
-
-
-class NotFound(RestClientException):
- message = "Object not found"
-
-
-class Unauthorized(RestClientException):
- message = 'Unauthorized'
-
-
-class InvalidServiceTag(RestClientException):
- message = "Invalid service tag"
-
-
-class TimeoutException(TempestException):
- message = "Request timed out"
-
-
-class BuildErrorException(TempestException):
- message = "Server %(server_id)s failed to build and is in ERROR status"
-
-
-class ImageKilledException(TempestException):
- message = "Image %(image_id)s 'killed' while waiting for '%(status)s'"
-
-
-class AddImageException(TempestException):
- message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
-
-
-class EC2RegisterImageException(TempestException):
- message = ("Image %(image_id)s failed to become 'available' "
- "in the allotted time")
-
-
-class VolumeBuildErrorException(TempestException):
- message = "Volume %(volume_id)s failed to build and is in ERROR status"
-
-
-class SnapshotBuildErrorException(TempestException):
- message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
-
-
-class VolumeBackupException(TempestException):
- message = "Volume backup %(backup_id)s failed and is in ERROR status"
-
-
-class StackBuildErrorException(TempestException):
- message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
- "due to '%(stack_status_reason)s'")
-
-
-class BadRequest(RestClientException):
- message = "Bad request"
-
-
-class UnprocessableEntity(RestClientException):
- message = "Unprocessable entity"
-
-
-class AuthenticationFailure(RestClientException):
- message = ("Authentication with user %(user)s and password "
- "%(password)s failed auth using tenant %(tenant)s.")
-
-
-class EndpointNotFound(TempestException):
- message = "Endpoint not found"
-
-
-class RateLimitExceeded(TempestException):
- message = "Rate limit exceeded"
-
-
-class OverLimit(TempestException):
- message = "Quota exceeded"
-
-
-class ServerFault(TempestException):
- message = "Got server fault"
-
-
-class ImageFault(TempestException):
- message = "Got image fault"
-
-
-class IdentityError(TempestException):
- message = "Got identity error"
-
-
-class Conflict(RestClientException):
- message = "An object with that identifier already exists"
-
-
-class SSHTimeout(TempestException):
- message = ("Connection to the %(host)s via SSH timed out.\n"
- "User: %(user)s, Password: %(password)s")
-
-
-class SSHExecCommandFailed(TempestException):
- """Raised when remotely executed command returns nonzero status."""
- message = ("Command '%(command)s', exit status: %(exit_status)d, "
- "Error:\n%(strerror)s")
-
-
-class ServerUnreachable(TempestException):
- message = "The server is not reachable via the configured network"
-
-
-class TearDownException(TempestException):
- message = "%(num)d cleanUp operation failed"
-
-
-class RFCViolation(RestClientException):
- message = "RFC Violation"
-
-
-class ResponseWithNonEmptyBody(RFCViolation):
- message = ("RFC Violation! Response with %(status)d HTTP Status Code "
- "MUST NOT have a body")
-
-
-class ResponseWithEntity(RFCViolation):
- message = ("RFC Violation! Response with 205 HTTP Status Code "
- "MUST NOT have an entity")
-
-
-class InvalidHTTPResponseBody(RestClientException):
- message = "HTTP response body is invalid json or xml"
diff --git a/tempest/exceptions/README.rst b/tempest/exceptions/README.rst
new file mode 100644
index 0000000..dbe42b2
--- /dev/null
+++ b/tempest/exceptions/README.rst
@@ -0,0 +1,27 @@
+Tempest Field Guide to Exceptions
+=================================
+
+
+What are these exceptions?
+--------------------------
+
+These exceptions are used by Tempest for covering OpenStack specific exceptional
+cases.
+
+How to add new exceptions?
+--------------------------
+
+Each exception-template for inheritance purposes should be added into 'base'
+submodule.
+All other exceptions can be added in two ways:
+- in main module
+- in submodule
+But only in one of the ways. Need to make sure, that new exception is not
+present already.
+
+How to use exceptions?
+----------------------
+
+Any exceptions from this module or its submodules should be used in appropriate
+places to handle exceptional cases.
+Classes from 'base' module should be used only for inheritance.
diff --git a/tempest/exceptions/__init__.py b/tempest/exceptions/__init__.py
new file mode 100644
index 0000000..c95f94f
--- /dev/null
+++ b/tempest/exceptions/__init__.py
@@ -0,0 +1,148 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.exceptions import base
+
+
+class InvalidConfiguration(base.TempestException):
+ message = "Invalid Configuration"
+
+
+class InvalidHttpSuccessCode(base.RestClientException):
+ message = "The success code is different than the expected one"
+
+
+class NotFound(base.RestClientException):
+ message = "Object not found"
+
+
+class Unauthorized(base.RestClientException):
+ message = 'Unauthorized'
+
+
+class InvalidServiceTag(base.RestClientException):
+ message = "Invalid service tag"
+
+
+class TimeoutException(base.TempestException):
+ message = "Request timed out"
+
+
+class BuildErrorException(base.TempestException):
+ message = "Server %(server_id)s failed to build and is in ERROR status"
+
+
+class ImageKilledException(base.TempestException):
+ message = "Image %(image_id)s 'killed' while waiting for '%(status)s'"
+
+
+class AddImageException(base.TempestException):
+ message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
+
+
+class EC2RegisterImageException(base.TempestException):
+ message = ("Image %(image_id)s failed to become 'available' "
+ "in the allotted time")
+
+
+class VolumeBuildErrorException(base.TempestException):
+ message = "Volume %(volume_id)s failed to build and is in ERROR status"
+
+
+class SnapshotBuildErrorException(base.TempestException):
+ message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
+
+
+class VolumeBackupException(base.TempestException):
+ message = "Volume backup %(backup_id)s failed and is in ERROR status"
+
+
+class StackBuildErrorException(base.TempestException):
+ message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
+ "due to '%(stack_status_reason)s'")
+
+
+class BadRequest(base.RestClientException):
+ message = "Bad request"
+
+
+class UnprocessableEntity(base.RestClientException):
+ message = "Unprocessable entity"
+
+
+class AuthenticationFailure(base.RestClientException):
+ message = ("Authentication with user %(user)s and password "
+ "%(password)s failed auth using tenant %(tenant)s.")
+
+
+class EndpointNotFound(base.TempestException):
+ message = "Endpoint not found"
+
+
+class RateLimitExceeded(base.TempestException):
+ message = "Rate limit exceeded"
+
+
+class OverLimit(base.TempestException):
+ message = "Quota exceeded"
+
+
+class ServerFault(base.TempestException):
+ message = "Got server fault"
+
+
+class ImageFault(base.TempestException):
+ message = "Got image fault"
+
+
+class IdentityError(base.TempestException):
+ message = "Got identity error"
+
+
+class Conflict(base.RestClientException):
+ message = "An object with that identifier already exists"
+
+
+class SSHTimeout(base.TempestException):
+ message = ("Connection to the %(host)s via SSH timed out.\n"
+ "User: %(user)s, Password: %(password)s")
+
+
+class SSHExecCommandFailed(base.TempestException):
+ """Raised when remotely executed command returns nonzero status."""
+ message = ("Command '%(command)s', exit status: %(exit_status)d, "
+ "Error:\n%(strerror)s")
+
+
+class ServerUnreachable(base.TempestException):
+ message = "The server is not reachable via the configured network"
+
+
+class TearDownException(base.TempestException):
+ message = "%(num)d cleanUp operation failed"
+
+
+class ResponseWithNonEmptyBody(base.RFCViolation):
+ message = ("RFC Violation! Response with %(status)d HTTP Status Code "
+ "MUST NOT have a body")
+
+
+class ResponseWithEntity(base.RFCViolation):
+ message = ("RFC Violation! Response with 205 HTTP Status Code "
+ "MUST NOT have an entity")
+
+
+class InvalidHTTPResponseBody(base.RestClientException):
+ message = "HTTP response body is invalid json or xml"
diff --git a/tempest/exceptions/base.py b/tempest/exceptions/base.py
new file mode 100644
index 0000000..b8e470e
--- /dev/null
+++ b/tempest/exceptions/base.py
@@ -0,0 +1,55 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+
+class TempestException(Exception):
+ """
+ Base Tempest Exception
+
+ To correctly use this class, inherit from it and define
+ a 'message' property. That message will get printf'd
+ with the keyword arguments provided to the constructor.
+ """
+ message = "An unknown exception occurred"
+
+ def __init__(self, *args, **kwargs):
+ super(TempestException, self).__init__()
+ try:
+ self._error_string = self.message % kwargs
+ except Exception:
+ # at least get the core message out if something happened
+ self._error_string = self.message
+ if len(args) > 0:
+ # If there is a non-kwarg parameter, assume it's the error
+ # message or reason description and tack it on to the end
+ # of the exception message
+ # Convert all arguments into their string representations...
+ args = ["%s" % arg for arg in args]
+ self._error_string = (self._error_string +
+ "\nDetails: %s" % '\n'.join(args))
+
+ def __str__(self):
+ return self._error_string
+
+
+class RestClientException(TempestException,
+ testtools.TestCase.failureException):
+ pass
+
+
+class RFCViolation(RestClientException):
+ message = "RFC Violation"
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 56fdcc8..f06a850 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -16,6 +16,7 @@
import logging
import os
+import six
import subprocess
import netaddr
@@ -225,8 +226,9 @@
# so case sensitive comparisons can really mess things
# up.
if new_status.lower() == error_status.lower():
- message = ("%s failed to get to expected status. "
- "In %s state.") % (thing, new_status)
+ message = ("%s failed to get to expected status (%s). "
+ "In %s state.") % (thing, expected_status,
+ new_status)
raise exceptions.BuildErrorException(message,
server_id=thing_id)
elif new_status == expected_status and expected_status is not None:
@@ -370,7 +372,7 @@
return keypair
def get_remote_client(self, server_or_ip, username=None, private_key=None):
- if isinstance(server_or_ip, basestring):
+ if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
network_name_for_ssh = CONF.compute.network_for_ssh
@@ -511,7 +513,7 @@
ports = self._list_ports(tenant_id=tenant_id)
return len(ports)
- def _create_subnet(self, network, namestart='subnet-smoke-'):
+ def _create_subnet(self, network, namestart='subnet-smoke-', **kwargs):
"""
Create a subnet for the given network within the cidr block
configured for tenant networks.
@@ -544,6 +546,7 @@
cidr=str_cidr,
),
)
+ body['subnet'].update(kwargs)
try:
result = self.network_client.create_subnet(body=body)
break
@@ -605,7 +608,7 @@
:param floating_ip: type DeletableFloatingIp
"""
floating_ip.update(port_id=None)
- self.assertEqual(None, floating_ip.port_id)
+ self.assertIsNone(floating_ip.port_id)
return floating_ip
def _ping_ip_address(self, ip_address, should_succeed=True):
@@ -701,6 +704,28 @@
private_key)
linux_client.validate_authentication()
+ def _check_remote_connectivity(self, source, dest, should_succeed=True):
+ """
+ check ping server via source ssh connection
+
+ :param source: RemoteClient: an ssh connection from which to ping
+ :param dest: and IP to ping against
+ :param should_succeed: boolean should ping succeed or not
+ :returns: boolean -- should_succeed == ping
+ :returns: ping is false if ping failed
+ """
+ def ping_remote():
+ try:
+ source.ping_host(dest)
+ except exceptions.SSHExecCommandFailed:
+ LOG.exception('Failed to ping host via ssh connection')
+ return not should_succeed
+ return should_succeed
+
+ return tempest.test.call_until_true(ping_remote,
+ CONF.compute.ping_timeout,
+ 1)
+
def _create_security_group_nova(self, client=None,
namestart='secgroup-smoke-',
tenant_id=None):
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 5bcdacd..ce2c66f 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -17,7 +17,6 @@
import urllib
from tempest.api.network import common as net_common
-from tempest.common import ssh
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -64,6 +63,8 @@
cls.servers_keypairs = {}
cls.members = []
cls.floating_ips = {}
+ cls.server_ip = None
+ cls.vip_ip = None
cls.port1 = 80
cls.port2 = 88
@@ -76,12 +77,10 @@
name = data_utils.rand_name("smoke_server-")
keypair = self.create_keypair(name='keypair-%s' % name)
security_groups = [self.security_groups[tenant_id].name]
- net = self.list_networks(tenant_id=self.tenant_id)[0]
- self.network = net_common.DeletableNetwork(client=self.network_client,
- **net['network'])
+ net = self._list_networks(tenant_id=self.tenant_id)[0]
create_kwargs = {
'nics': [
- {'net-id': self.network.id},
+ {'net-id': net['id']},
],
'key_name': keypair.name,
'security_groups': security_groups,
@@ -89,30 +88,36 @@
server = self.create_server(name=name,
create_kwargs=create_kwargs)
self.servers_keypairs[server] = keypair
+ if (config.network.public_network_id and not
+ config.network.tenant_networks_reachable):
+ public_network_id = config.network.public_network_id
+ floating_ip = self._create_floating_ip(
+ server, public_network_id)
+ self.floating_ips[floating_ip] = server
+ self.server_ip = floating_ip.floating_ip_address
+ else:
+ self.server_ip = server.networks[net['name']][0]
self.assertTrue(self.servers_keypairs)
+ return server
- def _start_servers(self):
+ def _start_servers(self, server):
"""
1. SSH to the instance
- 2. Start two servers listening on ports 80 and 88 respectively
+ 2. Start two http backends listening on ports 80 and 88 respectively
"""
- for server in self.servers_keypairs.keys():
- ssh_login = config.compute.image_ssh_user
- private_key = self.servers_keypairs[server].private_key
- network_name = self.network.name
- ip_address = server.networks[network_name][0]
- ssh_client = ssh.Client(ip_address, ssh_login,
- pkey=private_key,
- timeout=100)
- start_server = "while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\n" \
- "%(server)s' | sudo nc -l -p %(port)s ; done &"
- cmd = start_server % {'server': 'server1',
- 'port': self.port1}
- ssh_client.exec_command(cmd)
- cmd = start_server % {'server': 'server2',
- 'port': self.port2}
- ssh_client.exec_command(cmd)
+ private_key = self.servers_keypairs[server].private_key
+ ssh_client = self.get_remote_client(
+ server_or_ip=self.server_ip,
+ private_key=private_key).ssh_client
+ start_server = "while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\n" \
+ "%(server)s' | sudo nc -l -p %(port)s ; done &"
+ cmd = start_server % {'server': 'server1',
+ 'port': self.port1}
+ ssh_client.exec_command(cmd)
+ cmd = start_server % {'server': 'server2',
+ 'port': self.port2}
+ ssh_client.exec_command(cmd)
def _check_connection(self, check_ip):
def try_connect(ip):
@@ -135,14 +140,14 @@
# get tenant subnet and verify there's only one
subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
self.subnet = net_common.DeletableSubnet(client=self.network_client,
- **subnet['subnet'])
+ **subnet)
self.pool = super(TestLoadBalancerBasic, self)._create_pool(
'ROUND_ROBIN',
'HTTP',
self.subnet.id)
self.assertTrue(self.pool)
- def _create_members(self, network_name, server_ids):
+ def _create_members(self, server_ids):
"""
Create two members.
@@ -152,7 +157,7 @@
servers = self.compute_client.servers.list()
for server in servers:
if server.id in server_ids:
- ip = server.networks[network_name][0]
+ ip = self.server_ip
pool_id = self.pool.id
if len(set(server_ids)) == 1 or len(servers) == 1:
member1 = self._create_member(ip, self.port1, pool_id)
@@ -173,8 +178,7 @@
def _create_load_balancer(self):
self._create_pool()
- self._create_members(self.network.name,
- [self.servers_keypairs.keys()[0].id])
+ self._create_members([self.servers_keypairs.keys()[0].id])
subnet_id = self.subnet.id
pool_id = self.pool.id
self.vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
@@ -185,7 +189,13 @@
net_common.DeletableVip),
self.vip.id,
expected_status='ACTIVE')
- self._assign_floating_ip_to_vip(self.vip)
+ if (config.network.public_network_id and not
+ config.network.tenant_networks_reachable):
+ self._assign_floating_ip_to_vip(self.vip)
+ self.vip_ip = self.floating_ips[
+ self.vip.id][0]['floating_ip_address']
+ else:
+ self.vip_ip = self.vip.address
def _check_load_balancing(self):
"""
@@ -195,25 +205,22 @@
of the requests
"""
- vip = self.vip
- floating_ip_vip = self.floating_ips[vip.id][0]['floating_ip_address']
- self._check_connection(floating_ip_vip)
+ self._check_connection(self.vip_ip)
resp = []
for count in range(10):
resp.append(
urllib.urlopen(
- "http://{0}/".format(floating_ip_vip)).read())
+ "http://{0}/".format(self.vip_ip)).read())
self.assertEqual(set(["server1\n", "server2\n"]), set(resp))
self.assertEqual(5, resp.count("server1\n"))
self.assertEqual(5, resp.count("server2\n"))
- @test.skip_because(bug="1277381")
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_load_balancer_basic(self):
self._create_security_groups()
- self._create_server()
- self._start_servers()
+ server = self._create_server()
+ self._start_servers(server)
self._create_load_balancer()
self._check_load_balancing()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 998a474..489b271 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -15,6 +15,9 @@
# under the License.
import collections
+import re
+
+from tempest.api.network import common as net_common
from tempest.common import debug
from tempest.common.utils import data_utils
from tempest import config
@@ -36,36 +39,6 @@
boot VM's with Neutron-managed networking, and attempts to
verify network connectivity as follows:
- * For a freshly-booted VM with an IP address ("port") on a given network:
-
- - the Tempest host can ping the IP address. This implies, but
- does not guarantee (see the ssh check that follows), that the
- VM has been assigned the correct IP address and has
- connectivity to the Tempest host.
-
- - the Tempest host can perform key-based authentication to an
- ssh server hosted at the IP address. This check guarantees
- that the IP address is associated with the target VM.
-
- - detach the floating-ip from the VM and verify that it becomes
- unreachable
-
- - associate detached floating ip to a new VM and verify connectivity.
- VMs are created with unique keypair so connectivity also asserts that
- floating IP is associated with the new VM instead of the old one
-
- # TODO(mnewby) - Need to implement the following:
- - the Tempest host can ssh into the VM via the IP address and
- successfully execute the following:
-
- - ping an external IP address, implying external connectivity.
-
- - ping an external hostname, implying that dns is correctly
- configured.
-
- - ping an internal IP address, implying connectivity to another
- VM on the same network.
-
There are presumed to be two types of networks: tenant and
public. A tenant network may or may not be reachable from the
Tempest host. A public network is assumed to be reachable from
@@ -250,10 +223,150 @@
self.floating_ip_tuple = Floating_IP_tuple(
floating_ip, serv_dict['server'])
+ def _create_new_network(self):
+ self.new_net = self._create_network(self.tenant_id)
+ self.addCleanup(self.cleanup_wrapper, self.new_net)
+ self.new_subnet = self._create_subnet(
+ network=self.new_net,
+ gateway_ip=None)
+ self.addCleanup(self.cleanup_wrapper, self.new_subnet)
+
+ def _hotplug_server(self):
+ old_floating_ip, server = self.floating_ip_tuple
+ ip_address = old_floating_ip.floating_ip_address
+ private_key = self.servers[server].private_key
+ ssh_client = self.get_remote_client(ip_address,
+ private_key=private_key)
+ old_nic_list = self._get_server_nics(ssh_client)
+ # get a port from a list of one item
+ port_list = self._list_ports(device_id=server.id)
+ self.assertEqual(1, len(port_list))
+ old_port = port_list[0]
+ self.compute_client.servers.interface_attach(server=server,
+ net_id=self.new_net.id,
+ port_id=None,
+ fixed_ip=None)
+ # move server to the head of the cleanup list
+ self.addCleanup(self.cleanup_wrapper, server)
+
+ def check_ports():
+ port_list = [port for port in
+ self._list_ports(device_id=server.id)
+ if port != old_port]
+ return len(port_list) == 1
+
+ test.call_until_true(check_ports, 60, 1)
+ new_port_list = [p for p in
+ self._list_ports(device_id=server.id)
+ if p != old_port]
+ self.assertEqual(1, len(new_port_list))
+ new_port = new_port_list[0]
+ new_port = net_common.DeletablePort(client=self.network_client,
+ **new_port)
+ new_nic_list = self._get_server_nics(ssh_client)
+ diff_list = [n for n in new_nic_list if n not in old_nic_list]
+ self.assertEqual(1, len(diff_list))
+ num, new_nic = diff_list[0]
+ ssh_client.assign_static_ip(nic=new_nic,
+ addr=new_port.fixed_ips[0]['ip_address'])
+ ssh_client.turn_nic_on(nic=new_nic)
+
+ def _get_server_nics(self, ssh_client):
+ reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
+ ipatxt = ssh_client.get_ip_list()
+ return reg.findall(ipatxt)
+
+ def _check_network_internal_connectivity(self, network):
+ """
+ via ssh check VM internal connectivity:
+ - ping internal gateway and DHCP port, implying in-tenant connectivity
+ pinging both, because L3 and DHCP agents might be on different nodes
+ """
+ floating_ip, server = self.floating_ip_tuple
+ # get internal ports' ips:
+ # get all network ports in the new network
+ internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
+ self._list_ports(tenant_id=server.tenant_id,
+ network_id=network.id)
+ if p['device_owner'].startswith('network'))
+
+ self._check_server_connectivity(floating_ip, internal_ips)
+
+ def _check_network_external_connectivity(self):
+ """
+ ping public network default gateway to imply external connectivity
+
+ """
+ if not CONF.network.public_network_id:
+ msg = 'public network not defined.'
+ LOG.info(msg)
+ return
+
+ subnet = self.network_client.list_subnets(
+ network_id=CONF.network.public_network_id)['subnets']
+ self.assertEqual(1, len(subnet), "Found %d subnets" % len(subnet))
+
+ external_ips = [subnet[0]['gateway_ip']]
+ self._check_server_connectivity(self.floating_ip_tuple.floating_ip,
+ external_ips)
+
+ def _check_server_connectivity(self, floating_ip, address_list):
+ ip_address = floating_ip.floating_ip_address
+ private_key = self.servers[self.floating_ip_tuple.server].private_key
+ ssh_source = self._ssh_to_server(ip_address, private_key)
+
+ for remote_ip in address_list:
+ try:
+ self.assertTrue(self._check_remote_connectivity(ssh_source,
+ remote_ip),
+ "Timed out waiting for %s to become "
+ "reachable" % remote_ip)
+ except Exception:
+ LOG.exception("Unable to access {dest} via ssh to "
+ "floating-ip {src}".format(dest=remote_ip,
+ src=floating_ip))
+ debug.log_ip_ns()
+ raise
+
@test.attr(type='smoke')
@test.services('compute', 'network')
def test_network_basic_ops(self):
+ """
+ For a freshly-booted VM with an IP address ("port") on a given
+ network:
+
+ - the Tempest host can ping the IP address. This implies, but
+ does not guarantee (see the ssh check that follows), that the
+ VM has been assigned the correct IP address and has
+ connectivity to the Tempest host.
+
+ - the Tempest host can perform key-based authentication to an
+ ssh server hosted at the IP address. This check guarantees
+ that the IP address is associated with the target VM.
+
+ - the Tempest host can ssh into the VM via the IP address and
+ successfully execute the following:
+
+ - ping an external IP address, implying external connectivity.
+
+ - ping an external hostname, implying that dns is correctly
+ configured.
+
+ - ping an internal IP address, implying connectivity to another
+ VM on the same network.
+
+ - detach the floating-ip from the VM and verify that it becomes
+ unreachable
+
+ - associate detached floating ip to a new VM and verify connectivity.
+ VMs are created with unique keypair so connectivity also asserts that
+ floating IP is associated with the new VM instead of the old one
+
+
+ """
self._check_public_network_connectivity(should_connect=True)
+ self._check_network_internal_connectivity(network=self.network)
+ self._check_network_external_connectivity()
self._disassociate_floating_ips()
self._check_public_network_connectivity(should_connect=False,
msg="after disassociate "
@@ -262,3 +375,20 @@
self._check_public_network_connectivity(should_connect=True,
msg="after re-associate "
"floating ip")
+
+ @test.attr(type='smoke')
+ @test.services('compute', 'network')
+ def test_hotplug_nic(self):
+ """
+ 1. create a new network, with no gateway (to prevent overwriting VM's
+ gateway)
+ 2. connect VM to new network
+ 3. set static ip and bring new nic up
+ 4. check VM can ping new network dhcp port
+
+ """
+
+ self._check_public_network_connectivity(should_connect=True)
+ self._create_new_network()
+ self._hotplug_server()
+ self._check_network_internal_connectivity(network=self.new_net)
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index a26e0cf..d404dd1 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -17,7 +17,6 @@
from tempest.common import debug
from tempest.common.utils import data_utils
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
from tempest.scenario import manager
from tempest import test
@@ -332,28 +331,6 @@
private_key=private_key)
return access_point_ssh
- def _test_remote_connectivity(self, source, dest, should_succeed=True):
- """
- check ping server via source ssh connection
-
- :param source: RemoteClient: an ssh connection from which to ping
- :param dest: and IP to ping against
- :param should_succeed: boolean should ping succeed or not
- :returns: boolean -- should_succeed == ping
- :returns: ping is false if ping failed
- """
- def ping_remote():
- try:
- source.ping_host(dest)
- except exceptions.SSHExecCommandFailed as ex:
- LOG.debug(ex)
- return not should_succeed
- return should_succeed
-
- return test.call_until_true(ping_remote,
- CONF.compute.ping_timeout,
- 1)
-
def _check_connectivity(self, access_point, ip, should_succeed=True):
if should_succeed:
msg = "Timed out waiting for %s to become reachable" % ip
@@ -362,8 +339,8 @@
return True
msg = "%s is reachable" % ip
try:
- self.assertTrue(self._test_remote_connectivity(access_point, ip,
- should_succeed),
+ self.assertTrue(self._check_remote_connectivity(access_point, ip,
+ should_succeed),
msg)
except Exception:
debug.log_ip_ns()
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index e26f570..700a29b 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -15,14 +15,14 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class AggregatesClientJSON(RestClient):
+class AggregatesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AggregatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index ea4e95e..9278d5b 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class AvailabilityZoneClientJSON(RestClient):
+class AvailabilityZoneClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AvailabilityZoneClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index de0f1a8..c05e352 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class CertificatesClientJSON(RestClient):
+class CertificatesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(CertificatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index f7e2737..5ad8b98 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ExtensionsClientJSON(RestClient):
+class ExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ExtensionsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index af750a3..8b2c6c9 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class FixedIPsClientJSON(RestClient):
+class FixedIPsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FixedIPsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 289b09e..a8111af 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class FlavorsClientJSON(RestClient):
+class FlavorsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FlavorsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0385160..42487c3 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -16,14 +16,14 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class FloatingIPsClientJSON(RestClient):
+class FloatingIPsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FloatingIPsClientJSON, self).__init__(auth_provider)
self.service = CONF.compute.catalog_type
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index d826a78..fb45997 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -15,13 +15,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HostsClientJSON(RestClient):
+class HostsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HostsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 74844dc..c6b13b0 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HypervisorClientJSON(RestClient):
+class HypervisorClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HypervisorClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index b3d8c35..5a79a29 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.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -24,7 +24,7 @@
CONF = config.CONF
-class ImagesClientJSON(RestClient):
+class ImagesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ImagesClientJSON, self).__init__(auth_provider)
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 27930f2..1f6e988 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class InstanceUsagesAuditLogClientJSON(RestClient):
+class InstanceUsagesAuditLogClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(InstanceUsagesAuditLogClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index f4c4c64..9928b94 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -16,14 +16,14 @@
import json
import time
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class InterfacesClientJSON(RestClient):
+class InterfacesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(InterfacesClientJSON, self).__init__(auth_provider)
@@ -80,3 +80,25 @@
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = json.dumps({
+ 'addFixedIp': {
+ 'networkId': network_id
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = json.dumps({
+ 'removeFixedIp': {
+ 'address': ip_address
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 356c2e6..28f3c31 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class KeyPairsClientJSON(RestClient):
+class KeyPairsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(KeyPairsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index 765ba79..1493718 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class LimitsClientJSON(RestClient):
+class LimitsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(LimitsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7607cc0..459ab6d 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class QuotasClientJSON(RestClient):
+class QuotasClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(QuotasClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 2cd2d2e..899d4ef 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -16,14 +16,14 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class SecurityGroupsClientJSON(RestClient):
+class SecurityGroupsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(SecurityGroupsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 025c4e5..623bf42 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -18,7 +18,7 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -26,7 +26,7 @@
CONF = config.CONF
-class ServersClientJSON(RestClient):
+class ServersClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServersClientJSON, self).__init__(auth_provider)
@@ -428,3 +428,11 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def reset_network(self, server_id, **kwargs):
+ """Resets the Network of a server"""
+ return self.action(server_id, 'resetNetwork', None, **kwargs)
+
+ def inject_network_info(self, server_id, **kwargs):
+ """Inject the Network Info into server"""
+ return self.action(server_id, 'injectNetworkInfo', None, **kwargs)
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index 8380dc2..1ab25ec 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -17,13 +17,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ServicesClientJSON(RestClient):
+class ServicesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServicesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index b14fa9b..f3a67dd 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class TenantUsagesClientJSON(RestClient):
+class TenantUsagesClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(TenantUsagesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 4b9dc0b..5ef11ed 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -17,14 +17,14 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class VolumesExtensionsClientJSON(RestClient):
+class VolumesExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(VolumesExtensionsClientJSON, self).__init__(
diff --git a/tempest/services/compute/v3/json/aggregates_client.py b/tempest/services/compute/v3/json/aggregates_client.py
index 20ce87b..fddf5df 100644
--- a/tempest/services/compute/v3/json/aggregates_client.py
+++ b/tempest/services/compute/v3/json/aggregates_client.py
@@ -15,14 +15,14 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class AggregatesV3ClientJSON(RestClient):
+class AggregatesV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AggregatesV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/availability_zone_client.py b/tempest/services/compute/v3/json/availability_zone_client.py
index 4a6db55..bad2de9 100644
--- a/tempest/services/compute/v3/json/availability_zone_client.py
+++ b/tempest/services/compute/v3/json/availability_zone_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class AvailabilityZoneV3ClientJSON(RestClient):
+class AvailabilityZoneV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(AvailabilityZoneV3ClientJSON, self).__init__(
diff --git a/tempest/services/compute/v3/json/certificates_client.py b/tempest/services/compute/v3/json/certificates_client.py
index 620eedf..f8beeb9 100644
--- a/tempest/services/compute/v3/json/certificates_client.py
+++ b/tempest/services/compute/v3/json/certificates_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class CertificatesV3ClientJSON(RestClient):
+class CertificatesV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(CertificatesV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/extensions_client.py b/tempest/services/compute/v3/json/extensions_client.py
index 54f0aba..46f17a4 100644
--- a/tempest/services/compute/v3/json/extensions_client.py
+++ b/tempest/services/compute/v3/json/extensions_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ExtensionsV3ClientJSON(RestClient):
+class ExtensionsV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ExtensionsV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index f9df2b8..656bd84 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class FlavorsV3ClientJSON(RestClient):
+class FlavorsV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(FlavorsV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/hosts_client.py b/tempest/services/compute/v3/json/hosts_client.py
index 76af626..e27c7c6 100644
--- a/tempest/services/compute/v3/json/hosts_client.py
+++ b/tempest/services/compute/v3/json/hosts_client.py
@@ -15,13 +15,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HostsV3ClientJSON(RestClient):
+class HostsV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HostsV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/hypervisor_client.py b/tempest/services/compute/v3/json/hypervisor_client.py
index e07a1fb..30e391f 100644
--- a/tempest/services/compute/v3/json/hypervisor_client.py
+++ b/tempest/services/compute/v3/json/hypervisor_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class HypervisorV3ClientJSON(RestClient):
+class HypervisorV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(HypervisorV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
index c167520..b45426c 100644
--- a/tempest/services/compute/v3/json/interfaces_client.py
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -16,14 +16,14 @@
import json
import time
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class InterfacesV3ClientJSON(RestClient):
+class InterfacesV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(InterfacesV3ClientJSON, self).__init__(auth_provider)
@@ -81,3 +81,25 @@
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = json.dumps({
+ 'add_fixed_ip': {
+ 'network_id': network_id
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = json.dumps({
+ 'remove_fixed_ip': {
+ 'address': ip_address
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ return resp, body
diff --git a/tempest/services/compute/v3/json/keypairs_client.py b/tempest/services/compute/v3/json/keypairs_client.py
index 821b86f..9ca4885 100644
--- a/tempest/services/compute/v3/json/keypairs_client.py
+++ b/tempest/services/compute/v3/json/keypairs_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class KeyPairsV3ClientJSON(RestClient):
+class KeyPairsV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(KeyPairsV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index aa8bfaf..32e31a3 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class QuotasV3ClientJSON(RestClient):
+class QuotasV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(QuotasV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 840e914..256a730 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -19,7 +19,7 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.common import waiters
from tempest import config
from tempest import exceptions
@@ -27,7 +27,7 @@
CONF = config.CONF
-class ServersV3ClientJSON(RestClient):
+class ServersV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServersV3ClientJSON, self).__init__(auth_provider)
@@ -423,3 +423,23 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def get_vnc_console(self, server_id, type):
+ """Get URL of VNC console."""
+ post_body = json.dumps({
+ "get_vnc_console": {
+ "type": type
+ }
+ })
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ post_body)
+ body = json.loads(body)
+ return resp, body['console']
+
+ def reset_network(self, server_id, **kwargs):
+ """Resets the Network of a server"""
+ return self.action(server_id, 'reset_network', None, **kwargs)
+
+ def inject_network_info(self, server_id, **kwargs):
+ """Inject the Network Info into server"""
+ return self.action(server_id, 'inject_network_info', None, **kwargs)
diff --git a/tempest/services/compute/v3/json/services_client.py b/tempest/services/compute/v3/json/services_client.py
index e20dfde..b4e65a0 100644
--- a/tempest/services/compute/v3/json/services_client.py
+++ b/tempest/services/compute/v3/json/services_client.py
@@ -17,13 +17,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ServicesV3ClientJSON(RestClient):
+class ServicesV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServicesV3ClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/xml/common.py b/tempest/services/compute/xml/common.py
index 4def19f..b29b932 100644
--- a/tempest/services/compute/xml/common.py
+++ b/tempest/services/compute/xml/common.py
@@ -18,6 +18,11 @@
XMLNS_11 = "http://docs.openstack.org/compute/api/v1.1"
XMLNS_V3 = "http://docs.openstack.org/compute/api/v1.1"
+NEUTRON_NAMESPACES = {
+ 'router': "http://docs.openstack.org/ext/neutron/router/api/v1.0",
+ 'provider': 'http://docs.openstack.org/ext/provider/api/v1.0',
+}
+
# NOTE(danms): This is just a silly implementation to help make generating
# XML faster for prototyping. Could be replaced with proper etree gorp
@@ -137,6 +142,9 @@
tag = child.tag
if tag.startswith("{"):
ns, tag = tag.split("}", 1)
+ for key, uri in NEUTRON_NAMESPACES.iteritems():
+ if uri == ns[1:]:
+ tag = key + ":" + tag
if plurals is not None and tag in plurals:
json[tag] = parse_array(child, plurals)
else:
diff --git a/tempest/services/compute/xml/interfaces_client.py b/tempest/services/compute/xml/interfaces_client.py
index 5df6187..8d4bfcc 100644
--- a/tempest/services/compute/xml/interfaces_client.py
+++ b/tempest/services/compute/xml/interfaces_client.py
@@ -24,6 +24,7 @@
from tempest.services.compute.xml.common import Element
from tempest.services.compute.xml.common import Text
from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
CONF = config.CONF
@@ -104,3 +105,21 @@
(port_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
return resp, body
+
+ def add_fixed_ip(self, server_id, network_id):
+ """Add a fixed IP to input server instance."""
+ post_body = Element("addFixedIp",
+ xmlns=XMLNS_11,
+ networkId=network_id)
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ str(Document(post_body)))
+ return resp, body
+
+ def remove_fixed_ip(self, server_id, ip_address):
+ """Remove input fixed IP from input server instance."""
+ post_body = Element("removeFixedIp",
+ xmlns=XMLNS_11,
+ address=ip_address)
+ resp, body = self.post('servers/%s/action' % str(server_id),
+ str(Document(post_body)))
+ return resp, body
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index eb287c2..b8b759f 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -44,9 +44,6 @@
return quota
- def _parse_array(self, node):
- return [self._format_quota(xml_to_json(x)) for x in node]
-
def get_quota_set(self, tenant_id):
"""List the quota set for a tenant."""
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index da01b83..cd2cb06 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -633,3 +633,11 @@
def restore_soft_deleted_server(self, server_id, **kwargs):
"""Restore a soft-deleted server."""
return self.action(server_id, 'restore', None, **kwargs)
+
+ def reset_network(self, server_id, **kwargs):
+ """Resets the Network of a server"""
+ return self.action(server_id, 'resetNetwork', None, **kwargs)
+
+ def inject_network_info(self, server_id, **kwargs):
+ """Inject the Network Info into server"""
+ return self.action(server_id, 'injectNetworkInfo', None, **kwargs)
diff --git a/tempest/services/database/__init__.py b/tempest/services/database/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/database/__init__.py
diff --git a/tempest/services/database/json/__init__.py b/tempest/services/database/json/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/database/json/__init__.py
diff --git a/tempest/services/database/json/flavors_client.py b/tempest/services/database/json/flavors_client.py
new file mode 100644
index 0000000..1a8a4c1
--- /dev/null
+++ b/tempest/services/database/json/flavors_client.py
@@ -0,0 +1,39 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.common import rest_client
+from tempest import config
+import urllib
+
+CONF = config.CONF
+
+
+class DatabaseFlavorsClientJSON(rest_client.RestClient):
+
+ def __init__(self, auth_provider):
+ super(DatabaseFlavorsClientJSON, self).__init__(auth_provider)
+ self.service = CONF.database.catalog_type
+
+ def list_db_flavors(self, params=None):
+ url = 'flavors'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+
+ resp, body = self.get(url)
+ return resp, self._parse_resp(body)
+
+ def get_db_flavor_details(self, db_flavor_id):
+ resp, body = self.get("flavors/%s" % str(db_flavor_id))
+ return resp, self._parse_resp(body)
diff --git a/tempest/services/identity/v3/json/credentials_client.py b/tempest/services/identity/v3/json/credentials_client.py
index 5d6632a..f795c7b 100644
--- a/tempest/services/identity/v3/json/credentials_client.py
+++ b/tempest/services/identity/v3/json/credentials_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class CredentialsClientJSON(RestClient):
+class CredentialsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(CredentialsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index 652c345..c3c1e15 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class EndPointClientJSON(RestClient):
+class EndPointClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(EndPointClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index b044e4d..65f3355 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -15,14 +15,14 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class IdentityV3ClientJSON(RestClient):
+class IdentityV3ClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(IdentityV3ClientJSON, self).__init__(auth_provider)
@@ -439,7 +439,7 @@
return resp, body
-class V3TokenClientJSON(RestClient):
+class V3TokenClientJSON(rest_client.RestClient):
def __init__(self):
super(V3TokenClientJSON, self).__init__(None)
diff --git a/tempest/services/identity/v3/json/policy_client.py b/tempest/services/identity/v3/json/policy_client.py
index 5a3f891..3c90fa1 100644
--- a/tempest/services/identity/v3/json/policy_client.py
+++ b/tempest/services/identity/v3/json/policy_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class PolicyClientJSON(RestClient):
+class PolicyClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(PolicyClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/json/service_client.py b/tempest/services/identity/v3/json/service_client.py
index c1faebb..b66fb4a 100644
--- a/tempest/services/identity/v3/json/service_client.py
+++ b/tempest/services/identity/v3/json/service_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ServiceClientJSON(RestClient):
+class ServiceClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ServiceClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/identity/v3/xml/credentials_client.py b/tempest/services/identity/v3/xml/credentials_client.py
index 22ed44d..70f85a1 100644
--- a/tempest/services/identity/v3/xml/credentials_client.py
+++ b/tempest/services/identity/v3/xml/credentials_client.py
@@ -19,10 +19,7 @@
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -39,7 +36,7 @@
self.api_version = "v3"
def _parse_body(self, body):
- data = xml_to_json(body)
+ data = common.xml_to_json(body)
return data
def _parse_creds(self, node):
@@ -47,7 +44,7 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "credential":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def create_credential(self, access_key, secret_key, user_id, project_id):
@@ -55,14 +52,14 @@
cred_type = 'ec2'
access = ""access": "%s"" % access_key
secret = ""secret": "%s"" % secret_key
- blob = Element('blob',
- xmlns=XMLNS)
- blob.append(Text("{%s , %s}"
- % (access, secret)))
- credential = Element('credential', project_id=project_id,
- type=cred_type, user_id=user_id)
+ blob = common.Element('blob',
+ xmlns=XMLNS)
+ blob.append(common.Text("{%s , %s}"
+ % (access, secret)))
+ credential = common.Element('credential', project_id=project_id,
+ type=cred_type, user_id=user_id)
credential.append(blob)
- resp, body = self.post('credentials', str(Document(credential)))
+ resp, body = self.post('credentials', str(common.Document(credential)))
body = self._parse_body(etree.fromstring(body))
body['blob'] = json.loads(body['blob'])
return resp, body
@@ -77,15 +74,15 @@
user_id = kwargs.get('user_id', body['user_id'])
access = ""access": "%s"" % access_key
secret = ""secret": "%s"" % secret_key
- blob = Element('blob',
- xmlns=XMLNS)
- blob.append(Text("{%s , %s}"
- % (access, secret)))
- credential = Element('credential', project_id=project_id,
- type=cred_type, user_id=user_id)
+ blob = common.Element('blob',
+ xmlns=XMLNS)
+ blob.append(common.Text("{%s , %s}"
+ % (access, secret)))
+ credential = common.Element('credential', project_id=project_id,
+ type=cred_type, user_id=user_id)
credential.append(blob)
resp, body = self.patch('credentials/%s' % credential_id,
- str(Document(credential)))
+ str(common.Document(credential)))
body = self._parse_body(etree.fromstring(body))
body['blob'] = json.loads(body['blob'])
return resp, body
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index a32eede..cc9aa65 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -18,9 +18,7 @@
from tempest.common import http
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -41,11 +39,11 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "endpoint":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_body(self, body):
- json = xml_to_json(body)
+ json = common.xml_to_json(body)
return json
def request(self, method, url, headers=None, body=None, wait=None):
@@ -67,21 +65,24 @@
"""Create endpoint."""
region = kwargs.get('region', None)
enabled = kwargs.get('enabled', None)
- create_endpoint = Element("endpoint",
- xmlns=XMLNS,
- service_id=service_id,
- interface=interface,
- url=url, region=region,
- enabled=enabled)
- resp, body = self.post('endpoints', str(Document(create_endpoint)))
+ if enabled is not None:
+ enabled = str(enabled).lower()
+ create_endpoint = common.Element("endpoint",
+ xmlns=XMLNS,
+ service_id=service_id,
+ interface=interface,
+ url=url, region=region,
+ enabled=enabled)
+ resp, body = self.post('endpoints',
+ str(common.Document(create_endpoint)))
body = self._parse_body(etree.fromstring(body))
return resp, body
def update_endpoint(self, endpoint_id, service_id=None, interface=None,
url=None, region=None, enabled=None):
"""Updates an endpoint with given parameters."""
- doc = Document()
- endpoint = Element("endpoint")
+ doc = common.Document()
+ endpoint = common.Element("endpoint")
doc.append(endpoint)
if service_id:
@@ -93,7 +94,7 @@
if region:
endpoint.add_attr("region", region)
if enabled is not None:
- endpoint.add_attr("enabled", enabled)
+ endpoint.add_attr("enabled", str(enabled).lower())
resp, body = self.patch('endpoints/%s' % str(endpoint_id), str(doc))
body = self._parse_body(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index e8e70d8..6ff6d56 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -20,10 +20,7 @@
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -44,7 +41,7 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "project":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_domains(self, node):
@@ -52,7 +49,7 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "domain":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_group_users(self, node):
@@ -60,7 +57,7 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "user":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_roles(self, node):
@@ -68,17 +65,17 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "role":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_array(self, node):
array = []
for child in node.getchildren():
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_body(self, body):
- _json = xml_to_json(body)
+ _json = common.xml_to_json(body)
return _json
def create_user(self, user_name, **kwargs):
@@ -89,16 +86,16 @@
project_id = kwargs.get('project_id', None)
description = kwargs.get('description', None)
domain_id = kwargs.get('domain_id', 'default')
- post_body = Element("user",
- xmlns=XMLNS,
- name=user_name,
- password=password,
- description=description,
- email=email,
- enabled=str(en).lower(),
- project_id=project_id,
- domain_id=domain_id)
- resp, body = self.post('users', str(Document(post_body)))
+ post_body = common.Element("user",
+ xmlns=XMLNS,
+ name=user_name,
+ password=password,
+ description=description,
+ email=email,
+ enabled=str(en).lower(),
+ project_id=project_id,
+ domain_id=domain_id)
+ resp, body = self.post('users', str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -110,16 +107,16 @@
project_id = kwargs.get('project_id', body['project_id'])
description = kwargs.get('description', body['description'])
domain_id = kwargs.get('domain_id', body['domain_id'])
- update_user = Element("user",
- xmlns=XMLNS,
- name=name,
- email=email,
- project_id=project_id,
- domain_id=domain_id,
- description=description,
- enabled=str(en).lower())
+ update_user = common.Element("user",
+ xmlns=XMLNS,
+ name=name,
+ email=email,
+ project_id=project_id,
+ domain_id=domain_id,
+ description=description,
+ enabled=str(en).lower())
resp, body = self.patch('users/%s' % user_id,
- str(Document(update_user)))
+ str(common.Document(update_user)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -151,14 +148,14 @@
description = kwargs.get('description', None)
en = kwargs.get('enabled', 'true')
domain_id = kwargs.get('domain_id', 'default')
- post_body = Element("project",
- xmlns=XMLNS,
- description=description,
- domain_id=domain_id,
- enabled=str(en).lower(),
- name=name)
+ post_body = common.Element("project",
+ xmlns=XMLNS,
+ description=description,
+ domain_id=domain_id,
+ enabled=str(en).lower(),
+ name=name)
resp, body = self.post('projects',
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -175,14 +172,14 @@
desc = kwargs.get('description', body['description'])
en = kwargs.get('enabled', body['enabled'])
domain_id = kwargs.get('domain_id', body['domain_id'])
- post_body = Element("project",
- xmlns=XMLNS,
- name=name,
- description=desc,
- enabled=str(en).lower(),
- domain_id=domain_id)
+ post_body = common.Element("project",
+ xmlns=XMLNS,
+ name=name,
+ description=desc,
+ enabled=str(en).lower(),
+ domain_id=domain_id)
resp, body = self.patch('projects/%s' % project_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -199,10 +196,10 @@
def create_role(self, name):
"""Create a Role."""
- post_body = Element("role",
- xmlns=XMLNS,
- name=name)
- resp, body = self.post('roles', str(Document(post_body)))
+ post_body = common.Element("role",
+ xmlns=XMLNS,
+ name=name)
+ resp, body = self.post('roles', str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -214,11 +211,11 @@
def update_role(self, name, role_id):
"""Updates a Role."""
- post_body = Element("role",
- xmlns=XMLNS,
- name=name)
+ post_body = common.Element("role",
+ xmlns=XMLNS,
+ name=name)
resp, body = self.patch('roles/%s' % str(role_id),
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -237,12 +234,12 @@
"""Creates a domain."""
description = kwargs.get('description', None)
en = kwargs.get('enabled', True)
- post_body = Element("domain",
- xmlns=XMLNS,
- name=name,
- description=description,
- enabled=str(en).lower())
- resp, body = self.post('domains', str(Document(post_body)))
+ post_body = common.Element("domain",
+ xmlns=XMLNS,
+ name=name,
+ description=description,
+ enabled=str(en).lower())
+ resp, body = self.post('domains', str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -263,13 +260,13 @@
description = kwargs.get('description', body['description'])
en = kwargs.get('enabled', body['enabled'])
name = kwargs.get('name', body['name'])
- post_body = Element("domain",
- xmlns=XMLNS,
- name=name,
- description=description,
- enabled=str(en).lower())
+ post_body = common.Element("domain",
+ xmlns=XMLNS,
+ name=name,
+ description=description,
+ enabled=str(en).lower())
resp, body = self.patch('domains/%s' % domain_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -299,13 +296,13 @@
description = kwargs.get('description', None)
domain_id = kwargs.get('domain_id', 'default')
project_id = kwargs.get('project_id', None)
- post_body = Element("group",
- xmlns=XMLNS,
- name=name,
- description=description,
- domain_id=domain_id,
- project_id=project_id)
- resp, body = self.post('groups', str(Document(post_body)))
+ post_body = common.Element("group",
+ xmlns=XMLNS,
+ name=name,
+ description=description,
+ domain_id=domain_id,
+ project_id=project_id)
+ resp, body = self.post('groups', str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -320,12 +317,12 @@
resp, body = self.get_group(group_id)
name = kwargs.get('name', body['name'])
description = kwargs.get('description', body['description'])
- post_body = Element("group",
- xmlns=XMLNS,
- name=name,
- description=description)
+ post_body = common.Element("group",
+ xmlns=XMLNS,
+ name=name,
+ description=description)
resp, body = self.patch('groups/%s' % group_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -456,35 +453,35 @@
Validation is left to the server side.
"""
if user_type == 'id':
- _user = Element('user', id=user, password=password)
+ _user = common.Element('user', id=user, password=password)
else:
- _user = Element('user', name=user, password=password)
+ _user = common.Element('user', name=user, password=password)
if domain is not None:
- _domain = Element('domain', name=domain)
+ _domain = common.Element('domain', name=domain)
_user.append(_domain)
- password = Element('password')
+ password = common.Element('password')
password.append(_user)
- method = Element('method')
- method.append(Text('password'))
- methods = Element('methods')
+ method = common.Element('method')
+ method.append(common.Text('password'))
+ methods = common.Element('methods')
methods.append(method)
- identity = Element('identity')
+ identity = common.Element('identity')
identity.append(methods)
identity.append(password)
- auth = Element('auth')
+ auth = common.Element('auth')
auth.append(identity)
if tenant is not None:
- project = Element('project', name=tenant)
+ project = common.Element('project', name=tenant)
project.append(_domain)
- scope = Element('scope')
+ scope = common.Element('scope')
scope.append(project)
auth.append(scope)
- resp, body = self.post(self.auth_url, body=str(Document(auth)))
+ resp, body = self.post(self.auth_url, body=str(common.Document(auth)))
return resp, body
def request(self, method, url, headers=None, body=None):
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
index c12018a..bf4cce7 100644
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ b/tempest/services/identity/v3/xml/policy_client.py
@@ -18,9 +18,7 @@
from tempest.common import http
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -41,11 +39,11 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[1] == "policy":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def _parse_body(self, body):
- json = xml_to_json(body)
+ json = common.xml_to_json(body)
return json
def request(self, method, url, headers=None, body=None, wait=None):
@@ -59,8 +57,9 @@
def create_policy(self, blob, type):
"""Creates a Policy."""
- create_policy = Element("policy", xmlns=XMLNS, blob=blob, type=type)
- resp, body = self.post('policies', str(Document(create_policy)))
+ create_policy = common.Element("policy", xmlns=XMLNS,
+ blob=blob, type=type)
+ resp, body = self.post('policies', str(common.Document(create_policy)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -81,9 +80,9 @@
"""Updates a policy."""
resp, body = self.get_policy(policy_id)
type = kwargs.get('type')
- update_policy = Element("policy", xmlns=XMLNS, type=type)
+ update_policy = common.Element("policy", xmlns=XMLNS, type=type)
url = 'policies/%s' % policy_id
- resp, body = self.patch(url, str(Document(update_policy)))
+ resp, body = self.patch(url, str(common.Document(update_policy)))
body = self._parse_body(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
index d5476c4..966d7f7 100644
--- a/tempest/services/identity/v3/xml/service_client.py
+++ b/tempest/services/identity/v3/xml/service_client.py
@@ -17,9 +17,7 @@
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -35,14 +33,8 @@
self.endpoint_url = 'adminURL'
self.api_version = "v3"
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(xml_to_json(child))
- return array
-
def _parse_body(self, body):
- data = xml_to_json(body)
+ data = common.xml_to_json(body)
return data
def update_service(self, service_id, **kwargs):
@@ -51,14 +43,14 @@
name = kwargs.get('name', body['name'])
description = kwargs.get('description', body['description'])
type = kwargs.get('type', body['type'])
- update_service = Element("service",
- xmlns=XMLNS,
- id=service_id,
- name=name,
- description=description,
- type=type)
+ update_service = common.Element("service",
+ xmlns=XMLNS,
+ id=service_id,
+ name=name,
+ description=description,
+ type=type)
resp, body = self.patch('services/%s' % service_id,
- str(Document(update_service)))
+ str(common.Document(update_service)))
body = self._parse_body(etree.fromstring(body))
return resp, body
@@ -70,12 +62,12 @@
return resp, body
def create_service(self, serv_type, name=None, description=None):
- post_body = Element("service",
- xmlns=XMLNS,
- name=name,
- description=description,
- type=serv_type)
- resp, body = self.post("services", str(Document(post_body)))
+ post_body = common.Element("service",
+ xmlns=XMLNS,
+ name=name,
+ description=description,
+ type=serv_type)
+ resp, body = self.post("services", str(common.Document(post_body)))
body = self._parse_body(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index 932fa14..e22cd9c 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -21,7 +21,7 @@
import urllib
from tempest.common import glance_http
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -31,7 +31,7 @@
LOG = logging.getLogger(__name__)
-class ImageClientJSON(RestClient):
+class ImageClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ImageClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 58819d0..b3014fc 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -39,23 +39,9 @@
filters=self.filters,
insecure=dscv)
- def get_images_schema(self):
- url = 'v2/schemas/images'
- resp, body = self.get(url)
- body = json.loads(body)
- return resp, body
-
- def get_image_schema(self):
- url = 'v2/schemas/image'
- resp, body = self.get(url)
- body = json.loads(body)
- return resp, body
-
def _validate_schema(self, body, type='image'):
- if type == 'image':
- resp, schema = self.get_image_schema()
- elif type == 'images':
- resp, schema = self.get_images_schema()
+ if type in ['image', 'images']:
+ resp, schema = self.get_schema(type)
else:
raise ValueError("%s is not a valid schema type" % type)
@@ -68,6 +54,15 @@
self._http = self._get_http()
return self._http
+ def update_image(self, image_id, patch):
+ data = json.dumps(patch)
+ self._validate_schema(data)
+
+ headers = {"Content-Type": "application/openstack-images-v2.0"
+ "-json-patch"}
+ resp, body = self.patch('v2/images/%s' % image_id, data, headers)
+ return resp, self._parse_resp(body)
+
def create_image(self, name, container_format, disk_format, **kwargs):
params = {
"name": name,
@@ -163,3 +158,21 @@
body = json.loads(body)
self.expected_success(200, resp)
return resp, body
+
+ def get_member(self, image_id, member_id):
+ url = 'v2/images/%s/members/%s' % (image_id, member_id)
+ resp, body = self.get(url)
+ self.expected_success(200, resp)
+ return resp, json.loads(body)
+
+ def remove_member(self, image_id, member_id):
+ url = 'v2/images/%s/members/%s' % (image_id, member_id)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp)
+ return resp
+
+ def get_schema(self, schema):
+ url = 'v2/schemas/%s' % schema
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 366ccee..5786ae7 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -12,7 +12,7 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.services.network import network_client_base
@@ -32,7 +32,7 @@
"""
def get_rest_client(self, auth_provider):
- return RestClient(auth_provider)
+ return rest_client.RestClient(auth_provider)
def deserialize_single(self, body):
return json.loads(body)
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 97d514f..8152d71 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -30,12 +30,6 @@
rc.TYPE = self.TYPE
return rc
- def _parse_array(self, node):
- array = []
- for child in node.getchildren():
- array.append(common.xml_to_json(child))
- return array
-
def deserialize_list(self, body):
return common.parse_array(etree.fromstring(body), self.PLURALS)
@@ -49,9 +43,14 @@
post_body = common.Element(root)
post_body.add_attr('xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance')
+ elements = set()
for name, attr in body[root].items():
elt = self._get_element(name, attr)
post_body.append(elt)
+ if ":" in name:
+ elements.add(name.split(":")[0])
+ if elements:
+ self._add_namespaces(post_body, elements)
return str(common.Document(post_body))
def serialize_list(self, body, root_name=None, item_name=None):
@@ -88,6 +87,11 @@
else:
return common.Element(name, value)
+ def _add_namespaces(self, root, elements):
+ for element in elements:
+ root.add_attr('xmlns:%s' % element,
+ common.NEUTRON_NAMESPACES[element])
+
def create_member(self, address, protocol_port, pool_id):
uri = '%s/lb/members' % (self.uri_prefix)
post_body = common.Element("member")
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index efac5f5..7c3fa85 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -17,18 +17,18 @@
import urllib
from tempest.common import http
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
+from xml.etree import ElementTree as etree
CONF = config.CONF
-class AccountClient(RestClient):
+class AccountClient(rest_client.RestClient):
def __init__(self, auth_provider):
super(AccountClient, self).__init__(auth_provider)
self.service = CONF.object_storage.catalog_type
- self.format = 'json'
def create_account(self, data=None,
params=None,
@@ -87,7 +87,25 @@
headers = {}
for item in metadata:
- headers[metadata_prefix + item] = 'x'
+ headers[metadata_prefix + item] = metadata[item]
+ resp, body = self.post('', headers=headers, body=None)
+ return resp, body
+
+ def create_and_delete_account_metadata(
+ self,
+ create_metadata=None,
+ delete_metadata=None,
+ create_metadata_prefix='X-Account-Meta-',
+ delete_metadata_prefix='X-Remove-Account-Meta-'):
+ """
+ Creates and deletes an account metadata entry.
+ """
+ headers = {}
+ for key in create_metadata:
+ headers[create_metadata_prefix + key] = create_metadata[key]
+ for key in delete_metadata:
+ headers[delete_metadata_prefix + key] = delete_metadata[key]
+
resp, body = self.post('', headers=headers, body=None)
return resp, body
@@ -112,36 +130,35 @@
response.
DEFAULT: Python-List returned in response body
"""
+ url = '?%s' % urllib.urlencode(params) if params else ''
- if params:
- if 'format' not in params:
- params['format'] = self.format
- else:
- params = {'format': self.format}
-
- url = '?' + urllib.urlencode(params)
- resp, body = self.get(url)
-
+ resp, body = self.get(url, headers={})
if params and params.get('format') == 'json':
body = json.loads(body)
+ elif params and params.get('format') == 'xml':
+ body = etree.fromstring(body)
+ else:
+ body = body.strip().splitlines()
return resp, body
def list_extensions(self):
self.skip_path()
- resp, body = self.get('info')
- self.reset_path()
+ try:
+ resp, body = self.get('info')
+ finally:
+ self.reset_path()
body = json.loads(body)
return resp, body
-class AccountClientCustomizedHeader(RestClient):
+class AccountClientCustomizedHeader(rest_client.RestClient):
# TODO(andreaf) This class is now redundant, to be removed in next patch
def __init__(self, auth_provider):
super(AccountClientCustomizedHeader, self).__init__(
auth_provider)
- # Overwrites json-specific header encoding in RestClient
+ # Overwrites json-specific header encoding in rest_client.RestClient
self.service = CONF.object_storage.catalog_type
self.format = 'json'
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index f224407..546b557 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -16,18 +16,18 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from xml.etree import ElementTree as etree
CONF = config.CONF
-class ContainerClient(RestClient):
+class ContainerClient(rest_client.RestClient):
def __init__(self, auth_provider):
super(ContainerClient, self).__init__(auth_provider)
- # Overwrites json-specific header encoding in RestClient
+ # Overwrites json-specific header encoding in rest_client.RestClient
self.headers = {}
self.service = CONF.object_storage.catalog_type
self.format = 'json'
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 09e484e..77d29a5 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -16,14 +16,14 @@
import urllib
from tempest.common import http
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class ObjectClient(RestClient):
+class ObjectClient(rest_client.RestClient):
def __init__(self, auth_provider):
super(ObjectClient, self).__init__(auth_provider)
@@ -135,14 +135,14 @@
return resp, body
-class ObjectClientCustomizedHeader(RestClient):
+class ObjectClientCustomizedHeader(rest_client.RestClient):
# TODO(andreaf) This class is now redundant, to be removed in next patch
def __init__(self, auth_provider):
super(ObjectClientCustomizedHeader, self).__init__(
auth_provider)
- # Overwrites json-specific header encoding in RestClient
+ # Overwrites json-specific header encoding in rest_client.RestClient
self.service = CONF.object_storage.catalog_type
self.format = 'json'
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index e666475..996aceb 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest.openstack.common import jsonutils as json
import tempest.services.telemetry.telemetry_client_base as client
@@ -21,7 +21,7 @@
class TelemetryClientJSON(client.TelemetryClientBase):
def get_rest_client(self, auth_provider):
- return RestClient(auth_provider)
+ return rest_client.RestClient(auth_provider)
def deserialize(self, body):
return json.loads(body.replace("\n", ""))
diff --git a/tempest/services/telemetry/xml/telemetry_client.py b/tempest/services/telemetry/xml/telemetry_client.py
index 165f29a..673f98e 100644
--- a/tempest/services/telemetry/xml/telemetry_client.py
+++ b/tempest/services/telemetry/xml/telemetry_client.py
@@ -16,8 +16,7 @@
from lxml import etree
from tempest.common import rest_client
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
import tempest.services.telemetry.telemetry_client_base as client
@@ -32,11 +31,11 @@
def _parse_array(self, body):
array = []
for child in body.getchildren():
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def serialize(self, body):
- return str(Document(body))
+ return str(common.Document(body))
def deserialize(self, body):
return self._parse_array(etree.fromstring(body))
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index 6efb258..84e4705 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class VolumeHostsClientJSON(RestClient):
+class VolumeHostsClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
"""
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 0d50524..5554362 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -16,13 +16,13 @@
import json
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class VolumeTypesClientJSON(RestClient):
+class VolumeTypesClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Types API requests to a Cinder endpoint
"""
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
index baaf5a0..183d06b 100644
--- a/tempest/services/volume/json/backups_client.py
+++ b/tempest/services/volume/json/backups_client.py
@@ -69,6 +69,13 @@
body = json.loads(body)
return resp, body['backup']
+ def list_backups_with_detail(self):
+ """Information for all the tenant's backups."""
+ url = "backups/detail"
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return resp, body['backups']
+
def wait_for_backup_status(self, backup_id, status):
"""Waits for a Backup to reach a given status."""
resp, body = self.get_backup(backup_id)
diff --git a/tempest/services/volume/json/extensions_client.py b/tempest/services/volume/json/extensions_client.py
index 257b7c8..9e182ea 100644
--- a/tempest/services/volume/json/extensions_client.py
+++ b/tempest/services/volume/json/extensions_client.py
@@ -15,13 +15,13 @@
import json
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
CONF = config.CONF
-class ExtensionsClientJSON(RestClient):
+class ExtensionsClientJSON(rest_client.RestClient):
def __init__(self, auth_provider):
super(ExtensionsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index ba33c49..2dff63d 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -14,7 +14,7 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -24,7 +24,7 @@
LOG = logging.getLogger(__name__)
-class SnapshotsClientJSON(RestClient):
+class SnapshotsClientJSON(rest_client.RestClient):
"""Client class to send CRUD Volume API requests."""
def __init__(self, auth_provider):
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 2183c56..e4d2e8d 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -17,14 +17,14 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class VolumesClientJSON(RestClient):
+class VolumesClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume API requests to a Cinder endpoint
"""
diff --git a/tempest/services/volume/v2/json/volumes_client.py b/tempest/services/volume/v2/json/volumes_client.py
index bd98402..5bfa75f 100644
--- a/tempest/services/volume/v2/json/volumes_client.py
+++ b/tempest/services/volume/v2/json/volumes_client.py
@@ -17,14 +17,14 @@
import time
import urllib
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
from tempest import config
from tempest import exceptions
CONF = config.CONF
-class VolumesV2ClientJSON(RestClient):
+class VolumesV2ClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume V2 API requests to a Cinder endpoint
"""
diff --git a/tempest/services/volume/v2/xml/volumes_client.py b/tempest/services/volume/v2/xml/volumes_client.py
index bc57842..0b8f47c 100644
--- a/tempest/services/volume/v2/xml/volumes_client.py
+++ b/tempest/services/volume/v2/xml/volumes_client.py
@@ -21,11 +21,7 @@
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -56,7 +52,7 @@
meta.text) for meta in
child.getchildren())
else:
- vol[tag] = xml_to_json(child)
+ vol[tag] = common.xml_to_json(child)
return vol
def get_attachment_from_volume(self, volume):
@@ -134,15 +130,15 @@
image
"""
# NOTE(afazekas): it should use a volume namespace
- volume = Element("volume", xmlns=XMLNS_11, size=size)
+ volume = common.Element("volume", xmlns=common.XMLNS_11, size=size)
if 'metadata' in kwargs:
- _metadata = Element('metadata')
+ _metadata = common.Element('metadata')
volume.append(_metadata)
for key, value in kwargs['metadata'].items():
- meta = Element('meta')
+ meta = common.Element('meta')
meta.add_attr('key', key)
- meta.append(Text(value))
+ meta.append(common.Text(value))
_metadata.append(meta)
attr_to_add = kwargs.copy()
del attr_to_add['metadata']
@@ -152,17 +148,17 @@
for key, value in attr_to_add.items():
volume.add_attr(key, value)
- resp, body = self.post('volumes', str(Document(volume)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.post('volumes', str(common.Document(volume)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def update_volume(self, volume_id, **kwargs):
"""Updates the Specified Volume."""
- put_body = Element("volume", xmlns=XMLNS_11, **kwargs)
+ put_body = common.Element("volume", xmlns=common.XMLNS_11, **kwargs)
resp, body = self.put('volumes/%s' % volume_id,
- str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume(self, volume_id):
@@ -198,108 +194,107 @@
def attach_volume(self, volume_id, instance_uuid, mountpoint):
"""Attaches a volume to a given instance on a given mountpoint."""
- post_body = Element("os-attach",
- instance_uuid=instance_uuid,
- mountpoint=mountpoint
- )
+ post_body = common.Element("os-attach",
+ instance_uuid=instance_uuid,
+ mountpoint=mountpoint
+ )
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def detach_volume(self, volume_id):
"""Detaches a volume from an instance."""
- post_body = Element("os-detach")
+ post_body = common.Element("os-detach")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def upload_volume(self, volume_id, image_name, disk_format):
"""Uploads a volume in Glance."""
- post_body = Element("os-volume_upload_image",
- image_name=image_name,
- disk_format=disk_format)
+ post_body = common.Element("os-volume_upload_image",
+ image_name=image_name,
+ disk_format=disk_format)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ resp, body = self.post(url, str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def extend_volume(self, volume_id, extend_size):
"""Extend a volume."""
- post_body = Element("os-extend",
- new_size=extend_size)
+ post_body = common.Element("os-extend",
+ new_size=extend_size)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def reset_volume_status(self, volume_id, status):
"""Reset the Specified Volume's Status."""
- post_body = Element("os-reset_status",
- status=status
- )
+ post_body = common.Element("os-reset_status",
+ status=status
+ )
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def volume_begin_detaching(self, volume_id):
"""Volume Begin Detaching."""
- post_body = Element("os-begin_detaching")
+ post_body = common.Element("os-begin_detaching")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def volume_roll_detaching(self, volume_id):
"""Volume Roll Detaching."""
- post_body = Element("os-roll_detaching")
+ post_body = common.Element("os-roll_detaching")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def reserve_volume(self, volume_id):
"""Reserves a volume."""
- post_body = Element("os-reserve")
+ post_body = common.Element("os-reserve")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def unreserve_volume(self, volume_id):
"""Restore a reserved volume ."""
- post_body = Element("os-unreserve")
+ post_body = common.Element("os-unreserve")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def create_volume_transfer(self, vol_id, name=None):
"""Create a volume transfer."""
- post_body = Element("transfer",
- volume_id=vol_id)
+ post_body = common.Element("transfer", volume_id=vol_id)
if name:
post_body.add_attr('name', name)
resp, body = self.post('os-volume-transfer',
- str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def get_volume_transfer(self, transfer_id):
"""Returns the details of a volume transfer."""
url = "os-volume-transfer/%s" % str(transfer_id)
resp, body = self.get(url)
- volume = xml_to_json(etree.fromstring(body))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def list_volume_transfers(self, params=None):
@@ -321,7 +316,7 @@
tag = child.tag
if tag.startswith("{"):
tag = tag.split("}", 1)
- vol[tag] = xml_to_json(child)
+ vol[tag] = common.xml_to_json(child)
return vol
def delete_volume_transfer(self, transfer_id):
@@ -330,36 +325,36 @@
def accept_volume_transfer(self, transfer_id, transfer_auth_key):
"""Accept a volume transfer."""
- post_body = Element("accept", auth_key=transfer_auth_key)
+ post_body = common.Element("accept", auth_key=transfer_auth_key)
url = 'os-volume-transfer/%s/accept' % transfer_id
- resp, body = self.post(url, str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ resp, body = self.post(url, str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def update_volume_readonly(self, volume_id, readonly):
"""Update the Specified Volume readonly."""
- post_body = Element("os-update_readonly_flag",
- readonly=readonly)
+ post_body = common.Element("os-update_readonly_flag",
+ readonly=readonly)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def force_delete_volume(self, volume_id):
"""Force Delete Volume."""
- post_body = Element("os-force_delete")
+ post_body = common.Element("os-force_delete")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def _metadata_body(self, meta):
- post_body = Element('metadata')
+ post_body = common.Element('metadata')
for k, v in meta.items():
- data = Element('meta', key=k)
- data.append(Text(v))
+ data = common.Element('meta', key=k)
+ data.append(common.Text(v))
post_body.append(data)
return post_body
@@ -374,7 +369,7 @@
"""Create metadata for the volume."""
post_body = self._metadata_body(metadata)
resp, body = self.post('volumes/%s/metadata' % volume_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
@@ -389,18 +384,18 @@
"""Update metadata for the volume."""
put_body = self._metadata_body(metadata)
url = "volumes/%s/metadata" % str(volume_id)
- resp, body = self.put(url, str(Document(put_body)))
+ resp, body = self.put(url, str(common.Document(put_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
def update_volume_metadata_item(self, volume_id, id, meta_item):
"""Update metadata item for the volume."""
for k, v in meta_item.items():
- put_body = Element('meta', key=k)
- put_body.append(Text(v))
+ put_body = common.Element('meta', key=k)
+ put_body.append(common.Text(v))
url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
- resp, body = self.put(url, str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.put(url, str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume_metadata_item(self, volume_id, id):
diff --git a/tempest/services/volume/xml/admin/volume_hosts_client.py b/tempest/services/volume/xml/admin/volume_hosts_client.py
index fb84c83..e34b9f0 100644
--- a/tempest/services/volume/xml/admin/volume_hosts_client.py
+++ b/tempest/services/volume/xml/admin/volume_hosts_client.py
@@ -19,7 +19,7 @@
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -58,7 +58,7 @@
for child in node.getchildren():
tag_list = child.tag.split('}', 1)
if tag_list[0] == "host":
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def list_hosts(self, params=None):
diff --git a/tempest/services/volume/xml/admin/volume_types_client.py b/tempest/services/volume/xml/admin/volume_types_client.py
index 77bafec..1fa3e73 100644
--- a/tempest/services/volume/xml/admin/volume_types_client.py
+++ b/tempest/services/volume/xml/admin/volume_types_client.py
@@ -20,11 +20,7 @@
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -53,7 +49,7 @@
meta.text)
for meta in list(child))
else:
- vol_type[tag] = xml_to_json(child)
+ vol_type[tag] = common.xml_to_json(child)
return vol_type
def _parse_volume_type_extra_specs(self, body):
@@ -64,7 +60,7 @@
if tag.startswith("{"):
ns, tag = tag.split("}", 1)
else:
- extra_spec[tag] = xml_to_json(child)
+ extra_spec[tag] = common.xml_to_json(child)
return extra_spec
def list_volume_types(self, params=None):
@@ -95,22 +91,22 @@
Following optional keyword arguments are accepted:
extra_specs: A dictionary of values to be used as extra_specs.
"""
- vol_type = Element("volume_type", xmlns=XMLNS_11)
+ vol_type = common.Element("volume_type", xmlns=common.XMLNS_11)
if name:
vol_type.add_attr('name', name)
extra_specs = kwargs.get('extra_specs')
if extra_specs:
- _extra_specs = Element('extra_specs')
+ _extra_specs = common.Element('extra_specs')
vol_type.append(_extra_specs)
for key, value in extra_specs.items():
- spec = Element('extra_spec')
+ spec = common.Element('extra_spec')
spec.add_attr('key', key)
- spec.append(Text(value))
+ spec.append(common.Text(value))
_extra_specs.append(spec)
- resp, body = self.post('types', str(Document(vol_type)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.post('types', str(common.Document(vol_type)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume_type(self, type_id):
@@ -147,21 +143,21 @@
extra_specs: A dictionary of values to be used as extra_specs.
"""
url = "types/%s/extra_specs" % str(vol_type_id)
- extra_specs = Element("extra_specs", xmlns=XMLNS_11)
+ extra_specs = common.Element("extra_specs", xmlns=common.XMLNS_11)
if extra_spec:
if isinstance(extra_spec, list):
extra_specs.append(extra_spec)
else:
for key, value in extra_spec.items():
- spec = Element('extra_spec')
+ spec = common.Element('extra_spec')
spec.add_attr('key', key)
- spec.append(Text(value))
+ spec.append(common.Text(value))
extra_specs.append(spec)
else:
extra_specs = None
- resp, body = self.post(url, str(Document(extra_specs)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.post(url, str(common.Document(extra_specs)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume_type_extra_specs(self, vol_id, extra_spec_name):
@@ -180,17 +176,17 @@
"""
url = "types/%s/extra_specs/%s" % (str(vol_type_id),
str(extra_spec_name))
- extra_specs = Element("extra_specs", xmlns=XMLNS_11)
+ extra_specs = common.Element("extra_specs", xmlns=common.XMLNS_11)
if extra_spec is not None:
for key, value in extra_spec.items():
- spec = Element('extra_spec')
+ spec = common.Element('extra_spec')
spec.add_attr('key', key)
- spec.append(Text(value))
+ spec.append(common.Text(value))
extra_specs.append(spec)
- resp, body = self.put(url, str(Document(extra_specs)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.put(url, str(common.Document(extra_specs)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def is_resource_deleted(self, id):
diff --git a/tempest/services/volume/xml/extensions_client.py b/tempest/services/volume/xml/extensions_client.py
index 1ea974f..4861733 100644
--- a/tempest/services/volume/xml/extensions_client.py
+++ b/tempest/services/volume/xml/extensions_client.py
@@ -17,7 +17,7 @@
from tempest.common import rest_client
from tempest import config
-from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -32,7 +32,7 @@
def _parse_array(self, node):
array = []
for child in node:
- array.append(xml_to_json(child))
+ array.append(common.xml_to_json(child))
return array
def list_extensions(self):
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index 458001b..9ad86d2 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -19,11 +19,7 @@
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -52,7 +48,7 @@
body = etree.fromstring(body)
snapshots = []
for snap in body:
- snapshots.append(xml_to_json(snap))
+ snapshots.append(common.xml_to_json(snap))
return resp, snapshots
def list_snapshots_with_detail(self, params=None):
@@ -66,7 +62,7 @@
body = etree.fromstring(body)
snapshots = []
for snap in body:
- snapshots.append(xml_to_json(snap))
+ snapshots.append(common.xml_to_json(snap))
return resp, snapshots
def get_snapshot(self, snapshot_id):
@@ -74,7 +70,7 @@
url = "snapshots/%s" % str(snapshot_id)
resp, body = self.get(url)
body = etree.fromstring(body)
- return resp, xml_to_json(body)
+ return resp, common.xml_to_json(body)
def create_snapshot(self, volume_id, **kwargs):
"""Creates a new snapshot.
@@ -84,20 +80,22 @@
display_description: User friendly snapshot description.
"""
# NOTE(afazekas): it should use the volume namespace
- snapshot = Element("snapshot", xmlns=XMLNS_11, volume_id=volume_id)
+ snapshot = common.Element("snapshot", xmlns=common.XMLNS_11,
+ volume_id=volume_id)
for key, value in kwargs.items():
snapshot.add_attr(key, value)
- resp, body = self.post('snapshots', str(Document(snapshot)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.post('snapshots',
+ str(common.Document(snapshot)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def update_snapshot(self, snapshot_id, **kwargs):
"""Updates a snapshot."""
- put_body = Element("snapshot", xmlns=XMLNS_11, **kwargs)
+ put_body = common.Element("snapshot", xmlns=common.XMLNS_11, **kwargs)
resp, body = self.put('snapshots/%s' % snapshot_id,
- str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
# NOTE(afazekas): just for the wait function
@@ -150,32 +148,30 @@
def reset_snapshot_status(self, snapshot_id, status):
"""Reset the specified snapshot's status."""
- post_body = Element("os-reset_status",
- status=status
- )
+ post_body = common.Element("os-reset_status", status=status)
url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def update_snapshot_status(self, snapshot_id, status, progress):
"""Update the specified snapshot's status."""
- post_body = Element("os-update_snapshot_status",
- status=status,
- progress=progress
- )
+ post_body = common.Element("os-update_snapshot_status",
+ status=status,
+ progress=progress
+ )
url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def _metadata_body(self, meta):
- post_body = Element('metadata')
+ post_body = common.Element('metadata')
for k, v in meta.items():
- data = Element('meta', key=k)
- data.append(Text(v))
+ data = common.Element('meta', key=k)
+ data.append(common.Text(v))
post_body.append(data)
return post_body
@@ -190,7 +186,7 @@
"""Create metadata for the snapshot."""
post_body = self._metadata_body(metadata)
resp, body = self.post('snapshots/%s/metadata' % snapshot_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
@@ -205,18 +201,18 @@
"""Update metadata for the snapshot."""
put_body = self._metadata_body(metadata)
url = "snapshots/%s/metadata" % str(snapshot_id)
- resp, body = self.put(url, str(Document(put_body)))
+ resp, body = self.put(url, str(common.Document(put_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
def update_snapshot_metadata_item(self, snapshot_id, id, meta_item):
"""Update metadata item for the snapshot."""
for k, v in meta_item.items():
- put_body = Element('meta', key=k)
- put_body.append(Text(v))
+ put_body = common.Element('meta', key=k)
+ put_body.append(common.Text(v))
url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
- resp, body = self.put(url, str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.put(url, str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_snapshot_metadata_item(self, snapshot_id, id):
@@ -226,9 +222,9 @@
def force_delete_snapshot(self, snapshot_id):
"""Force Delete Snapshot."""
- post_body = Element("os-force_delete")
+ post_body = common.Element("os-force_delete")
url = 'snapshots/%s/action' % str(snapshot_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index aef1e3c..8e886ce 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -17,16 +17,12 @@
import urllib
from lxml import etree
-from xml.sax.saxutils import escape
+from xml.sax import saxutils
from tempest.common import rest_client
from tempest import config
from tempest import exceptions
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
-from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml import common
CONF = config.CONF
@@ -55,7 +51,7 @@
meta.text) for meta in
child.getchildren())
else:
- vol[tag] = xml_to_json(child)
+ vol[tag] = common.xml_to_json(child)
return vol
def get_attachment_from_volume(self, volume):
@@ -135,15 +131,15 @@
image
"""
# NOTE(afazekas): it should use a volume namespace
- volume = Element("volume", xmlns=XMLNS_11, size=size)
+ volume = common.Element("volume", xmlns=common.XMLNS_11, size=size)
if 'metadata' in kwargs:
- _metadata = Element('metadata')
+ _metadata = common.Element('metadata')
volume.append(_metadata)
for key, value in kwargs['metadata'].items():
- meta = Element('meta')
+ meta = common.Element('meta')
meta.add_attr('key', key)
- meta.append(Text(value))
+ meta.append(common.Text(value))
_metadata.append(meta)
attr_to_add = kwargs.copy()
del attr_to_add['metadata']
@@ -153,17 +149,17 @@
for key, value in attr_to_add.items():
volume.add_attr(key, value)
- resp, body = self.post('volumes', str(Document(volume)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.post('volumes', str(common.Document(volume)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def update_volume(self, volume_id, **kwargs):
"""Updates the Specified Volume."""
- put_body = Element("volume", xmlns=XMLNS_11, **kwargs)
+ put_body = common.Element("volume", xmlns=common.XMLNS_11, **kwargs)
resp, body = self.put('volumes/%s' % volume_id,
- str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume(self, volume_id):
@@ -199,108 +195,108 @@
def attach_volume(self, volume_id, instance_uuid, mountpoint):
"""Attaches a volume to a given instance on a given mountpoint."""
- post_body = Element("os-attach",
- instance_uuid=instance_uuid,
- mountpoint=mountpoint
- )
+ post_body = common.Element("os-attach",
+ instance_uuid=instance_uuid,
+ mountpoint=mountpoint
+ )
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def detach_volume(self, volume_id):
"""Detaches a volume from an instance."""
- post_body = Element("os-detach")
+ post_body = common.Element("os-detach")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def upload_volume(self, volume_id, image_name, disk_format):
"""Uploads a volume in Glance."""
- post_body = Element("os-volume_upload_image",
- image_name=image_name,
- disk_format=disk_format)
+ post_body = common.Element("os-volume_upload_image",
+ image_name=image_name,
+ disk_format=disk_format)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ resp, body = self.post(url, str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def extend_volume(self, volume_id, extend_size):
"""Extend a volume."""
- post_body = Element("os-extend",
- new_size=extend_size)
+ post_body = common.Element("os-extend",
+ new_size=extend_size)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def reset_volume_status(self, volume_id, status):
"""Reset the Specified Volume's Status."""
- post_body = Element("os-reset_status",
- status=status
- )
+ post_body = common.Element("os-reset_status",
+ status=status
+ )
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def volume_begin_detaching(self, volume_id):
"""Volume Begin Detaching."""
- post_body = Element("os-begin_detaching")
+ post_body = common.Element("os-begin_detaching")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def volume_roll_detaching(self, volume_id):
"""Volume Roll Detaching."""
- post_body = Element("os-roll_detaching")
+ post_body = common.Element("os-roll_detaching")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def reserve_volume(self, volume_id):
"""Reserves a volume."""
- post_body = Element("os-reserve")
+ post_body = common.Element("os-reserve")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def unreserve_volume(self, volume_id):
"""Restore a reserved volume ."""
- post_body = Element("os-unreserve")
+ post_body = common.Element("os-unreserve")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def create_volume_transfer(self, vol_id, display_name=None):
"""Create a volume transfer."""
- post_body = Element("transfer",
- volume_id=vol_id)
+ post_body = common.Element("transfer",
+ volume_id=vol_id)
if display_name:
post_body.add_attr('name', display_name)
resp, body = self.post('os-volume-transfer',
- str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def get_volume_transfer(self, transfer_id):
"""Returns the details of a volume transfer."""
url = "os-volume-transfer/%s" % str(transfer_id)
resp, body = self.get(url)
- volume = xml_to_json(etree.fromstring(body))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def list_volume_transfers(self, params=None):
@@ -322,7 +318,7 @@
tag = child.tag
if tag.startswith("{"):
tag = tag.split("}", 1)
- vol[tag] = xml_to_json(child)
+ vol[tag] = common.xml_to_json(child)
return vol
def delete_volume_transfer(self, transfer_id):
@@ -331,37 +327,37 @@
def accept_volume_transfer(self, transfer_id, transfer_auth_key):
"""Accept a volume transfer."""
- post_body = Element("accept", auth_key=transfer_auth_key)
+ post_body = common.Element("accept", auth_key=transfer_auth_key)
url = 'os-volume-transfer/%s/accept' % transfer_id
- resp, body = self.post(url, str(Document(post_body)))
- volume = xml_to_json(etree.fromstring(body))
+ resp, body = self.post(url, str(common.Document(post_body)))
+ volume = common.xml_to_json(etree.fromstring(body))
return resp, volume
def update_volume_readonly(self, volume_id, readonly):
"""Update the Specified Volume readonly."""
- post_body = Element("os-update_readonly_flag",
- readonly=readonly)
+ post_body = common.Element("os-update_readonly_flag",
+ readonly=readonly)
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def force_delete_volume(self, volume_id):
"""Force Delete Volume."""
- post_body = Element("os-force_delete")
+ post_body = common.Element("os-force_delete")
url = 'volumes/%s/action' % str(volume_id)
- resp, body = self.post(url, str(Document(post_body)))
+ resp, body = self.post(url, str(common.Document(post_body)))
if body:
- body = xml_to_json(etree.fromstring(body))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def _metadata_body(self, meta):
- post_body = Element('metadata')
+ post_body = common.Element('metadata')
for k, v in meta.items():
- data = Element('meta', key=k)
+ data = common.Element('meta', key=k)
# Escape value to allow for special XML chars
- data.append(Text(escape(v)))
+ data.append(common.Text(saxutils.escape(v)))
post_body.append(data)
return post_body
@@ -376,7 +372,7 @@
"""Create metadata for the volume."""
post_body = self._metadata_body(metadata)
resp, body = self.post('volumes/%s/metadata' % volume_id,
- str(Document(post_body)))
+ str(common.Document(post_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
@@ -391,18 +387,18 @@
"""Update metadata for the volume."""
put_body = self._metadata_body(metadata)
url = "volumes/%s/metadata" % str(volume_id)
- resp, body = self.put(url, str(Document(put_body)))
+ resp, body = self.put(url, str(common.Document(put_body)))
body = self._parse_key_value(etree.fromstring(body))
return resp, body
def update_volume_metadata_item(self, volume_id, id, meta_item):
"""Update metadata item for the volume."""
for k, v in meta_item.items():
- put_body = Element('meta', key=k)
- put_body.append(Text(v))
+ put_body = common.Element('meta', key=k)
+ put_body.append(common.Text(v))
url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
- resp, body = self.put(url, str(Document(put_body)))
- body = xml_to_json(etree.fromstring(body))
+ resp, body = self.put(url, str(common.Document(put_body)))
+ body = common.xml_to_json(etree.fromstring(body))
return resp, body
def delete_volume_metadata_item(self, volume_id, id):
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 3715636..9660081 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -17,6 +17,8 @@
import signal
import time
+from six import moves
+
from tempest import clients
from tempest.common import ssh
from tempest.common.utils import data_utils
@@ -128,7 +130,7 @@
manager = admin_manager
else:
manager = clients.Manager()
- for p_number in xrange(test.get('threads', default_thread_num)):
+ for p_number in moves.xrange(test.get('threads', default_thread_num)):
if test.get('use_isolated_tenants', False):
username = data_utils.rand_name("stress_user")
tenant_name = data_utils.rand_name("stress_tenant")
diff --git a/tempest/test.py b/tempest/test.py
index c6e3d6e..2125047 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -27,10 +27,11 @@
import testtools
from tempest import clients
-from tempest.common import generate_json
+import tempest.common.generator.valid_generator as valid
from tempest.common import isolated_creds
from tempest import config
from tempest import exceptions
+from tempest.openstack.common import importutils
from tempest.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@@ -400,7 +401,8 @@
"""
description = NegativeAutoTest.load_schema(description_file)
LOG.debug(description)
- generate_json.validate_negative_test_schema(description)
+ generator = importutils.import_class(CONF.negative.test_generator)()
+ generator.validate_schema(description)
schema = description.get("json-schema", None)
resources = description.get("resources", [])
scenario_list = []
@@ -416,7 +418,7 @@
"expected_result": expected_result
}))
if schema is not None:
- for invalid in generate_json.generate_invalid(schema):
+ for invalid in generator.generate(schema):
scenario_list.append((invalid[0],
{"schema": invalid[1],
"expected_result": invalid[2]}))
@@ -459,11 +461,12 @@
# Note(mkoderer): The resources list already contains an invalid
# entry (see get_resource).
# We just send a valid json-schema with it
- valid = None
+ valid_schema = None
schema = description.get("json-schema", None)
if schema:
- valid = generate_json.generate_valid(schema)
- new_url, body = self._http_arguments(valid, url, method)
+ valid_schema = \
+ valid.ValidTestGenerator().generate_valid(schema)
+ new_url, body = self._http_arguments(valid_schema, url, method)
elif hasattr(self, "schema"):
new_url, body = self._http_arguments(self.schema, url, method)
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 41b0558..e941606 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -43,6 +43,10 @@
swift = True
horizon = True
+ class fake_negative(object):
+ test_generator = 'tempest.common.' \
+ 'generator.negative_generator.NegativeTestGenerator'
+
compute_feature_enabled = fake_compute_feature_enabled()
volume_feature_enabled = fake_default_feature_enabled()
network_feature_enabled = fake_default_feature_enabled()
@@ -52,3 +56,5 @@
compute = fake_compute()
identity = fake_identity()
+
+ negative = fake_negative()
diff --git a/tempest/tests/fake_identity.py b/tempest/tests/fake_identity.py
index ea2bd44..058c9c2 100644
--- a/tempest/tests/fake_identity.py
+++ b/tempest/tests/fake_identity.py
@@ -25,16 +25,16 @@
COMPUTE_ENDPOINTS_V2 = {
"endpoints": [
{
- "adminURL": "http://fake_url/api/admin",
+ "adminURL": "http://fake_url/v2/first_endpoint/admin",
"region": "NoMatchRegion",
- "internalURL": "http://fake_url/api/internal",
- "publicURL": "http://fake_url/api/public"
+ "internalURL": "http://fake_url/v2/first_endpoint/internal",
+ "publicURL": "http://fake_url/v2/first_endpoint/public"
},
{
- "adminURL": "http://fake_url/api/admin",
+ "adminURL": "http://fake_url/v2/second_endpoint/admin",
"region": "FakeRegion",
- "internalURL": "http://fake_url/api/internal",
- "publicURL": "http://fake_url/api/public"
+ "internalURL": "http://fake_url/v2/second_endpoint/internal",
+ "publicURL": "http://fake_url/v2/second_endpoint/public"
},
],
"type": "compute",
@@ -79,17 +79,24 @@
COMPUTE_ENDPOINTS_V3 = {
"endpoints": [
{
- "id": "fake_service",
+ "id": "first_compute_fake_service",
"interface": "public",
"region": "NoMatchRegion",
- "url": "http://fake_url/v3"
+ "url": "http://fake_url/v3/first_endpoint/api"
},
{
- "id": "another_fake_service",
+ "id": "second_fake_service",
"interface": "public",
"region": "FakeRegion",
- "url": "http://fake_url/v3"
+ "url": "http://fake_url/v3/second_endpoint/api"
+ },
+ {
+ "id": "third_fake_service",
+ "interface": "admin",
+ "region": "MiddleEarthRegion",
+ "url": "http://fake_url/v3/third_endpoint/api"
}
+
],
"type": "compute",
"id": "fake_compute_endpoint"
diff --git a/tempest/tests/negative/test_generate_json.py b/tempest/tests/negative/test_generate_json.py
index a0aa088..e09fcdf 100644
--- a/tempest/tests/negative/test_generate_json.py
+++ b/tempest/tests/negative/test_generate_json.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common import generate_json as gen
+from tempest.common.generator import negative_generator
import tempest.test
-class TestGenerateJson(tempest.test.BaseTestCase):
+class TestNegativeGenerator(tempest.test.BaseTestCase):
fake_input_str = {"type": "string",
"minLength": 2,
@@ -35,19 +35,23 @@
}
}
+ def setUp(self):
+ super(TestNegativeGenerator, self).setUp()
+ self.negative = negative_generator.NegativeTestGenerator()
+
def _validate_result(self, data):
self.assertTrue(isinstance(data, list))
for t in data:
self.assertTrue(isinstance(t, tuple))
def test_generate_invalid_string(self):
- result = gen.generate_invalid(self.fake_input_str)
+ result = self.negative.generate(self.fake_input_str)
self._validate_result(result)
def test_generate_invalid_integer(self):
- result = gen.generate_invalid(self.fake_input_int)
+ result = self.negative.generate(self.fake_input_int)
self._validate_result(result)
def test_generate_invalid_obj(self):
- result = gen.generate_invalid(self.fake_input_obj)
+ result = self.negative.generate(self.fake_input_obj)
self._validate_result(result)
diff --git a/tempest/tests/negative/test_negative_auto_test.py b/tempest/tests/negative/test_negative_auto_test.py
index 4c59383..27ddc95 100644
--- a/tempest/tests/negative/test_negative_auto_test.py
+++ b/tempest/tests/negative/test_negative_auto_test.py
@@ -16,9 +16,11 @@
import mock
import tempest.test as test
+from tempest.tests import base
+from tempest.tests import fake_config
-class TestNegativeAutoTest(test.BaseTestCase):
+class TestNegativeAutoTest(base.TestCase):
# Fake entries
_interface = 'json'
_service = 'compute'
@@ -34,6 +36,10 @@
"resources": ["flavor", "volume", "image"]
}
+ def setUp(self):
+ super(TestNegativeAutoTest, self).setUp()
+ self.stubs.Set(test, 'CONF', fake_config.FakeConfig)
+
def _check_prop_entries(self, result, entry):
entries = [a for a in result if entry in a[0]]
self.assertIsNotNone(entries)
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
index 5346052..df04d65 100644
--- a/tempest/tests/test_auth.py
+++ b/tempest/tests/test_auth.py
@@ -100,6 +100,7 @@
class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
+ _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog']
_auth_provider_class = auth.KeystoneV2AuthProvider
def setUp(self):
@@ -111,41 +112,71 @@
def _get_fake_alt_identity(self):
return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
- def _get_result_url_from_fake_identity(self):
- return fake_identity.COMPUTE_ENDPOINTS_V2['endpoints'][1]['publicURL']
+ def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL',
+ replacement=None):
+ if replacement:
+ return ep[endpoint_type].replace('v2', replacement)
+ return ep[endpoint_type]
def _get_token_from_fake_identity(self):
return fake_identity.TOKEN
- def _test_request_helper(self):
+ def _test_request_helper(self, filters, expected):
+ url, headers, body = self.auth_provider.auth_request('GET',
+ self.target_url,
+ filters=filters)
+
+ self.assertEqual(expected['url'], url)
+ self.assertEqual(expected['token'], headers['X-Auth-Token'])
+ self.assertEqual(expected['body'], body)
+
+ def test_request(self):
+ filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion'
+ }
+
+ url = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][1]) + '/' + self.target_url
+
+ expected = {
+ 'body': None,
+ 'url': url,
+ 'token': self._get_token_from_fake_identity(),
+ }
+ self._test_request_helper(filters, expected)
+
+ def test_request_with_alt_auth_cleans_alt(self):
+ self.auth_provider.set_alt_auth_data(
+ 'body',
+ (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
+ self.test_request()
+ # Assert alt auth data is clear after it
+ self.assertIsNone(self.auth_provider.alt_part)
+ self.assertIsNone(self.auth_provider.alt_auth_data)
+
+ def test_request_with_alt_part_without_alt_data(self):
+ """
+ Assert that when alt_part is defined, the corresponding original
+ request element is kept the same.
+ """
filters = {
'service': 'compute',
'endpoint_type': 'publicURL',
'region': 'fakeRegion'
}
+ self.auth_provider.set_alt_auth_data('url', None)
url, headers, body = self.auth_provider.auth_request('GET',
self.target_url,
filters=filters)
- result_url = self._get_result_url_from_fake_identity()
- self.assertEqual(url, result_url + '/' + self.target_url)
+ self.assertEqual(url, self.target_url)
self.assertEqual(self._get_token_from_fake_identity(),
headers['X-Auth-Token'])
self.assertEqual(body, None)
- def test_request(self):
- self._test_request_helper()
-
- def test_request_with_alt_auth(self):
- self.auth_provider.set_alt_auth_data(
- 'body',
- (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
- self._test_request_helper()
- # Assert alt auth data is clear after it
- self.assertIsNone(self.auth_provider.alt_part)
- self.assertIsNone(self.auth_provider.alt_auth_data)
-
def test_request_with_bad_service(self):
filters = {
'service': 'BAD_SERVICE',
@@ -154,7 +185,7 @@
}
self.assertRaises(exceptions.EndpointNotFound,
self.auth_provider.auth_request, 'GET',
- 'http://fakeurl.com/fake_api', filters=filters)
+ self.target_url, filters=filters)
def test_request_without_service(self):
filters = {
@@ -164,7 +195,7 @@
}
self.assertRaises(exceptions.EndpointNotFound,
self.auth_provider.auth_request, 'GET',
- 'http://fakeurl.com/fake_api', filters=filters)
+ self.target_url, filters=filters)
def test_check_credentials_missing_attribute(self):
for attr in ['username', 'password']:
@@ -183,8 +214,86 @@
del cred['tenant_name']
self.assertFalse(self.auth_provider.check_credentials(cred))
+ def _test_base_url_helper(self, expected_url, filters,
+ auth_data=None):
+
+ url = self.auth_provider.base_url(filters, auth_data)
+ self.assertEqual(url, expected_url)
+
+ def test_base_url(self):
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion'
+ }
+ expected = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][1])
+ self._test_base_url_helper(expected, self.filters)
+
+ def test_base_url_to_get_admin_endpoint(self):
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'adminURL',
+ 'region': 'FakeRegion'
+ }
+ expected = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][1], endpoint_type='adminURL')
+ self._test_base_url_helper(expected, self.filters)
+
+ def test_base_url_unknown_region(self):
+ """
+ Assure that if the region is unknow the first endpoint is returned.
+ """
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'AintNoBodyKnowThisRegion'
+ }
+ expected = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][0])
+ self._test_base_url_helper(expected, self.filters)
+
+ def test_base_url_with_non_existent_service(self):
+ self.filters = {
+ 'service': 'BAD_SERVICE',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion'
+ }
+ self.assertRaises(exceptions.EndpointNotFound,
+ self._test_base_url_helper, None, self.filters)
+
+ def test_base_url_without_service(self):
+ self.filters = {
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion'
+ }
+ self.assertRaises(exceptions.EndpointNotFound,
+ self._test_base_url_helper, None, self.filters)
+
+ def test_base_url_with_api_version_filter(self):
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'api_version': 'v12'
+ }
+ expected = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][1], replacement='v12')
+ self._test_base_url_helper(expected, self.filters)
+
+ def test_base_url_with_skip_path_filter(self):
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'publicURL',
+ 'region': 'FakeRegion',
+ 'skip_path': True
+ }
+ expected = 'http://fake_url/'
+ self._test_base_url_helper(expected, self.filters)
+
class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
+ _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
_auth_provider_class = auth.KeystoneV3AuthProvider
credentials = {
'username': 'fake_user',
@@ -201,10 +310,23 @@
def _get_fake_alt_identity(self):
return fake_identity.ALT_IDENTITY_V3['token']
- def _get_result_url_from_fake_identity(self):
- return fake_identity.COMPUTE_ENDPOINTS_V3['endpoints'][1]['url']
+ def _get_result_url_from_endpoint(self, ep, replacement=None):
+ if replacement:
+ return ep['url'].replace('v3', replacement)
+ return ep['url']
def test_check_credentials_missing_tenant_name(self):
cred = copy.copy(self.credentials)
del cred['domain_name']
self.assertFalse(self.auth_provider.check_credentials(cred))
+
+ # Overwrites v2 test
+ def test_base_url_to_get_admin_endpoint(self):
+ self.filters = {
+ 'service': 'compute',
+ 'endpoint_type': 'admin',
+ 'region': 'MiddleEarthRegion'
+ }
+ expected = self._get_result_url_from_endpoint(
+ self._endpoints[0]['endpoints'][2])
+ self._test_base_url_helper(expected, self.filters)
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
index ba43daf..9f07972 100644
--- a/tempest/tests/test_rest_client.py
+++ b/tempest/tests/test_rest_client.py
@@ -164,7 +164,7 @@
keys = ["fake_key1", "fake_key2"]
values = ["fake_value1", "fake_value2"]
- item_expected = {key: value for key, value in zip(keys, values)}
+ item_expected = dict((key, value) for (key, value) in zip(keys, values))
list_expected = {"body_list": [
{keys[0]: values[0]},
{keys[1]: values[1]},
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index b36e8c7..10d421e 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -17,6 +17,7 @@
import logging as orig_logging
import os
import re
+import six
import urlparse
import boto
@@ -26,14 +27,12 @@
import keystoneclient.exceptions
import tempest.clients
-from tempest.common.utils.file_utils import have_effective_read_access
+from tempest.common.utils import file_utils
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
import tempest.test
-from tempest.thirdparty.boto.utils.wait import re_search_wait
-from tempest.thirdparty.boto.utils.wait import state_wait
-from tempest.thirdparty.boto.utils.wait import wait_exception
+from tempest.thirdparty.boto.utils import wait
CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -47,7 +46,7 @@
id_matcher = re.compile("[A-Za-z0-9]{20,}")
def all_read(*args):
- return all(map(have_effective_read_access, args))
+ return all(map(file_utils.have_effective_read_access, args))
materials_path = CONF.boto.s3_materials_path
ami_path = materials_path + os.sep + CONF.boto.ami_manifest
@@ -136,7 +135,7 @@
The not leaf elements does wildcard match
"""
# in error_code just literal and '.' characters expected
- if not isinstance(error_data, basestring):
+ if not isinstance(error_data, six.string_types):
(error_code, status_code) = map(str, error_data)
else:
status_code = None
@@ -146,7 +145,7 @@
num_parts = len(parts)
max_index = num_parts - 1
add_cls = error_cls
- for i_part in xrange(num_parts):
+ for i_part in six.moves.xrange(num_parts):
part = parts[i_part]
leaf = i_part == max_index
if not leaf:
@@ -327,7 +326,7 @@
final_set = set((final_set,))
final_set |= self.gone_set
lfunction = self.get_lfunction_gone(lfunction)
- state = state_wait(lfunction, final_set, valid_set)
+ state = wait.state_wait(lfunction, final_set, valid_set)
self.assertIn(state, valid_set | self.gone_set)
return state
@@ -377,8 +376,8 @@
return "ASSOCIATED"
return "DISASSOCIATED"
- state = state_wait(_disassociate, "DISASSOCIATED",
- set(("ASSOCIATED", "DISASSOCIATED")))
+ state = wait.state_wait(_disassociate, "DISASSOCIATED",
+ set(("ASSOCIATED", "DISASSOCIATED")))
self.assertEqual(state, "DISASSOCIATED")
def assertAddressReleasedWait(self, address):
@@ -391,7 +390,7 @@
return "DELETED"
return "NOTDELETED"
- state = state_wait(_address_delete, "DELETED")
+ state = wait.state_wait(_address_delete, "DELETED")
self.assertEqual(state, "DELETED")
def assertReSearch(self, regexp, string):
@@ -462,7 +461,7 @@
for instance in reservation.instances:
try:
instance.terminate()
- re_search_wait(_instance_state, "_GONE")
+ wait.re_search_wait(_instance_state, "_GONE")
except BaseException:
LOG.exception("Failed to terminate instance %s " % instance)
exc_num += 1
@@ -503,7 +502,8 @@
return volume.status
try:
- re_search_wait(_volume_state, "available") # not validates status
+ wait.re_search_wait(_volume_state, "available")
+ # not validates status
LOG.info(_volume_state())
volume.delete()
except BaseException:
@@ -520,7 +520,7 @@
def _update():
snapshot.update(validate=True)
- wait_exception(_update)
+ wait.wait_exception(_update)
# you can specify tuples if you want to specify the status pattern
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 54861be..bbfbb79 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -16,23 +16,21 @@
from boto import exception
from tempest.common.utils import data_utils
-from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest.common.utils.linux import remote_client
from tempest import config
from tempest import exceptions
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
-from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
-from tempest.thirdparty.boto.utils.wait import re_search_wait
-from tempest.thirdparty.boto.utils.wait import state_wait
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
+from tempest.thirdparty.boto.utils import wait
CONF = config.CONF
LOG = logging.getLogger(__name__)
-class InstanceRunTest(BotoTestCase):
+class InstanceRunTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -57,7 +55,7 @@
cls.addResourceCleanUp(cls.destroy_bucket,
cls.s3_client.connection_data,
cls.bucket_name)
- s3_upload_dir(bucket, cls.materials_path)
+ s3.s3_upload_dir(bucket, cls.materials_path)
cls.images = {"ami":
{"name": data_utils.rand_name("ami-name-"),
"location": cls.bucket_name + "/" + ami_manifest},
@@ -78,14 +76,14 @@
def _state():
retr = cls.ec2_client.get_image(image["image_id"])
return retr.state
- state = state_wait(_state, "available")
+ state = wait.state_wait(_state, "available")
if state != "available":
for _image in cls.images.itervalues():
cls.ec2_client.deregister_image(_image["image_id"])
raise exceptions.EC2RegisterImageException(image_id=
image["image_id"])
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_idempotent_instances(self):
# EC2 run instances idempotently
@@ -123,7 +121,7 @@
_terminate_reservation(reservation_1, rcuk_1)
_terminate_reservation(reservation_2, rcuk_2)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_stop_terminate_instance(self):
# EC2 run, stop and terminate instance
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -148,7 +146,7 @@
instance.terminate()
self.cancelResourceCleanUp(rcuk)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_run_stop_terminate_instance_with_tags(self):
# EC2 run, stop and terminate instance with tags
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -195,8 +193,8 @@
instance.terminate()
self.cancelResourceCleanUp(rcuk)
- @skip_because(bug="1098891")
- @attr(type='smoke')
+ @test.skip_because(bug="1098891")
+ @test.attr(type='smoke')
def test_run_terminate_instance(self):
# EC2 run, terminate immediately
image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -222,8 +220,8 @@
# NOTE(afazekas): doctored test case,
# with normal validation it would fail
- @skip_because(bug="1182679")
- @attr(type='smoke')
+ @test.skip_because(bug="1182679")
+ @test.attr(type='smoke')
def test_integration_1(self):
# EC2 1. integration test (not strict)
image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
@@ -271,9 +269,9 @@
self.assertVolumeStatusWait(volume, "available")
# NOTE(afazekas): it may be reports available before it is available
- ssh = RemoteClient(address.public_ip,
- CONF.compute.ssh_user,
- pkey=self.keypair.material)
+ ssh = remote_client.RemoteClient(address.public_ip,
+ CONF.compute.ssh_user,
+ pkey=self.keypair.material)
text = data_utils.rand_name("Pattern text for console output -")
resp = ssh.write_to_console(text)
self.assertFalse(resp)
@@ -282,7 +280,7 @@
output = instance.get_console_output()
return output.output
- re_search_wait(_output, text)
+ wait.re_search_wait(_output, text)
part_lines = ssh.get_partitions().split('\n')
volume.attach(instance.id, "/dev/vdh")
@@ -291,7 +289,7 @@
return volume.status
self.assertVolumeStatusWait(_volume_state, "in-use")
- re_search_wait(_volume_state, "in-use")
+ wait.re_search_wait(_volume_state, "in-use")
# NOTE(afazekas): Different Hypervisor backends names
# differently the devices,
@@ -305,7 +303,7 @@
return 'DECREASE'
return 'EQUAL'
- state_wait(_part_state, 'INCREASE')
+ wait.state_wait(_part_state, 'INCREASE')
part_lines = ssh.get_partitions().split('\n')
# TODO(afazekas): Resource compare to the flavor settings
@@ -313,10 +311,10 @@
volume.detach()
self.assertVolumeStatusWait(_volume_state, "available")
- re_search_wait(_volume_state, "available")
+ wait.re_search_wait(_volume_state, "available")
LOG.info("Volume %s state: %s", volume.id, volume.status)
- state_wait(_part_state, 'DECREASE')
+ wait.state_wait(_part_state, 'DECREASE')
instance.stop()
address.disassociate()
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 329ace3..dec0170 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -14,9 +14,8 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
def compare_key_pairs(a, b):
@@ -24,7 +23,7 @@
a.fingerprint == b.fingerprint)
-class EC2KeysTest(BotoTestCase):
+class EC2KeysTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -33,7 +32,7 @@
cls.ec = cls.ec2_error_code
# TODO(afazekas): merge create, delete, get test cases
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_ec2_keypair(self):
# EC2 create KeyPair
key_name = data_utils.rand_name("keypair-")
@@ -42,16 +41,16 @@
self.assertTrue(compare_key_pairs(keypair,
self.client.get_key_pair(key_name)))
- @skip_because(bug="1072318")
- @attr(type='smoke')
+ @test.skip_because(bug="1072318")
+ @test.attr(type='smoke')
def test_delete_ec2_keypair(self):
# EC2 delete KeyPair
key_name = data_utils.rand_name("keypair-")
self.client.create_key_pair(key_name)
self.client.delete_key_pair(key_name)
- self.assertEqual(None, self.client.get_key_pair(key_name))
+ self.assertIsNone(self.client.get_key_pair(key_name))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_get_ec2_keypair(self):
# EC2 get KeyPair
key_name = data_utils.rand_name("keypair-")
@@ -60,7 +59,7 @@
self.assertTrue(compare_key_pairs(keypair,
self.client.get_key_pair(key_name)))
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_duplicate_ec2_keypair(self):
# EC2 duplicate KeyPair
key_name = data_utils.rand_name("keypair-")
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index 4b2f01f..d508c07 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -13,12 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class EC2NetworkTest(BotoTestCase):
+class EC2NetworkTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -26,8 +25,8 @@
cls.client = cls.os.ec2api_client
# Note(afazekas): these tests for things duable without an instance
- @skip_because(bug="1080406")
- @attr(type='smoke')
+ @test.skip_because(bug="1080406")
+ @test.attr(type='smoke')
def test_disassociate_not_associated_floating_ip(self):
# EC2 disassociate not associated floating ip
ec2_codes = self.ec2_error_code
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 9b58603..86140ec 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -14,18 +14,18 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class EC2SecurityGroupTest(BotoTestCase):
+class EC2SecurityGroupTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(EC2SecurityGroupTest, cls).setUpClass()
cls.client = cls.os.ec2api_client
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_authorize_security_group(self):
# EC2 Create, authorize/revoke security group
group_name = data_utils.rand_name("securty_group-")
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index 04671c5..6a771e5 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -13,10 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest import config
from tempest.openstack.common import log as logging
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+CONF = config.CONF
LOG = logging.getLogger(__name__)
@@ -25,15 +27,20 @@
a.size == b.size)
-class EC2VolumesTest(BotoTestCase):
+class EC2VolumesTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(EC2VolumesTest, cls).setUpClass()
+
+ if not CONF.service_available.cinder:
+ skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
cls.client = cls.os.ec2api_client
cls.zone = cls.client.get_good_zone()
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_get_delete(self):
# EC2 Create, get, delete Volume
volume = self.client.create_volume(1, self.zone)
@@ -46,7 +53,7 @@
self.client.delete_volume(volume.id)
self.cancelResourceCleanUp(cuk)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_volume_from_snapshot(self):
# EC2 Create volume from snapshot
volume = self.client.create_volume(1, self.zone)
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index f34faac..af6aa8b 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -14,20 +14,19 @@
# under the License.
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.test import skip_because
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(S3BucketsTest, cls).setUpClass()
cls.client = cls.os.s3_client
- @skip_because(bug="1076965")
- @attr(type='smoke')
+ @test.skip_because(bug="1076965")
+ @test.attr(type='smoke')
def test_create_and_get_delete_bucket(self):
# S3 Create, get and delete bucket
bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index 9607a92..d2300ee 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -17,14 +17,14 @@
from tempest.common.utils import data_utils
from tempest import config
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
-from tempest.thirdparty.boto.utils.s3 import s3_upload_dir
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
+from tempest.thirdparty.boto.utils import s3
CONF = config.CONF
-class S3ImagesTest(BotoTestCase):
+class S3ImagesTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
@@ -46,9 +46,9 @@
cls.addResourceCleanUp(cls.destroy_bucket,
cls.s3_client.connection_data,
cls.bucket_name)
- s3_upload_dir(bucket, cls.materials_path)
+ s3.s3_upload_dir(bucket, cls.materials_path)
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_register_get_deregister_ami_image(self):
# Register and deregister ami image
image = {"name": data_utils.rand_name("ami-name-"),
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index a102a22..1ae46de 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -18,18 +18,18 @@
import boto.s3.key
from tempest.common.utils import data_utils
-from tempest.test import attr
-from tempest.thirdparty.boto.test import BotoTestCase
+from tempest import test
+from tempest.thirdparty.boto import test as boto_test
-class S3BucketsTest(BotoTestCase):
+class S3BucketsTest(boto_test.BotoTestCase):
@classmethod
def setUpClass(cls):
super(S3BucketsTest, cls).setUpClass()
cls.client = cls.os.s3_client
- @attr(type='smoke')
+ @test.attr(type='smoke')
def test_create_get_delete_object(self):
# S3 Create, get and delete object
bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/utils/wait.py b/tempest/thirdparty/boto/utils/wait.py
index eed0a92..752ed0f 100644
--- a/tempest/thirdparty/boto/utils/wait.py
+++ b/tempest/thirdparty/boto/utils/wait.py
@@ -17,7 +17,7 @@
import time
import boto.exception
-from testtools import TestCase
+import testtools
from tempest import config
from tempest.openstack.common import log as logging
@@ -44,10 +44,11 @@
return status
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("State change timeout exceeded!"
- '(%ds) While waiting'
- 'for %s at "%s"' %
- (dtime, final_set, status))
+ raise testtools.TestCase\
+ .failureException("State change timeout exceeded!"
+ '(%ds) While waiting'
+ 'for %s at "%s"' %
+ (dtime, final_set, status))
time.sleep(CONF.boto.build_interval)
old_status = status
status = lfunction()
@@ -67,10 +68,11 @@
return result
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException('Pattern find timeout exceeded!'
- '(%ds) While waiting for'
- '"%s" pattern in "%s"' %
- (dtime, regexp, text))
+ raise testtools.TestCase\
+ .failureException('Pattern find timeout exceeded!'
+ '(%ds) While waiting for'
+ '"%s" pattern in "%s"' %
+ (dtime, regexp, text))
time.sleep(CONF.boto.build_interval)
@@ -98,8 +100,8 @@
# Let the other exceptions propagate
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
- dtime)
+ raise testtools.TestCase\
+ .failureException("Wait timeout exceeded! (%ds)" % dtime)
time.sleep(CONF.boto.build_interval)
@@ -116,8 +118,8 @@
return exc
dtime = time.time() - start_time
if dtime > CONF.boto.build_timeout:
- raise TestCase.failureException("Wait timeout exceeded! (%ds)" %
- dtime)
+ raise testtools.TestCase\
+ .failureException("Wait timeout exceeded! (%ds)" % dtime)
time.sleep(CONF.boto.build_interval)
# TODO(afazekas): consider strategy design pattern..
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 15988a6..98e079a 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -32,7 +32,7 @@
def process_files(file_specs, url_specs, whitelists):
- regexp = re.compile(r"^.* (ERROR|CRITICAL) .*\[.*\-.*\]")
+ regexp = re.compile(r"^.* (ERROR|CRITICAL|TRACE) .*\[.*\-.*\]")
had_errors = False
for (name, filename) in file_specs:
whitelist = whitelists.get(name, [])
diff --git a/tox.ini b/tox.ini
index 758d681..4a625f8 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,11 +4,10 @@
skipsdist = True
[testenv]
-sitepackages = True
setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./tempest/test_discover
usedevelop = True
-install_command = pip install {opts} {packages}
+install_command = pip install -U {opts} {packages}
[testenv:py26]
setenv = OS_TEST_PATH=./tempest/tests
@@ -27,11 +26,13 @@
commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
[testenv:all]
+sitepackages = True
setenv = VIRTUAL_ENV={envdir}
commands =
- python setup.py testr --slowest --testr-args='{posargs}'
+ bash tools/pretty_tox.sh '{posargs}'
[testenv:full]
+sitepackages = True
# The regex below is used to select which tests to run and exclude the slow tag:
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
@@ -44,24 +45,29 @@
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:testr-full]
+sitepackages = True
commands =
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:heat-slow]
+sitepackages = True
setenv = OS_TEST_TIMEOUT=1200
# The regex below is used to select heat api/scenario tests tagged as slow.
commands =
bash tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
[testenv:large-ops]
+sitepackages = True
commands =
python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
[testenv:smoke]
+sitepackages = True
commands =
bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:smoke-serial]
+sitepackages = True
# This is still serial because neutron doesn't work with parallel. See:
# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
# job would fail if we moved it to parallel.
@@ -69,6 +75,7 @@
bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
[testenv:stress]
+sitepackages = True
commands =
python -m tempest/stress/run_stress -a -d 3600 -S