Changes the namespace from storm to tempest, as well as adding addition tests and improvements
* Changed namespace from storm to tempest
* Added absolute limits service and server personality file tests
* Optimized run time for image metadata tests
* Added additional assertions for create server and rebuild server tests
* Removed any SSH verification until further decisions are made
Change-Id: I5bebd29be382c9404914c7314302670ae09627fc
diff --git a/etc/STORM_README.txt b/etc/TEMPEST_README.txt
similarity index 69%
rename from etc/STORM_README.txt
rename to etc/TEMPEST_README.txt
index d445896..e46e195 100644
--- a/etc/STORM_README.txt
+++ b/etc/TEMPEST_README.txt
@@ -1,8 +1,8 @@
To run:
--rename the /etc/storm.conf.sample file to storm.conf
+-rename the /etc/tempest.conf.sample file to tempest.conf
-Set the fields in the file to values relevant to your system
-Set the "authentication" value (basic or keystone_v2 currently supported)
--from the root directory of the project, run "nosetests storm/tests" to
+-from the root directory of the project, run "nosetests tempest/tests" to
run all tests
TODO:
diff --git a/etc/storm.conf.sample b/etc/tempest.conf.sample
similarity index 100%
rename from etc/storm.conf.sample
rename to etc/tempest.conf.sample
diff --git a/storm/tests/test_image_metadata.py b/storm/tests/test_image_metadata.py
deleted file mode 100644
index c8dff27..0000000
--- a/storm/tests/test_image_metadata.py
+++ /dev/null
@@ -1,158 +0,0 @@
-from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
-import storm.config
-import unittest2 as unittest
-
-
-class ImagesMetadataTest(unittest.TestCase):
-
- @classmethod
- def setUpClass(cls):
- cls.os = openstack.Manager()
- cls.servers_client = cls.os.servers_client
- cls.client = cls.os.images_client
- cls.config = cls.os.config
- cls.image_ref = cls.config.env.image_ref
- cls.flavor_ref = cls.config.env.flavor_ref
- cls.ssh_timeout = cls.config.nova.ssh_timeout
-
- name = rand_name('server')
- resp, cls.server = cls.servers_client.create_server(name,
- cls.image_ref,
- cls.flavor_ref)
- #Wait for the server to become active
- cls.servers_client.wait_for_server_status(cls.server['id'], 'ACTIVE')
-
- #Create an image from the server
- name = rand_name('image')
- cls.meta = {'key1': 'value1', 'key2': 'value2'}
- resp, body = cls.client.create_image(cls.server['id'], name, cls.meta)
- image_ref = resp['location']
- temp = image_ref.rsplit('/')
- image_id = temp[len(temp) - 1]
-
- cls.client.wait_for_image_resp_code(image_id, 200)
- cls.client.wait_for_image_status(image_id, 'ACTIVE')
- resp, cls.image = cls.client.get_image(image_id)
-
- @classmethod
- def tearDownClass(cls):
- cls.servers_client.delete_server(cls.server['id'])
- cls.client.delete_image(cls.image['id'])
-
- def _parse_image_id(self, image_ref):
- temp = image_ref.rsplit('/')
- return len(temp) - 1
-
- def test_list_image_metadata(self):
- """All metadata key/value pairs for an image should be returned"""
- resp, metadata = self.client.list_image_metadata(self.image['id'])
- self.assertEqual('value1', metadata['key1'])
- self.assertEqual('value2', metadata['key2'])
-
- def test_set_image_metadata(self):
- """The metadata for the image should match the new values"""
- meta = {'meta1': 'data1'}
- name = rand_name('server')
- resp, server = self.servers_client.create_server(name, self.image_ref,
- self.flavor_ref)
- self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
-
- name = rand_name('image')
- resp, body = self.client.create_image(server['id'], name, meta)
- image_id = self._parse_image_id(resp['location'])
- self.client.wait_for_image_resp_code(image_id, 200)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
- resp, image = self.client.get_image(image_id)
-
- meta = {'meta2': 'data2', 'meta3': 'data3'}
- resp, body = self.client.set_image_metadata(image['id'], meta)
-
- resp, metadata = self.client.list_image_metadata(image['id'])
- self.assertEqual('data2', metadata['meta2'])
- self.assertEqual('data3', metadata['meta3'])
- self.assertTrue('meta1' not in metadata)
-
- self.servers_client.delete_server(server['id'])
- self.client.delete_image(image['id'])
-
- def test_update_image_metadata(self):
- """The metadata for the image should match the updated values"""
- meta = {'key1': 'value1', 'key2': 'value2'}
- name = rand_name('server')
- resp, server = self.servers_client.create_server(name, self.image_ref,
- self.flavor_ref)
- self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
-
- name = rand_name('image')
- resp, body = self.client.create_image(server['id'], name, meta)
- image_id = self._parse_image_id(resp['location'])
- self.client.wait_for_image_resp_code(image_id, 200)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
- resp, image = self.client.get_image(image_id)
-
- meta = {'key1': 'alt1', 'key2': 'alt2'}
- resp, metadata = self.client.update_image_metadata(image['id'], meta)
-
- resp, metadata = self.client.list_image_metadata(image['id'])
- self.assertEqual('alt1', metadata['key1'])
- self.assertEqual('alt2', metadata['key2'])
-
- self.servers_client.delete_server(server['id'])
- self.client.delete_image(image['id'])
-
- def test_get_image_metadata_item(self):
- """The value for a specic metadata key should be returned"""
- resp, meta = self.client.get_image_metadata_item(self.image['id'],
- 'key2')
- self.assertTrue('value2', meta['key2'])
-
- def test_set_image_metadata_item(self):
- """
- The value provided for the given meta item should be set for the image
- """
- meta = {'nova': 'server'}
- name = rand_name('server')
- resp, server = self.servers_client.create_server(name, self.image_ref,
- self.flavor_ref)
- self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
-
- name = rand_name('image')
- resp, body = self.client.create_image(server['id'], name, meta)
- image_id = self._parse_image_id(resp['location'])
- self.client.wait_for_image_resp_code(image_id, 200)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
- resp, image = self.client.get_image(image_id)
-
- meta = {'nova': 'alt'}
- resp, body = self.client.set_image_metadata_item(image['id'],
- 'nova', meta)
- resp, metadata = self.client.list_image_metadata(image['id'])
- self.assertEqual('alt', metadata['nova'])
-
- self.servers_client.delete_server(server['id'])
- self.client.delete_image(image['id'])
-
- def test_delete_image_metadata_item(self):
- """The metadata value/key pair should be deleted from the image"""
- meta = {'delkey': 'delvalue'}
- name = rand_name('server')
- resp, server = self.servers_client.create_server(name, self.image_ref,
- self.flavor_ref)
- self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
-
- name = rand_name('image')
- resp, body = self.client.create_image(server['id'], name, meta)
- image_id = self._parse_image_id(resp['location'])
- self.client.wait_for_image_resp_code(image_id, 200)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
- resp, image = self.client.get_image(image_id)
-
- resp, body = self.client.delete_image_metadata_item(image['id'],
- 'delkey')
- resp, metadata = self.client.list_image_metadata(image['id'])
- self.assertTrue('delkey' not in metadata)
-
- self.servers_client.delete_server(server['id'])
- self.client.delete_image(image['id'])
diff --git a/storm/tests/test_server_actions.py b/storm/tests/test_server_actions.py
deleted file mode 100644
index d7c9db4..0000000
--- a/storm/tests/test_server_actions.py
+++ /dev/null
@@ -1,98 +0,0 @@
-from nose.plugins.attrib import attr
-from storm import openstack
-import unittest2 as unittest
-import storm.config
-from storm.common.utils.data_utils import rand_name
-
-# Some module-level skip conditions
-resize_available = False
-
-class ServerActionsTest(unittest.TestCase):
-
- @classmethod
- def setUpClass(cls):
- cls.os = openstack.Manager()
- cls.client = cls.os.servers_client
- cls.config = cls.os.config
- cls.image_ref = cls.config.env.image_ref
- cls.image_ref_alt = cls.config.env.image_ref_alt
- cls.flavor_ref = cls.config.env.flavor_ref
- cls.flavor_ref_alt = cls.config.env.flavor_ref_alt
- resize_available = cls.config.env.resize_available
-
- def setUp(self):
- self.name = rand_name('server')
- resp, server = self.client.create_server(self.name, self.image_ref,
- self.flavor_ref)
- self.id = server['id']
- self.client.wait_for_server_status(self.id, 'ACTIVE')
-
- def tearDown(self):
- self.client.delete_server(self.id)
-
- @attr(type='smoke')
- def test_change_server_password(self):
- """The server's password should be set to the provided password"""
- resp, body = self.client.change_password(self.id, 'newpass')
- self.client.wait_for_server_status(self.id, 'ACTIVE')
- #TODO: SSH in to verify the new password works
-
- @attr(type='smoke')
- def test_reboot_server_hard(self):
- """ The server should be power cycled """
- #TODO: Add validation the server has been rebooted
-
- resp, body = self.client.reboot(self.id, 'HARD')
- self.client.wait_for_server_status(self.id, 'ACTIVE')
-
- @attr(type='smoke')
- def test_reboot_server_soft(self):
- """The server should be signaled to reboot gracefully"""
- #TODO: Add validation the server has been rebooted
-
- resp, body = self.client.reboot(self.id, 'SOFT')
- self.client.wait_for_server_status(self.id, 'ACTIVE')
-
- @attr(type='smoke')
- def test_rebuild_server(self):
- """The server should be rebuilt using the provided image"""
-
- self.client.rebuild(self.id, self.image_ref_alt, name='rebuiltserver')
- self.client.wait_for_server_status(self.id, 'ACTIVE')
- resp, server = self.client.get_server(self.id)
- self.assertEqual(self.image_ref_alt, server['image']['id'])
- self.assertEqual('rebuiltserver', server['name'])
-
- @attr(type='smoke')
- @unittest.skipIf(not resize_available, 'Resize not available.')
- def test_resize_server_confirm(self):
- """
- The server's RAM and disk space should be modified to that of
- the provided flavor
- """
-
- self.client.resize(self.id, self.flavor_ref_alt)
- self.client.wait_for_server_status(self.id, 'VERIFY_RESIZE')
-
- self.client.confirm_resize(self.id)
- self.client.wait_for_server_status(self.id, 'ACTIVE')
-
- resp, server = self.client.get_server(self.id)
- self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
-
- @attr(type='smoke')
- @unittest.skipIf(not resize_available, 'Resize not available.')
- def test_resize_server_revert(self):
- """
- The server's RAM and disk space should return to its original
- values after a resize is reverted
- """
-
- self.client.resize(self.id, self.flavor_ref_alt)
- self.client.wait_for_server_status(id, 'VERIFY_RESIZE')
-
- self.client.revert_resize(self.id)
- self.client.wait_for_server_status(id, 'ACTIVE')
-
- resp, server = self.client.get_server(id)
- self.assertEqual(self.flavor_ref, server['flavor']['id'])
diff --git a/storm/__init__.py b/tempest/__init__.py
similarity index 100%
rename from storm/__init__.py
rename to tempest/__init__.py
diff --git a/storm/common/__init__.py b/tempest/common/__init__.py
similarity index 100%
rename from storm/common/__init__.py
rename to tempest/common/__init__.py
diff --git a/storm/common/rest_client.py b/tempest/common/rest_client.py
similarity index 90%
rename from storm/common/rest_client.py
rename to tempest/common/rest_client.py
index 170e523..94e44e4 100644
--- a/storm/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -2,8 +2,8 @@
import httplib2
-from storm import exceptions
-import storm.config
+from tempest import exceptions
+import tempest.config
class RestClient(object):
@@ -102,4 +102,12 @@
body = json.loads(body)
raise exceptions.BadRequest(body['badRequest']['message'])
+ if resp.status == 413:
+ body = json.loads(body)
+ raise exceptions.OverLimit(body['overLimit']['message'])
+
+ if resp.status in (500, 501):
+ body = json.loads(body)
+ raise exceptions.ComputeFault(body['computeFault']['message'])
+
return resp, body
diff --git a/storm/common/ssh.py b/tempest/common/ssh.py
similarity index 100%
rename from storm/common/ssh.py
rename to tempest/common/ssh.py
diff --git a/storm/common/utils/__init__.py b/tempest/common/utils/__init__.py
similarity index 100%
rename from storm/common/utils/__init__.py
rename to tempest/common/utils/__init__.py
diff --git a/storm/common/utils/data_utils.py b/tempest/common/utils/data_utils.py
similarity index 100%
rename from storm/common/utils/data_utils.py
rename to tempest/common/utils/data_utils.py
diff --git a/storm/config.py b/tempest/config.py
similarity index 98%
rename from storm/config.py
rename to tempest/config.py
index 42b9894..2bbadc7 100644
--- a/storm/config.py
+++ b/tempest/config.py
@@ -120,9 +120,10 @@
return self.get("authentication", 'keystone')
-class StormConfig(object):
+class TempestConfig(object):
"""Provides OpenStack configuration information."""
+
def __init__(self, conf_dir, conf_file):
"""
Initialize a configuration from a conf directory and conf file.
diff --git a/storm/exceptions.py b/tempest/exceptions.py
similarity index 78%
rename from storm/exceptions.py
rename to tempest/exceptions.py
index 9290cf7..b4d056d 100644
--- a/storm/exceptions.py
+++ b/tempest/exceptions.py
@@ -16,10 +16,18 @@
def __str__(self):
return repr(self.message)
-
-
+
+
class AuthenticationFailure(Exception):
msg = ("Authentication with user %(user)s and password "
"%(password)s failed.")
def __init__(self, **kwargs):
self.message = self.msg % kwargs
+
+
+class OverLimit(Exception):
+ def __init__(self, message):
+ self.message = message
+
+ def __str__(self):
+ return repr(self.message)
diff --git a/storm/openstack.py b/tempest/openstack.py
similarity index 74%
rename from storm/openstack.py
rename to tempest/openstack.py
index 78f8c03..15cfaf9 100644
--- a/storm/openstack.py
+++ b/tempest/openstack.py
@@ -1,10 +1,11 @@
import os
-from storm.services.nova.json.images_client import ImagesClient
-from storm.services.nova.json.flavors_client import FlavorsClient
-from storm.services.nova.json.servers_client import ServersClient
-from storm.common.utils import data_utils
-import storm.config
+from tempest.services.nova.json.images_client import ImagesClient
+from tempest.services.nova.json.flavors_client import FlavorsClient
+from tempest.services.nova.json.servers_client import ServersClient
+from tempest.services.nova.json.limits_client import LimitsClient
+from tempest.common.utils import data_utils
+import tempest.config
class Manager(object):
@@ -48,6 +49,12 @@
self.config.nova.api_key,
self.auth_url,
self.config.nova.tenant_name)
+ self.limits_client = LimitsClient(self.config,
+ self.config.nova.username,
+ self.config.nova.api_key,
+ self.auth_url,
+ self.config.nova.tenant_name)
+
else:
#Assuming basic/native authentication
self.servers_client = ServersClient(self.config,
@@ -63,3 +70,8 @@
self.config.nova.auth_url,
self.config.nova.api_key,
self.auth_url)
+ self.limits_client = LimitsClient(self.config,
+ self.config.nova.username,
+ self.config.nova.auth_url,
+ self.config.nova.api_key,
+ self.auth_url)
diff --git a/storm/services/__init__.py b/tempest/services/__init__.py
similarity index 100%
rename from storm/services/__init__.py
rename to tempest/services/__init__.py
diff --git a/storm/services/nova/__init__.py b/tempest/services/nova/__init__.py
similarity index 100%
rename from storm/services/nova/__init__.py
rename to tempest/services/nova/__init__.py
diff --git a/storm/services/nova/json/__init__.py b/tempest/services/nova/json/__init__.py
similarity index 100%
rename from storm/services/nova/json/__init__.py
rename to tempest/services/nova/json/__init__.py
diff --git a/storm/services/nova/json/flavors_client.py b/tempest/services/nova/json/flavors_client.py
similarity index 96%
rename from storm/services/nova/json/flavors_client.py
rename to tempest/services/nova/json/flavors_client.py
index d6526c8..e3a030f 100644
--- a/storm/services/nova/json/flavors_client.py
+++ b/tempest/services/nova/json/flavors_client.py
@@ -1,4 +1,4 @@
-from storm.common import rest_client
+from tempest.common import rest_client
import json
import time
diff --git a/storm/services/nova/json/images_client.py b/tempest/services/nova/json/images_client.py
similarity index 97%
rename from storm/services/nova/json/images_client.py
rename to tempest/services/nova/json/images_client.py
index 59e9269..e5871cb 100644
--- a/storm/services/nova/json/images_client.py
+++ b/tempest/services/nova/json/images_client.py
@@ -1,6 +1,7 @@
-from storm.common import rest_client
+from tempest.common import rest_client
+from tempest import exceptions
import json
-import storm.config
+import tempest.config
import time
@@ -10,6 +11,7 @@
self.config = config
self.client = rest_client.RestClient(config, username, key,
auth_url, tenant_name)
+
self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout
self.headers = {'Content-Type': 'application/json',
diff --git a/tempest/services/nova/json/limits_client.py b/tempest/services/nova/json/limits_client.py
new file mode 100644
index 0000000..883bdf2
--- /dev/null
+++ b/tempest/services/nova/json/limits_client.py
@@ -0,0 +1,26 @@
+import json
+from tempest.common import rest_client
+
+
+class LimitsClient(object):
+
+ def __init__(self, username, key, auth_url, tenant_name=None):
+ self.client = rest_client.RestClient(config, username, key,
+ auth_url, tenant_name)
+
+ def get_limits(self):
+ resp, body = self.client.get("limits")
+ body = json.loads(body)
+ return resp, body['limits']
+
+ def get_max_server_meta(self):
+ resp, limits_dict = self.get_limits()
+ return resp, limits_dict['absolute']['maxServerMeta']
+
+ def get_personality_file_limit(self):
+ resp, limits_dict = self.get_limits()
+ return resp, limits_dict['absolute']['maxPersonality']
+
+ def get_personality_size_limit(self):
+ resp, limits_dict = self.get_limits()
+ return resp, limits_dict['absolute']['maxPersonalitySize']
diff --git a/storm/services/nova/json/servers_client.py b/tempest/services/nova/json/servers_client.py
similarity index 98%
rename from storm/services/nova/json/servers_client.py
rename to tempest/services/nova/json/servers_client.py
index b587ee0..502da72 100644
--- a/storm/services/nova/json/servers_client.py
+++ b/tempest/services/nova/json/servers_client.py
@@ -1,7 +1,7 @@
-from storm import exceptions
-from storm.common import rest_client
+from tempest import exceptions
+from tempest.common import rest_client
import json
-import storm.config
+import tempest.config
import time
@@ -11,6 +11,7 @@
self.config = config
self.client = rest_client.RestClient(config, username, key,
auth_url, tenant_name)
+
self.build_interval = self.config.nova.build_interval
self.build_timeout = self.config.nova.build_timeout
self.headers = {'Content-Type': 'application/json',
diff --git a/storm/services/nova/xml/__init__.py b/tempest/services/nova/xml/__init__.py
similarity index 100%
rename from storm/services/nova/xml/__init__.py
rename to tempest/services/nova/xml/__init__.py
diff --git a/storm/tests/__init__.py b/tempest/tests/__init__.py
similarity index 100%
rename from storm/tests/__init__.py
rename to tempest/tests/__init__.py
diff --git a/storm/tests/test_flavors.py b/tempest/tests/test_flavors.py
similarity index 96%
rename from storm/tests/test_flavors.py
rename to tempest/tests/test_flavors.py
index 5153693..b506795 100644
--- a/storm/tests/test_flavors.py
+++ b/tempest/tests/test_flavors.py
@@ -1,6 +1,6 @@
from nose.plugins.attrib import attr
-from storm import openstack
-import storm.config
+from tempest import openstack
+import tempest.config
import unittest2 as unittest
diff --git a/tempest/tests/test_image_metadata.py b/tempest/tests/test_image_metadata.py
new file mode 100644
index 0000000..7a15b32
--- /dev/null
+++ b/tempest/tests/test_image_metadata.py
@@ -0,0 +1,107 @@
+from nose.plugins.attrib import attr
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+import tempest.config
+import unittest2 as unittest
+
+
+class ImagesMetadataTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.os = openstack.Manager()
+ cls.servers_client = cls.os.servers_client
+ cls.client = cls.os.images_client
+ cls.config = cls.os.config
+ cls.image_ref = cls.config.env.image_ref
+ cls.flavor_ref = cls.config.env.flavor_ref
+ cls.ssh_timeout = cls.config.nova.ssh_timeout
+
+ name = rand_name('server')
+ resp, cls.server = cls.servers_client.create_server(name,
+ cls.image_ref,
+ cls.flavor_ref)
+ #Wait for the server to become active
+ cls.servers_client.wait_for_server_status(cls.server['id'], 'ACTIVE')
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.servers_client.delete_server(cls.server['id'])
+
+ def setUp(self):
+ meta = {'key1': 'value1', 'key2': 'value2'}
+ name = rand_name('image')
+ resp, body = self.client.create_image(self.server['id'], name, meta)
+ image_ref = resp['location']
+ temp = image_ref.rsplit('/')
+ image_id = temp[6]
+
+ self.client.wait_for_image_resp_code(image_id, 200)
+ self.client.wait_for_image_status(image_id, 'ACTIVE')
+ resp, self.image = self.client.get_image(image_id)
+
+ def tearDown(self):
+ self.client.delete_image(self.image['id'])
+
+ def _parse_image_id(self, image_ref):
+ temp = image_ref.rsplit('/')
+ return len(temp) - 1
+
+ def test_list_image_metadata(self):
+ """All metadata key/value pairs for an image should be returned"""
+ resp, metadata = self.client.list_image_metadata(self.image['id'])
+ self.assertEqual('value1', metadata['key1'])
+ self.assertEqual('value2', metadata['key2'])
+
+ def test_set_image_metadata(self):
+ """The metadata for the image should match the new values"""
+ meta = {'meta1': 'data1'}
+ name = rand_name('image')
+ resp, body = self.client.create_image(self.server['id'], name, meta)
+ image_id = self._parse_image_id(resp['location'])
+ self.client.wait_for_image_resp_code(image_id, 200)
+ self.client.wait_for_image_status(image_id, 'ACTIVE')
+ resp, image = self.client.get_image(image_id)
+
+ meta = {'meta2': 'data2', 'meta3': 'data3'}
+ resp, body = self.client.set_image_metadata(image['id'], meta)
+
+ resp, metadata = self.client.list_image_metadata(image['id'])
+ self.assertEqual('data2', metadata['meta2'])
+ self.assertEqual('data3', metadata['meta3'])
+ self.assertTrue('key1' not in metadata)
+
+ self.servers_client.delete_server(server['id'])
+ self.client.delete_image(image['id'])
+
+ def test_update_image_metadata(self):
+ """The metadata for the image should match the updated values"""
+ meta = {'key1': 'alt1', 'key2': 'alt2'}
+ resp, metadata = self.client.update_image_metadata(self.image['id'], meta)
+
+ resp, metadata = self.client.list_image_metadata(self.image['id'])
+ self.assertEqual('alt1', metadata['key1'])
+ self.assertEqual('alt2', metadata['key2'])
+
+ def test_get_image_metadata_item(self):
+ """The value for a specic metadata key should be returned"""
+ resp, meta = self.client.get_image_metadata_item(self.image['id'],
+ 'key2')
+ self.assertTrue('value2', meta['key2'])
+
+ def test_set_image_metadata_item(self):
+ """
+ The value provided for the given meta item should be set for the image
+ """
+ meta = {'key1': 'alt'}
+ resp, body = self.client.set_image_metadata_item(self.image['id'],
+ 'key1', meta)
+ resp, metadata = self.client.list_image_metadata(self.image['id'])
+ self.assertEqual('alt', metadata['key1'])
+
+ def test_delete_image_metadata_item(self):
+ """The metadata value/key pair should be deleted from the image"""
+ resp, body = self.client.delete_image_metadata_item(self.image['id'],
+ 'key1')
+ resp, metadata = self.client.list_image_metadata(self.image['id'])
+ self.assertTrue('key1' not in metadata)
diff --git a/storm/tests/test_images.py b/tempest/tests/test_images.py
similarity index 65%
rename from storm/tests/test_images.py
rename to tempest/tests/test_images.py
index e1349b7..7f4c451 100644
--- a/storm/tests/test_images.py
+++ b/tempest/tests/test_images.py
@@ -1,8 +1,8 @@
from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
import unittest2 as unittest
-import storm.config
+import tempest.config
# Some module-level skip conditions
create_image_enabled = False
@@ -24,8 +24,9 @@
temp = image_ref.rsplit('/')
return temp[6]
- @unittest.skipIf(not create_image_enabled,
+ @unittest.skipIf(not imaging_enabled,
'Environment unable to create images.')
+ @attr(type='smoke')
def test_create_delete_image(self):
"""An image for the provided server should be created"""
server_name = rand_name('server')
@@ -36,7 +37,8 @@
#Create a new image
name = rand_name('image')
- resp, body = self.client.create_image(server['id'], name)
+ meta = {'image_type': 'test'}
+ resp, body = self.client.create_image(server['id'], name, meta)
image_id = self._parse_image_id(resp['location'])
self.client.wait_for_image_resp_code(image_id, 200)
self.client.wait_for_image_status(image_id, 'ACTIVE')
@@ -44,27 +46,13 @@
#Verify the image was created correctly
resp, image = self.client.get_image(image_id)
self.assertEqual(name, image['name'])
+ self.assertEqual('test', image['metadata']['image_type'])
+
+ #Verify minRAM and minDisk values are the same as the original image
+ resp, original_image = self.client.get_image(self.image_ref)
+ self.assertEqual(original_image['minRam'], image['minRam'])
+ self.assertEqual(original_image['minDisk'], image['minDisk'])
#Teardown
self.client.delete_image(image['id'])
self.servers_client.delete_server(server['id'])
-
- @attr(type='smoke')
- def test_get_image(self):
- """Returns the correct details for a single image"""
- resp, image = self.client.get_image(self.image_ref)
- self.assertEqual(self.image_ref, image['id'])
-
- @attr(type='smoke')
- def test_list_images(self):
- """The list of all images should contain the image flavor"""
- resp, images = self.client.list_images()
- found = any([i for i in images if i['id'] == self.image_ref])
- self.assertTrue(found)
-
- @attr(type='smoke')
- def test_list_images_with_detail(self):
- """Detailed list of all images should contain the expected image"""
- resp, images = self.client.list_images_with_detail()
- found = any([i for i in images if i['id'] == self.image_ref])
- self.assertTrue(found)
diff --git a/tempest/tests/test_list_images.py b/tempest/tests/test_list_images.py
new file mode 100644
index 0000000..a4cdac0
--- /dev/null
+++ b/tempest/tests/test_list_images.py
@@ -0,0 +1,37 @@
+from nose.plugins.attrib import attr
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+import unittest2 as unittest
+import tempest.config
+
+
+class ListImagesTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.os = openstack.Manager()
+ cls.client = cls.os.images_client
+ cls.servers_client = cls.os.servers_client
+ cls.config = cls.os.config
+ cls.image_ref = cls.config.env.image_ref
+ cls.flavor_ref = cls.config.env.flavor_ref
+
+ @attr(type='smoke')
+ def test_get_image(self):
+ """Returns the correct details for a single image"""
+ resp, image = self.client.get_image(self.image_ref)
+ self.assertEqual(self.image_ref, image['id'])
+
+ @attr(type='smoke')
+ def test_list_images(self):
+ """The list of all images should contain the image"""
+ resp, images = self.client.list_images()
+ found = any([i for i in images if i['id'] == self.image_ref])
+ self.assertTrue(found)
+
+ @attr(type='smoke')
+ def test_list_images_with_detail(self):
+ """Detailed list of all images should contain the expected image"""
+ resp, images = self.client.list_images_with_detail()
+ found = any([i for i in images if i['id'] == self.image_ref])
+ self.assertTrue(found)
diff --git a/storm/tests/test_server_details.py b/tempest/tests/test_list_servers.py
similarity index 96%
rename from storm/tests/test_server_details.py
rename to tempest/tests/test_list_servers.py
index b042ea2..76bf7aa 100644
--- a/storm/tests/test_server_details.py
+++ b/tempest/tests/test_list_servers.py
@@ -1,8 +1,8 @@
from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
import unittest2 as unittest
-import storm.config
+import tempest.config
class ServerDetailsTest(unittest.TestCase):
diff --git a/tempest/tests/test_server_actions.py b/tempest/tests/test_server_actions.py
new file mode 100644
index 0000000..3ae9dd8
--- /dev/null
+++ b/tempest/tests/test_server_actions.py
@@ -0,0 +1,113 @@
+from nose.plugins.attrib import attr
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+import unittest2 as unittest
+import tempest.config
+import base64
+
+
+class ServerActionsTest(unittest.TestCase):
+ resize_available = tempest.config.TempestConfig().env.resize_available
+
+ @classmethod
+ def setUpClass(cls):
+ cls.os = openstack.Manager()
+ cls.client = cls.os.servers_client
+ cls.config = cls.os.config
+ cls.image_ref = cls.config.env.image_ref
+ cls.image_ref_alt = cls.config.env.image_ref_alt
+ cls.flavor_ref = cls.config.env.flavor_ref
+ cls.flavor_ref_alt = cls.config.env.flavor_ref_alt
+
+ def setUp(self):
+ self.name = rand_name('server')
+ resp, self.server = self.client.create_server(self.name,
+ self.image_ref,
+ self.flavor_ref)
+ self.client.wait_for_server_status(self.server['id'], 'ACTIVE')
+
+ def tearDown(self):
+ self.client.delete_server(self.id)
+
+ @attr(type='smoke')
+ def test_change_server_password(self):
+ """The server's password should be set to the provided password"""
+ resp, body = self.client.change_password(self.server['id'], 'newpass')
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(self.server['id'], 'ACTIVE')
+
+ @attr(type='smoke')
+ def test_reboot_server_hard(self):
+ """ The server should be power cycled """
+ resp, body = self.client.reboot(self.server['id'], 'HARD')
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(self.server['id'], 'ACTIVE')
+
+ @attr(type='smoke')
+ def test_reboot_server_soft(self):
+ """The server should be signaled to reboot gracefully"""
+ resp, body = self.client.reboot(self.server['id'], 'SOFT')
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(self.server['id'], 'ACTIVE')
+
+ @attr(type='smoke')
+ def test_rebuild_server(self):
+ """ The server should be rebuilt using the provided image and data """
+ meta = {'rebuild': 'server'}
+ name = rand_name('server')
+ file_contents = 'Test server rebuild.'
+ personality = [{'path': '/etc/rebuild.txt',
+ 'contents': base64.b64encode(file_contents)}]
+
+ resp, rebuilt_server = self.client.rebuild(self.server['id'],
+ self.image_ref_alt,
+ name=name, meta=meta,
+ personality=personality,
+ adminPass='rebuild')
+
+ #Verify the properties in the initial response are correct
+ self.assertEqual(self.server['id'], rebuilt_server['id'])
+ self.assertEqual(self.image_ref_alt, rebuilt_server['image']['id'])
+ self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+
+ #Verify the server properties after the rebuild completes
+ self.client.wait_for_server_status(rebuilt_server['id'], 'ACTIVE')
+ resp, server = self.client.get_server(rebuilt_server['id'])
+ self.assertEqual(self.image_ref_alt, rebuilt_server['image']['id'])
+ self.assertEqual('rebuiltserver', rebuilt_server['name'])
+
+ @attr(type='smoke')
+ @unittest.skipIf(not resize_available, 'Resize not available.')
+ def test_resize_server_confirm(self):
+ """
+ The server's RAM and disk space should be modified to that of
+ the provided flavor
+ """
+
+ resp, server = self.client.resize(self.id, self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(self.id, 'VERIFY_RESIZE')
+
+ self.client.confirm_resize(self.id)
+ self.client.wait_for_server_status(self.id, 'ACTIVE')
+
+ resp, server = self.client.get_server(self.id)
+ self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
+
+ @attr(type='smoke')
+ @unittest.skipIf(not resize_available, 'Resize not available.')
+ def test_resize_server_revert(self):
+ """
+ The server's RAM and disk space should return to its original
+ values after a resize is reverted
+ """
+
+ resp, server = self.client.resize(self.id, self.flavor_ref_alt)
+ self.assertEqual(202, resp.status)
+ self.client.wait_for_server_status(id, 'VERIFY_RESIZE')
+
+ self.client.revert_resize(self.id)
+ self.client.wait_for_server_status(id, 'ACTIVE')
+
+ resp, server = self.client.get_server(id)
+ self.assertEqual(self.flavor_ref, server['flavor']['id'])
diff --git a/storm/tests/test_server_metadata.py b/tempest/tests/test_server_metadata.py
similarity index 97%
rename from storm/tests/test_server_metadata.py
rename to tempest/tests/test_server_metadata.py
index 397599a..5ec826b 100644
--- a/storm/tests/test_server_metadata.py
+++ b/tempest/tests/test_server_metadata.py
@@ -1,8 +1,8 @@
from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
import unittest2 as unittest
-import storm.config
+import tempest.config
class ServerMetadataTest(unittest.TestCase):
diff --git a/tempest/tests/test_server_personality.py b/tempest/tests/test_server_personality.py
new file mode 100644
index 0000000..ebf5e8f
--- /dev/null
+++ b/tempest/tests/test_server_personality.py
@@ -0,0 +1,67 @@
+from nose.plugins.attrib import attr
+from tempest import openstack
+from tempest import exceptions
+from tempest.common.utils.data_utils import rand_name
+import base64
+import tempest.config
+import unittest2 as unittest
+
+
+class ServerPersonalityTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.os = openstack.Manager()
+ cls.client = cls.os.servers_client
+ cls.config = cls.config = cls.os.config
+ cls.image_ref = cls.config.env.image_ref
+ cls.flavor_ref = cls.config.env.flavor_ref
+ cls.user_client = cls.os.limits_client
+
+ def test_personality_files_exceed_limit(self):
+ """
+ Server creation should fail if greater than the maximum allowed
+ number of files are injected into the server.
+ """
+ name = rand_name('server')
+ file_contents = 'This is a test file.'
+ personality = []
+ resp, max_file_limit = self.user_client.get_personality_file_limit()
+ for i in range(0, max_file_limit + 1):
+ path = 'etc/test' + str(i) + '.txt'
+ personality.append({'path': path,
+ 'contents': base64.b64encode(file_contents)})
+ try:
+ resp, resp_body = self.client.create_server(name, self.image_ref,
+ self.flavor_ref,
+ personality=personality)
+ except exceptions.OverLimit:
+ pass
+ else:
+ self.fail('This request did not fail as expected')
+
+ @attr(type='positive')
+ def test_can_create_server_with_max_number_personality_files(self):
+ """
+ Server should be created successfully if maximum allowed number of
+ files is injected into the server during creation.
+ """
+ name = rand_name('server')
+ file_contents = 'This is a test file.'
+
+ resp, max_file_limit = self.user_client.get_personality_file_limit()
+ self.assertEqual(200, resp.status)
+
+ personality = []
+ for i in range(0, max_file_limit):
+ path = 'etc/test' + str(i) + '.txt'
+ personality.append({'path': path,
+ 'contents': base64.b64encode(file_contents)})
+
+ resp, server = self.client.create_server(name, self.image_ref,
+ self.flavor_ref,
+ personality=personality)
+ self.assertEqual('202', resp['status'])
+
+ #Teardown
+ self.client.delete_server(server['id'])
diff --git a/storm/tests/test_servers.py b/tempest/tests/test_servers.py
similarity index 82%
rename from storm/tests/test_servers.py
rename to tempest/tests/test_servers.py
index fead6aa..8e332ed 100644
--- a/storm/tests/test_servers.py
+++ b/tempest/tests/test_servers.py
@@ -1,9 +1,9 @@
-from storm.common import ssh
+from tempest.common import ssh
from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
import base64
-import storm.config
+import tempest.config
import unittest2 as unittest
@@ -16,7 +16,6 @@
cls.config = cls.os.config
cls.image_ref = cls.config.env.image_ref
cls.flavor_ref = cls.config.env.flavor_ref
- cls.ssh_timeout = cls.config.nova.ssh_timeout
@attr(type='smoke')
def test_create_delete_server(self):
@@ -34,6 +33,10 @@
accessIPv4=accessIPv4,
accessIPv6=accessIPv6,
personality=personality)
+ #Check the initial response
+ self.assertEqual(202, resp.status)
+ self.assertTrue(server['id'] is not None)
+ self.assertTrue(server['adminPass'] is not None)
#Wait for the server to become active
self.client.wait_for_server_status(server['id'], 'ACTIVE')
@@ -46,8 +49,9 @@
self.assertEqual(self.image_ref, server['image']['id'])
self.assertEqual(str(self.flavor_ref), server['flavor']['id'])
- #Teardown
- self.client.delete_server(self.id)
+ #Delete the server
+ resp, body = self.client.delete_server(server['id'])
+ self.assertEqual(204, resp.status)
@attr(type='smoke')
def test_create_server_with_admin_password(self):
@@ -64,14 +68,6 @@
#Verify the password is set correctly in the response
self.assertEqual('testpassword', server['adminPass'])
- #SSH into the server using the set password
- self.client.wait_for_server_status(server['id'], 'ACTIVE')
- resp, addresses = self.client.list_addresses(server['id'])
- ip = addresses['public'][0]['addr']
-
- client = ssh.Client(ip, 'root', 'testpassword', self.ssh_timeout)
- self.assertTrue(client.test_connection_auth())
-
#Teardown
self.client.delete_server(server['id'])
@@ -84,7 +80,8 @@
self.client.wait_for_server_status(server['id'], 'ACTIVE')
#Update the server with a new name
- self.client.update_server(server['id'], name='newname')
+ resp, server = self.client.update_server(server['id'], name='newname')
+ self.assertEquals(200, resp.status)
self.client.wait_for_server_status(server['id'], 'ACTIVE')
#Verify the name of the server has changed
@@ -105,8 +102,10 @@
self.client.wait_for_server_status(server['id'], 'ACTIVE')
#Update the IPv4 and IPv6 access addresses
- self.client.update_server(server['id'], accessIPv4='1.1.1.1',
- accessIPv6='::babe:2.2.2.2')
+ resp, body = self.client.update_server(server['id'],
+ accessIPv4='1.1.1.1',
+ accessIPv6='::babe:2.2.2.2')
+ self.assertEqual(200, resp.status)
self.client.wait_for_server_status(server['id'], 'ACTIVE')
#Verify the access addresses have been updated
diff --git a/storm/tests/test_servers_negative.py b/tempest/tests/test_servers_negative.py
similarity index 95%
rename from storm/tests/test_servers_negative.py
rename to tempest/tests/test_servers_negative.py
index 068ca5d..3355514 100644
--- a/storm/tests/test_servers_negative.py
+++ b/tempest/tests/test_servers_negative.py
@@ -1,11 +1,11 @@
import unittest2 as unittest
-import storm.config
+import tempest.config
import base64
from nose.plugins.attrib import attr
-from storm import openstack
-from storm.common.utils.data_utils import rand_name
-from storm.common import ssh
-from storm import exceptions
+from tempest import openstack
+from tempest.common.utils.data_utils import rand_name
+from tempest.common import ssh
+from tempest import exceptions
class ServersNegativeTest(unittest.TestCase):