Merge "Fixes LP#921409 * Adds /servers filter tests * Re-ordered resource building in fixtures to improve execution time"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index dd14e13..da35c8f 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -9,6 +9,7 @@
ssh_timeout=300
build_interval=10
build_timeout=600
+catalog_name=nova
[environment]
image_ref=3
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 119494d..754a1f6 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -128,6 +128,11 @@
self._log(req_url, body, resp, resp_body)
raise exceptions.BadRequest(resp_body['badRequest']['message'])
+ if resp.status == 409:
+ resp_body = json.loads(resp_body)
+ self._log(req_url, body, resp, resp_body)
+ raise exceptions.Duplicate(resp_body)
+
if resp.status == 413:
resp_body = json.loads(resp_body)
self._log(req_url, body, resp, resp_body)
@@ -150,4 +155,9 @@
message = resp_body['computeFault']['message']
raise exceptions.ComputeFault(message)
+ if resp.status >= 400:
+ resp_body = json.loads(resp_body)
+ self._log(req_url, body, resp, resp_body)
+ raise exceptions.TempestException(str(resp.status))
+
return resp, resp_body
diff --git a/tempest/config.py b/tempest/config.py
index 6f816d2..960ff74 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -88,6 +88,11 @@
"""Timeout in seconds to wait for an entity to build."""
return float(self.get("build_timeout", 300))
+ @property
+ def catalog_name(self):
+ """Catalog name of the Nova service."""
+ return self.get("catalog_name", 'nova')
+
class EnvironmentConfig(object):
def __init__(self, conf):
@@ -135,6 +140,11 @@
""" What auth method does the environment use (basic|keystone) """
return self.get("authentication", 'keystone')
+ @property
+ def release_name(self):
+ """ Which release is this? """
+ return self.get("release_name", 'essex')
+
class ImagesConfig(object):
"""
diff --git a/tempest/services/nova/json/extensions_client.py b/tempest/services/nova/json/extensions_client.py
index abd8957..5f2cac4 100644
--- a/tempest/services/nova/json/extensions_client.py
+++ b/tempest/services/nova/json/extensions_client.py
@@ -6,8 +6,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
def list_extensions(self):
url = 'extensions'
diff --git a/tempest/services/nova/json/flavors_client.py b/tempest/services/nova/json/flavors_client.py
index 60807a3..b592781 100644
--- a/tempest/services/nova/json/flavors_client.py
+++ b/tempest/services/nova/json/flavors_client.py
@@ -6,8 +6,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
def list_flavors(self, params=None):
url = 'flavors'
diff --git a/tempest/services/nova/json/floating_ips_client.py b/tempest/services/nova/json/floating_ips_client.py
index 8bd276f..4a9f9eb 100644
--- a/tempest/services/nova/json/floating_ips_client.py
+++ b/tempest/services/nova/json/floating_ips_client.py
@@ -6,8 +6,12 @@
class FloatingIPsClient(object):
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
+ self.headers = {'Content-Type': 'application/json',
+ 'Accept': 'application/json'}
def list_floating_ips(self, params=None):
"""Returns a list of all floating IPs filtered by any parameters"""
@@ -43,21 +47,28 @@
resp, body = self.client.delete(url)
return resp, body
- def associate_floating_ip_to_server(self, floating_ip_id, fixed_ip_addr):
+ def associate_floating_ip_to_server(self, floating_ip, server_id):
"""Associate the provided floating IP to a specific server"""
- url = "os-floating-ips/%s/associate" % str(floating_ip_id)
+ url = "servers/%s/action" % str(server_id)
post_body = {
- 'associate_address': {
- 'fixed_ip': fixed_ip_addr,
+ 'addFloatingIp': {
+ 'address': floating_ip,
}
}
post_body = json.dumps(post_body)
- resp, body = self.client.post(url, post_body, None)
+ resp, body = self.client.post(url, post_body, self.headers)
return resp, body
- def disassociate_floating_ip_from_server(self, floating_ip_id):
+ def disassociate_floating_ip_from_server(self, floating_ip, server_id):
"""Disassociate the provided floating IP from a specific server"""
- url = "os-floating-ips/%s/disassociate" % str(floating_ip_id)
- resp, body = self.client.post(url, None, None)
+ url = "servers/%s/action" % str(server_id)
+ post_body = {
+ 'removeFloatingIp': {
+ 'address': floating_ip,
+ }
+ }
+
+ post_body = json.dumps(post_body)
+ resp, body = self.client.post(url, post_body, self.headers)
return resp, body
diff --git a/tempest/services/nova/json/images_client.py b/tempest/services/nova/json/images_client.py
index 12c1774..435e2fa 100644
--- a/tempest/services/nova/json/images_client.py
+++ b/tempest/services/nova/json/images_client.py
@@ -8,8 +8,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout
diff --git a/tempest/services/nova/json/keypairs_client.py b/tempest/services/nova/json/keypairs_client.py
index 73b92a9..88dfcfe 100644
--- a/tempest/services/nova/json/keypairs_client.py
+++ b/tempest/services/nova/json/keypairs_client.py
@@ -6,8 +6,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
self.headers = {'Content-Type': 'application/json',
'Accept': 'application/json'}
diff --git a/tempest/services/nova/json/limits_client.py b/tempest/services/nova/json/limits_client.py
index f06235c..9b96fb4 100644
--- a/tempest/services/nova/json/limits_client.py
+++ b/tempest/services/nova/json/limits_client.py
@@ -5,8 +5,11 @@
class LimitsClient(object):
def __init__(self, config, username, key, auth_url, tenant_name=None):
+ self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
def get_limits(self):
resp, body = self.client.get("limits")
diff --git a/tempest/services/nova/json/security_groups_client.py b/tempest/services/nova/json/security_groups_client.py
index b365ce5..05ba61f 100644
--- a/tempest/services/nova/json/security_groups_client.py
+++ b/tempest/services/nova/json/security_groups_client.py
@@ -6,8 +6,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
def list_security_groups(self, params=None):
"""List all security groups for a user"""
diff --git a/tempest/services/nova/json/servers_client.py b/tempest/services/nova/json/servers_client.py
index 4f2e257..0d343d2 100644
--- a/tempest/services/nova/json/servers_client.py
+++ b/tempest/services/nova/json/servers_client.py
@@ -8,8 +8,10 @@
def __init__(self, config, username, key, auth_url, tenant_name=None):
self.config = config
+ catalog_name = self.config.nova.catalog_name
self.client = rest_client.RestClient(config, username, key,
- auth_url, 'nova', tenant_name)
+ auth_url, catalog_name,
+ tenant_name)
self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout
diff --git a/tempest/tests/test_flavors.py b/tempest/tests/test_flavors.py
index 7e87830..3ddcb58 100644
--- a/tempest/tests/test_flavors.py
+++ b/tempest/tests/test_flavors.py
@@ -2,10 +2,13 @@
from nose.plugins.attrib import attr
from tempest import exceptions
from tempest import openstack
+import tempest.config
class FlavorsTest(unittest.TestCase):
+ release = tempest.config.TempestConfig().env.release_name
+
@classmethod
def setUpClass(cls):
cls.os = openstack.Manager()
@@ -41,7 +44,7 @@
self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
999)
- @unittest.expectedFailure
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive', bug='lp912922')
def test_list_flavors_limit_results(self):
"""Only the expected number of flavors should be returned"""
@@ -49,7 +52,7 @@
resp, flavors = self.client.list_flavors(params)
self.assertEqual(1, len(flavors))
- @unittest.expectedFailure
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive', bug='lp912922')
def test_list_flavors_detailed_limit_results(self):
"""Only the expected number of flavors (detailed) should be returned"""
@@ -81,6 +84,7 @@
self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
'The list of flavors did not start after the marker.')
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive')
def test_list_flavors_detailed_filter_by_min_disk(self):
"""The detailed list of flavors should be filtered by disk space"""
@@ -92,6 +96,7 @@
resp, flavors = self.client.list_flavors_with_detail(params)
self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive')
def test_list_flavors_detailed_filter_by_min_ram(self):
"""The detailed list of flavors should be filtered by RAM"""
@@ -103,6 +108,7 @@
resp, flavors = self.client.list_flavors_with_detail(params)
self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive')
def test_list_flavors_filter_by_min_disk(self):
"""The list of flavors should be filtered by disk space"""
@@ -114,6 +120,7 @@
resp, flavors = self.client.list_flavors(params)
self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='positive')
def test_list_flavors_filter_by_min_ram(self):
"""The list of flavors should be filtered by RAM"""
diff --git a/tempest/tests/test_floating_ips_actions.py b/tempest/tests/test_floating_ips_actions.py
index ab9e22d..e5862c1 100644
--- a/tempest/tests/test_floating_ips_actions.py
+++ b/tempest/tests/test_floating_ips_actions.py
@@ -7,7 +7,7 @@
class FloatingIPsTest(unittest.TestCase):
server_id = None
- floating_ip_id = None
+ floating_ip = None
@classmethod
def setUpClass(cls):
@@ -28,6 +28,7 @@
#Floating IP creation
resp, body = cls.client.create_floating_ip()
cls.floating_ip_id = body['id']
+ cls.floating_ip = body['ip']
#Generating a nonexistant floatingIP id
cls.floating_ip_ids = []
resp, body = cls.client.list_floating_ips()
@@ -89,12 +90,13 @@
l"""
#Association of floating IP to fixed IP address
resp, body =\
- self.client.associate_floating_ip_to_server(self.floating_ip_id,
- self.fixed_ip_addr)
+ self.client.associate_floating_ip_to_server(self.floating_ip,
+ self.server_id)
self.assertEqual(202, resp.status)
#Disassociation of floating IP that was associated in this method
resp, body = \
- self.client.disassociate_floating_ip_from_server(floating_ip_id)
+ self.client.disassociate_floating_ip_from_server(self.floating_ip,
+ self.server_id)
@attr(type='positive')
def test_dissociate_floating_ip(self):
@@ -105,11 +107,12 @@
#Association of floating IP to a specific server
#so as to check dissociation
resp, body = \
- self.client.associate_floating_ip_to_server(self.floating_ip_id,
- self.fixed_ip_addr)
+ self.client.associate_floating_ip_to_server(self.floating_ip,
+ self.server_id)
#Disassociation of floating IP
resp, body = \
- self.client.disassociate_floating_ip_from_server(self.floating_ip_id)
+ self.client.disassociate_floating_ip_from_server(self.floating_ip,
+ self.server_id)
self.assertEqual(202, resp.status)
@attr(type='negative')
@@ -122,7 +125,7 @@
#Deleting the non existant floating IP
try:
resp, body = self.client.delete_floating_ip(self.non_exist_id)
- except exceptions.NotFound:
+ except:
pass
else:
self.fail('Should not be able to delete a nonexistant floating IP')
@@ -136,9 +139,9 @@
#Associating non existant floating IP
try:
resp, body = \
- self.client.associate_floating_ip_to_server(self.non_exist_id,
- self.fixed_ip_addr)
- except exceptions.NotFound:
+ self.client.associate_floating_ip_to_server("0.0.0.0",
+ self.server_id)
+ except:
pass
else:
self.fail('Should not be able to associate'
@@ -152,8 +155,9 @@
#Dissociating non existant floating IP
try:
resp, body = \
- self.client.disassociate_floating_ip_from_server(self.non_exist_id)
- except exceptions.NotFound:
+ self.client.disassociate_floating_ip_from_server("0.0.0.0",
+ self.server_id)
+ except:
pass
else:
self.fail('Should not be able to dissociate'
diff --git a/tempest/tests/test_keypairs.py b/tempest/tests/test_keypairs.py
index 4b75524..53fcd0b 100644
--- a/tempest/tests/test_keypairs.py
+++ b/tempest/tests/test_keypairs.py
@@ -2,10 +2,14 @@
import unittest2 as unittest
from tempest import openstack
from tempest.common.utils.data_utils import rand_name
+import tempest.config
+from tempest import exceptions
class KeyPairsTest(unittest.TestCase):
+ release = tempest.config.TempestConfig().env.release_name
+
@classmethod
def setUpClass(cls):
cls.os = openstack.Manager()
@@ -62,26 +66,6 @@
self.assertEqual(202, resp.status)
@attr(type='smoke')
- def test_keypair_create_get_delete(self):
- """Keypair should be created, fetched and deleted"""
- k_name = rand_name('keypair-')
- resp, keypair = self.client.create_keypair(k_name)
- self.assertEqual(200, resp.status)
- #Need to pop these keys so that our compare doesn't fail later,
- #as the keypair dicts from get API doesn't have them.
- keypair.pop('private_key')
- keypair.pop('user_id')
- #Now fetch the created keypair by its name
- resp, fetched_key = self.client.get_keypair(k_name)
- self.assertEqual(200, resp.status)
-
- self.assertEqual(keypair, fetched_key,
- "The fetched keypair is different from the created key")
- #Delete the keypair
- resp, _ = self.client.delete_keypair(k_name)
- self.assertEqual(202, resp.status)
-
- @attr(type='smoke')
def test_keypair_create_with_pub_key(self):
"""Keypair should be created with a given public key"""
k_name = rand_name('keypair-')
@@ -109,23 +93,23 @@
"""Keypair should not be created with a non RSA public key"""
k_name = rand_name('keypair-')
pub_key = "ssh-rsa JUNK nova@ubuntu"
- resp, _ = self.client.create_keypair(k_name, pub_key)
- self.assertEqual(400, resp.status)
-
- @attr(type='negative')
- def test_keypair_create_with_empty_pub_key(self):
- """Keypair should not be created with an empty public key"""
- k_name = rand_name('keypair-')
- pub_key = ""
- resp, _ = self.client.create_keypair(k_name, pub_key)
- self.assertEqual(400, resp.status)
+ try:
+ resp, _ = self.client.create_keypair(k_name, pub_key)
+ except exceptions.BadRequest:
+ pass
+ else:
+ self.fail('Expected BadRequest for invalid public key')
@attr(type='negative')
def test_keypair_delete_nonexistant_key(self):
"""Non-existant key deletion should throw a proper error"""
k_name = rand_name("keypair-non-existant-")
- resp, _ = self.client.delete_keypair(k_name)
- self.assertEqual(400, resp.status)
+ try:
+ resp, _ = self.client.delete_keypair(k_name)
+ except exceptions.NotFound:
+ pass
+ else:
+ self.fail('nonexistent key')
@attr(type='negative')
def test_create_keypair_with_duplicate_name(self):
@@ -134,19 +118,34 @@
resp, _ = self.client.create_keypair(k_name)
self.assertEqual(200, resp.status)
#Now try the same keyname to ceate another key
- resp, _ = self.client.create_keypair(k_name)
- #Expect a HTTP 409 Conflict Error
- self.assertEqual(409, resp.status)
+ try:
+ resp, _ = self.client.create_keypair(k_name)
+ #Expect a HTTP 409 Conflict Error
+ except exceptions.Duplicate:
+ pass
+ else:
+ self.fail('duplicate name')
+ resp, _ = self.client.delete_keypair(k_name)
+ self.assertEqual(202, resp.status)
@attr(type='negative')
def test_create_keypair_with_empty_name_string(self):
"""Keypairs with name being an empty string should not be created"""
- resp, _ = self.client.create_keypair('')
- self.assertEqual(400, resp.status)
+ try:
+ resp, _ = self.client.create_keypair('')
+ except exceptions.BadRequest:
+ pass
+ else:
+ self.fail('empty string')
+ @unittest.skipIf(release == 'diablo', 'bug in diablo')
@attr(type='negative')
def test_create_keypair_with_long_keynames(self):
"""Keypairs with name longer than 255 chars should not be created"""
k_name = 'keypair-'.ljust(260, '0')
- resp, _ = self.client.create_keypair(k_name)
- self.assertEqual(400, resp.status)
+ try:
+ resp, _ = self.client.create_keypair(k_name)
+ except exceptions.BadRequest:
+ pass
+ else:
+ self.fail('too long')
diff --git a/tempest/tests/test_server_actions.py b/tempest/tests/test_server_actions.py
index 3581845..ab7c801 100644
--- a/tempest/tests/test_server_actions.py
+++ b/tempest/tests/test_server_actions.py
@@ -123,8 +123,7 @@
Negative Test: The server reboot on non existant server should return
an error
"""
- resp, body = self.client.reboot(999, 'SOFT')
- self.assertEqual(404, resp.status)
+ self.assertRaises(exceptions.NotFound, self.client.reboot, 999, 'SOFT')
@attr(type='negative')
def test_rebuild_nonexistant_server(self):
diff --git a/tempest/tests/test_server_metadata.py b/tempest/tests/test_server_metadata.py
index 1fc6de8..18491ca 100644
--- a/tempest/tests/test_server_metadata.py
+++ b/tempest/tests/test_server_metadata.py
@@ -54,6 +54,7 @@
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
self.assertEqual(resp_metadata, req_metadata)
+ @attr(type='negative')
def test_server_create_metadata_key_too_long(self):
"""
Attempt to start a server with a meta-data key that is > 255 characters
@@ -63,10 +64,14 @@
key = "k" * sz
meta = {key: 'data1'}
name = rand_name('server')
- resp, server = self.client.create_server(name, self.image_ref,
- self.flavor_ref,
- meta=meta)
- self.assertEqual(413, resp.status)
+ try:
+ resp, server = self.client.create_server(name, self.image_ref,
+ self.flavor_ref,
+ meta=meta)
+ except:
+ pass
+ else:
+ self.fail('Metadata should have been too long')
# no teardown - all creates should fail
def test_update_server_metadata(self):
@@ -170,8 +175,12 @@
Negative test: Should not be able to delete metadata item from a
nonexistant server
"""
- meta = {'delkey': 'delvalue'}
+ meta = {'d': 'delvalue'}
#Delete the metadata item
- resp, metadata = self.client.delete_server_metadata_item(999, 'delkey')
- self.assertEqual(404, resp.status)
+ try:
+ resp, metadata = self.client.delete_server_metadata_item(999, 'd')
+ except:
+ pass
+ else:
+ self.fail('A delete should not happen for a nonexistant image')
diff --git a/tempest/tools/conf_from_devstack b/tempest/tools/conf_from_devstack
index 15346d9..8baa8fb 100755
--- a/tempest/tools/conf_from_devstack
+++ b/tempest/tools/conf_from_devstack
@@ -159,7 +159,7 @@
[environment]
image_ref=%(base_image_uuid)s
-image_ref_alt=4
+image_ref_alt=%(base_image_uuid)s
flavor_ref=1
flavor_ref_alt=2
create_image_enabled=true