diff --git a/openstack_dashboard/test/integration_tests/config.py b/openstack_dashboard/test/integration_tests/config.py index c4b0c287e3..c4acee32bb 100644 --- a/openstack_dashboard/test/integration_tests/config.py +++ b/openstack_dashboard/test/integration_tests/config.py @@ -103,6 +103,9 @@ InstancesGroup = [ cfg.StrOpt('image_name', default='cirros-0.3.4-x86_64-uec (24.0 MB)', help="Boot Source to be selected for launch Instances"), + cfg.StrOpt('flavor', + default='m1.tiny', + help="Flavor to be selected for launch Instances"), ] VolumeGroup = [ diff --git a/openstack_dashboard/test/integration_tests/horizon.conf b/openstack_dashboard/test/integration_tests/horizon.conf index fbfa378746..27073816d8 100644 --- a/openstack_dashboard/test/integration_tests/horizon.conf +++ b/openstack_dashboard/test/integration_tests/horizon.conf @@ -77,6 +77,8 @@ ssh_user=cirros available_zone=nova #image_name to launch instances image_name=cirros-0.3.4-x86_64-uec (24.0 MB) +#flavor to launch instances +flavor=m1.tiny [volume] volume_type=lvmdriver-1 diff --git a/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py b/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py index 0b79bec6a8..e7a4009629 100644 --- a/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py +++ b/openstack_dashboard/test/integration_tests/pages/project/compute/imagespage.py @@ -16,6 +16,11 @@ from openstack_dashboard.test.integration_tests.pages import basepage from openstack_dashboard.test.integration_tests.regions import forms from openstack_dashboard.test.integration_tests.regions import tables +from openstack_dashboard.test.integration_tests.pages.project.compute.\ + instancespage import InstancesPage +from openstack_dashboard.test.integration_tests.pages.project.compute.\ + volumes.volumespage import VolumesPage + class ImagesTable(tables.TableRegion): name = "images" @@ -27,6 +32,20 @@ class ImagesTable(tables.TableRegion): "minimum_ram", "is_public", "protected" ) + CREATE_VOLUME_FROM_IMAGE_FORM_FIELDS = ( + "name", "description", "image_source", + "type", "size", "availability_zone") + + LAUNCH_INSTANCE_FROM_FIELDS = (( + "availability_zone", "name", "flavor", + "count", "source_type", "instance_snapshot_id", + "volume_id", "volume_snapshot_id", "image_id", "volume_size", + "vol_delete_on_instance_delete"), + ("keypair", "groups"), + ("script_source", "script_upload", "script_data"), + ("disk_config", "config_drive") + ) + @tables.bind_table_action('create') def create_image(self, create_button): create_button.click() @@ -38,6 +57,20 @@ class ImagesTable(tables.TableRegion): delete_button.click() return forms.BaseFormRegion(self.driver, self.conf) + @tables.bind_row_action('create_volume_from_image') + def create_volume(self, create_volume, row): + create_volume.click() + return forms.FormRegion( + self.driver, self.conf, + field_mappings=self.CREATE_VOLUME_FROM_IMAGE_FORM_FIELDS) + + @tables.bind_row_action('launch_image', primary=True) + def launch_instance(self, launch_instance, row): + launch_instance.click() + return forms.TabbedFormRegion( + self.driver, self.conf, + field_mappings=self.LAUNCH_INSTANCE_FROM_FIELDS) + class ImagesPage(basepage.BaseNavigationPage): @@ -107,3 +140,34 @@ class ImagesPage(basepage.BaseNavigationPage): def wait_until_image_active(self, name): self._wait_until(lambda x: self.is_image_active(name)) + + def create_volume_from_image(self, name, volume_name=None, + description=None, + volume_size=None): + row = self._get_row_with_image_name(name) + create_volume_form = self.images_table.create_volume(row) + if volume_name is not None: + create_volume_form.name.text = volume_name + if description is not None: + create_volume_form.description.text = description + create_volume_form.image_source = name + create_volume_form.size.value = volume_size if volume_size \ + else self.conf.volume.volume_size + create_volume_form.availability_zone.value = \ + self.conf.launch_instances.available_zone + create_volume_form.submit() + return VolumesPage(self.driver, self.conf) + + def launch_instance_from_image(self, name, instance_name, + instance_count=1, flavor=None): + row = self._get_row_with_image_name(name) + launch_instance = self.images_table.launch_instance(row) + launch_instance.availability_zone.value = \ + self.conf.launch_instances.available_zone + launch_instance.name.text = instance_name + if flavor is None: + flavor = self.conf.launch_instances.flavor + launch_instance.flavor.text = flavor + launch_instance.count.value = instance_count + launch_instance.submit() + return InstancesPage(self.driver, self.conf) diff --git a/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py b/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py index 96eb3ec2ae..183549fd0c 100644 --- a/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py +++ b/openstack_dashboard/test/integration_tests/pages/project/compute/instancespage.py @@ -54,6 +54,7 @@ class InstancesPage(basepage.BaseNavigationPage): INSTANCES_TABLE_NAME_COLUMN = 'name' INSTANCES_TABLE_STATUS_COLUMN = 'status' + INSTANCES_TABLE_IMAGE_NAME_COLUMN = 'image_name' def __init__(self, driver, conf): super(InstancesPage, self).__init__(driver, conf) @@ -135,3 +136,7 @@ class InstancesPage(basepage.BaseNavigationPage): elif 'volume snapshot (creates a new volume)' in boot_source: return (instance.volume_snapshot_id, self.DEFAULT_VOLUME_SNAPSHOT_NAME) + + def get_image_name(self, instance_name): + row = self._get_row_with_instance_name(instance_name) + return row.cells[self.INSTANCES_TABLE_IMAGE_NAME_COLUMN].text diff --git a/openstack_dashboard/test/integration_tests/tests/test_images.py b/openstack_dashboard/test/integration_tests/tests/test_images.py index d73375aa0d..11735e8aa0 100644 --- a/openstack_dashboard/test/integration_tests/tests/test_images.py +++ b/openstack_dashboard/test/integration_tests/tests/test_images.py @@ -13,10 +13,10 @@ from openstack_dashboard.test.integration_tests import helpers from openstack_dashboard.test.integration_tests.regions import messages +IMAGE_NAME = helpers.gen_random_resource_name("image") -class TestImages(helpers.TestCase): - """Login as demo user""" - IMAGE_NAME = helpers.gen_random_resource_name("image") + +class TestImagesBasic(helpers.TestCase): @property def images_page(self): @@ -31,16 +31,16 @@ class TestImages(helpers.TestCase): """ images_page = self.images_page - images_page.create_image(self.IMAGE_NAME) + images_page.create_image(IMAGE_NAME) self.assertTrue(images_page.find_message_and_dismiss(messages.SUCCESS)) self.assertFalse(images_page.find_message_and_dismiss(messages.ERROR)) - self.assertTrue(images_page.is_image_present(self.IMAGE_NAME)) - self.assertTrue(images_page.is_image_active(self.IMAGE_NAME)) + self.assertTrue(images_page.is_image_present(IMAGE_NAME)) + self.assertTrue(images_page.is_image_active(IMAGE_NAME)) - images_page.delete_image(self.IMAGE_NAME) + images_page.delete_image(IMAGE_NAME) self.assertTrue(images_page.find_message_and_dismiss(messages.SUCCESS)) self.assertFalse(images_page.find_message_and_dismiss(messages.ERROR)) - self.assertFalse(images_page.is_image_present(self.IMAGE_NAME)) + self.assertFalse(images_page.is_image_present(IMAGE_NAME)) def test_images_pagination(self): """This test checks images pagination @@ -95,7 +95,72 @@ class TestImages(helpers.TestCase): settings_page.find_message_and_dismiss(messages.SUCCESS) -class TestImagesAdmin(helpers.AdminTestCase, TestImages): +class TestImagesAdvanced(helpers.TestCase): + """Login as demo user""" + + @property + def images_page(self): + return self.home_pg.go_to_compute_imagespage() + + def test_create_volume_from_image(self): + """This test case checks create volume from image functionality: + Steps: + 1. Login to Horizon Dashboard as regular user + 2. Navigate to Project -> Compute -> Images + 3. Create new volume from image + 4. Check that volume is created with expected name + 5. Check that volume status is Available + """ + images_page = self.images_page + source_image = self.CONFIG.image.images_list[0] + target_volume = "created_from_{0}".format(source_image) + + volumes_page = images_page.create_volume_from_image( + source_image, volume_name=target_volume) + self.assertTrue( + volumes_page.find_message_and_dismiss(messages.INFO)) + self.assertFalse( + volumes_page.find_message_and_dismiss(messages.ERROR)) + self.assertTrue(volumes_page.is_volume_present(target_volume)) + self.assertTrue(volumes_page.is_volume_status(target_volume, + 'Available')) + volumes_page.delete_volume(target_volume) + volumes_page.find_message_and_dismiss(messages.SUCCESS) + volumes_page.find_message_and_dismiss(messages.ERROR) + self.assertTrue(volumes_page.is_volume_deleted(target_volume)) + + def test_launch_instance_from_image(self): + """This test case checks launch instance from image functionality: + Steps: + 1. Login to Horizon Dashboard as regular user + 2. Navigate to Project -> Compute -> Images + 3. Launch new instance from image + 4. Check that instance is create + 5. Check that status of newly created instance is Active + 6. Check that image_name in correct in instances table + """ + images_page = self.images_page + source_image = self.CONFIG.image.images_list[0] + target_instance = "created_from_{0}".format(source_image) + instances_page = images_page.launch_instance_from_image( + source_image, target_instance) + self.assertTrue( + instances_page.find_message_and_dismiss(messages.SUCCESS)) + self.assertFalse( + instances_page.find_message_and_dismiss(messages.ERROR)) + self.assertTrue(instances_page.is_instance_active(target_instance)) + actual_image_name = instances_page.get_image_name(target_instance) + self.assertEqual(source_image, actual_image_name) + + instances_page.delete_instance(target_instance) + self.assertTrue( + instances_page.find_message_and_dismiss(messages.SUCCESS)) + self.assertFalse( + instances_page.find_message_and_dismiss(messages.ERROR)) + self.assertTrue(instances_page.is_instance_deleted(target_instance)) + + +class TestImagesAdmin(helpers.AdminTestCase, TestImagesBasic): """Login as admin user""" IMAGE_NAME = helpers.gen_random_resource_name("image")