diff --git a/etc/STORM_README.txt b/etc/TEMPEST_README.txt similarity index 68% rename from etc/STORM_README.txt rename to etc/TEMPEST_README.txt index d44589688e..e46e195fac 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 c8dff27233..0000000000 --- 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 d7c9db40f4..0000000000 --- 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 91% rename from storm/common/rest_client.py rename to tempest/common/rest_client.py index 170e5230d6..94e44e4e36 100644 --- a/storm/common/rest_client.py +++ b/tempest/common/rest_client.py @@ -2,8 +2,8 @@ import json import httplib2 -from storm import exceptions -import storm.config +from tempest import exceptions +import tempest.config class RestClient(object): @@ -102,4 +102,12 @@ class RestClient(object): 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 99% rename from storm/config.py rename to tempest/config.py index 42b9894c49..2bbadc7117 100644 --- a/storm/config.py +++ b/tempest/config.py @@ -120,9 +120,10 @@ class EnvironmentConfig(object): 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 79% rename from storm/exceptions.py rename to tempest/exceptions.py index 9290cf7b78..b4d056d71d 100644 --- a/storm/exceptions.py +++ b/tempest/exceptions.py @@ -16,10 +16,18 @@ class BadRequest(Exception): 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 78f8c03219..15cfaf905c 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 @@ class Manager(object): 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 @@ class Manager(object): 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 97% rename from storm/services/nova/json/flavors_client.py rename to tempest/services/nova/json/flavors_client.py index d6526c8837..e3a030fcc9 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 98% rename from storm/services/nova/json/images_client.py rename to tempest/services/nova/json/images_client.py index 59e926988a..e5871cba9a 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 @@ class ImagesClient(object): 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 0000000000..883bdf2d8e --- /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 99% rename from storm/services/nova/json/servers_client.py rename to tempest/services/nova/json/servers_client.py index b587ee04e9..502da72fda 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 @@ class ServersClient(object): 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 515369384e..b506795e46 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 0000000000..7a15b32f56 --- /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 e1349b71d0..7f4c4517fa 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 @@ class ImagesTest(unittest.TestCase): 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 @@ class ImagesTest(unittest.TestCase): #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 @@ class ImagesTest(unittest.TestCase): #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 0000000000..a4cdac003c --- /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 97% rename from storm/tests/test_server_details.py rename to tempest/tests/test_list_servers.py index b042ea2302..76bf7aa1d2 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 0000000000..3ae9dd8913 --- /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 98% rename from storm/tests/test_server_metadata.py rename to tempest/tests/test_server_metadata.py index 397599aa33..5ec826b2b9 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 0000000000..ebf5e8fecd --- /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 fead6aa138..8e332ed2d9 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 @@ class ServersTest(unittest.TestCase): 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 @@ class ServersTest(unittest.TestCase): 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 @@ class ServersTest(unittest.TestCase): 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 @@ class ServersTest(unittest.TestCase): #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 @@ class ServersTest(unittest.TestCase): 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 @@ class ServersTest(unittest.TestCase): 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 068ca5dd3c..33555145da 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):