Added tests for check volumes management functionality
Tests check that create/edit/delete volumes actions are executed without errors under admin and non-admin user. Volumes page object was defined similar to other pages. 'volume' section is added to horizon.conf Implements blueprint: horizon-integration-tests-coverage Change-Id: Ib2c2bcb98bd010232fea404e565591cf6140383f
This commit is contained in:
parent
595d1ee6be
commit
abad2d3af4
@ -95,6 +95,10 @@ class BaseWebObject(unittest.TestCase):
|
||||
actually waiting for a _different_ element with a different text to
|
||||
appear in place of an old element. So a way to avoid capturing stale
|
||||
element reference should be provided for this use case.
|
||||
|
||||
Better to wrap getting entity status cell in a lambda
|
||||
to avoid problems with cell being replaced with totally different
|
||||
element by Javascript
|
||||
"""
|
||||
def predicate(_):
|
||||
elt = element() if hasattr(element, '__call__') else element
|
||||
|
@ -79,6 +79,15 @@ InstancesGroup = [
|
||||
help="Boot Source to be selected for launch Instances"),
|
||||
]
|
||||
|
||||
VolumeGroup = [
|
||||
cfg.StrOpt('volume_type',
|
||||
default='lvmdriver-1',
|
||||
help='Default volume type'),
|
||||
cfg.StrOpt('volume_size',
|
||||
default='1',
|
||||
help='Default volume size ')
|
||||
]
|
||||
|
||||
PluginGroup = [
|
||||
cfg.BoolOpt('is_plugin',
|
||||
default='False',
|
||||
@ -110,5 +119,6 @@ def get_config():
|
||||
cfg.CONF.register_opts(ScenarioGroup, group="scenario")
|
||||
cfg.CONF.register_opts(InstancesGroup, group="launch_instances")
|
||||
cfg.CONF.register_opts(PluginGroup, group="plugin")
|
||||
cfg.CONF.register_opts(VolumeGroup, group="volume")
|
||||
|
||||
return cfg.CONF
|
||||
|
@ -56,3 +56,7 @@ ssh_user=cirros
|
||||
available_zone=nova
|
||||
#image_name to launch instances
|
||||
image_name=cirros-0.3.4-x86_64-uec (24.0 MB)
|
||||
|
||||
[volume]
|
||||
volume_type=lvmdriver-1
|
||||
volume_size=1
|
||||
|
@ -0,0 +1,18 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack_dashboard.test.integration_tests.pages.project.compute.volumes\
|
||||
import volumespage
|
||||
|
||||
|
||||
class VolumesPage(volumespage.VolumesPage):
|
||||
pass
|
@ -96,9 +96,6 @@ class ImagesPage(basepage.BaseNavigationPage):
|
||||
def is_image_active(self, name):
|
||||
row = self._get_row_with_image_name(name)
|
||||
|
||||
# NOTE(tsufiev): better to wrap getting image status cell in a lambda
|
||||
# to avoid problems with cell being replaced with totally different
|
||||
# element by Javascript
|
||||
def cell_getter():
|
||||
return row.cells[self.IMAGES_TABLE_STATUS_COLUMN]
|
||||
try:
|
||||
|
@ -0,0 +1,137 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from selenium.common import exceptions
|
||||
|
||||
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
|
||||
|
||||
VOLUME_SOURCE_TYPE = 'Volume'
|
||||
IMAGE_SOURCE_TYPE = 'Image'
|
||||
|
||||
|
||||
class VolumesTable(tables.TableRegion):
|
||||
name = 'volumes'
|
||||
|
||||
# This form is applicable for volume creation from image only.
|
||||
# Volume creation from volume requires additional 'volume_source' field
|
||||
# which is available only in case at least one volume is already present.
|
||||
CREATE_VOLUME_FROM_IMAGE_FORM_FIELDS = (
|
||||
"name", "description", "volume_source_type", "image_source",
|
||||
"type", "size", "availability_zone")
|
||||
|
||||
EDIT_VOLUME_FORM_FIELDS = ("name", "description")
|
||||
|
||||
@tables.bind_table_action('create')
|
||||
def create_volume(self, create_button):
|
||||
create_button.click()
|
||||
return forms.FormRegion(
|
||||
self.driver, self.conf,
|
||||
field_mappings=self.CREATE_VOLUME_FROM_IMAGE_FORM_FIELDS)
|
||||
|
||||
@tables.bind_table_action('delete')
|
||||
def delete_volume(self, delete_button):
|
||||
delete_button.click()
|
||||
return forms.BaseFormRegion(self.driver, self.conf)
|
||||
|
||||
@tables.bind_row_action('edit', primary=True)
|
||||
def edit_volume(self, edit_button, row):
|
||||
edit_button.click()
|
||||
return forms.FormRegion(self.driver, self.conf,
|
||||
field_mappings=self.EDIT_VOLUME_FORM_FIELDS)
|
||||
|
||||
|
||||
class VolumesPage(basepage.BaseNavigationPage):
|
||||
|
||||
VOLUMES_TABLE_NAME_COLUMN = 'name'
|
||||
VOLUMES_TABLE_STATUS_COLUMN = 'status'
|
||||
|
||||
def __init__(self, driver, conf):
|
||||
super(VolumesPage, self).__init__(driver, conf)
|
||||
self._page_title = "Volumes"
|
||||
|
||||
def _get_row_with_volume_name(self, name):
|
||||
return self.volumes_table.get_row(
|
||||
self.VOLUMES_TABLE_NAME_COLUMN, name)
|
||||
|
||||
@property
|
||||
def volumes_table(self):
|
||||
return VolumesTable(self.driver, self.conf)
|
||||
|
||||
def create_volume(self, volume_name, description=None,
|
||||
volume_source_type=IMAGE_SOURCE_TYPE,
|
||||
volume_size=None,
|
||||
volume_source=None):
|
||||
volume_form = self.volumes_table.create_volume()
|
||||
volume_form.name.text = volume_name
|
||||
if description is not None:
|
||||
volume_form.description.text = description
|
||||
volume_form.volume_source_type.text = volume_source_type
|
||||
volume_source_type = self._get_source_name(volume_form,
|
||||
volume_source_type,
|
||||
self.conf.launch_instances,
|
||||
volume_source)
|
||||
volume_source_type[0].text = volume_source_type[1]
|
||||
if volume_size is None:
|
||||
volume_size = self.conf.volume.volume_size
|
||||
volume_form.size.value = volume_size
|
||||
if volume_source_type != "Volume":
|
||||
volume_form.type.value = self.conf.volume.volume_type
|
||||
volume_form.availability_zone.value = \
|
||||
self.conf.launch_instances.available_zone
|
||||
volume_form.submit()
|
||||
|
||||
def delete_volume(self, name):
|
||||
row = self._get_row_with_volume_name(name)
|
||||
row.mark()
|
||||
confirm_delete_volumes_form = self.volumes_table.delete_volume()
|
||||
confirm_delete_volumes_form.submit()
|
||||
|
||||
def edit_volume(self, name, new_name=None, description=None):
|
||||
row = self._get_row_with_volume_name(name)
|
||||
volume_edit_form = self.volumes_table.edit_volume(row)
|
||||
if new_name:
|
||||
volume_edit_form.name.text = new_name
|
||||
if description:
|
||||
volume_edit_form.description.text = description
|
||||
volume_edit_form.submit()
|
||||
|
||||
def is_volume_present(self, name):
|
||||
return bool(self._get_row_with_volume_name(name))
|
||||
|
||||
def is_volume_status(self, name, status):
|
||||
row = self._get_row_with_volume_name(name)
|
||||
|
||||
def cell_getter():
|
||||
return row.cells[self.VOLUMES_TABLE_STATUS_COLUMN]
|
||||
|
||||
try:
|
||||
self._wait_till_text_present_in_element(cell_getter, status)
|
||||
except exceptions.TimeoutException:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_volume_deleted(self, name):
|
||||
try:
|
||||
getter = lambda: self._get_row_with_volume_name(name)
|
||||
self.wait_till_element_disappears(getter)
|
||||
except exceptions.TimeoutException:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _get_source_name(self, volume_form, volume_source_type, conf,
|
||||
volume_source):
|
||||
if volume_source_type == IMAGE_SOURCE_TYPE:
|
||||
return volume_form.image_source, conf.image_name
|
||||
if volume_source_type == VOLUME_SOURCE_TYPE:
|
||||
return volume_form.volume_id, volume_source
|
115
openstack_dashboard/test/integration_tests/tests/test_volumes.py
Normal file
115
openstack_dashboard/test/integration_tests/tests/test_volumes.py
Normal file
@ -0,0 +1,115 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from openstack_dashboard.test.integration_tests import helpers
|
||||
from openstack_dashboard.test.integration_tests.regions import messages
|
||||
|
||||
|
||||
class TestVolumes(helpers.TestCase):
|
||||
VOLUME_NAME = helpers.gen_random_resource_name("volume")
|
||||
|
||||
def test_volume_create_edit_delete(self):
|
||||
"""This test case checks create, edit, delete volume functionality
|
||||
executed by non-admin user::
|
||||
Steps:
|
||||
1. Login to Horizon Dashboard as horizon user
|
||||
2. Navigate to Project -> Compute -> Volumes page
|
||||
3. Create new volume
|
||||
4. Check that the volume is in the list
|
||||
5. Check that no Error messages present
|
||||
6. Edit the volume
|
||||
7. Check that the volume is still in the list
|
||||
8. Check that no Error messages present
|
||||
9. Delete the volume
|
||||
10. Check that the volume is absent in the list
|
||||
11. Check that no Error messages present
|
||||
"""
|
||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||
|
||||
volumes_page.create_volume(self.VOLUME_NAME)
|
||||
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(self.VOLUME_NAME))
|
||||
self.assertTrue(volumes_page.is_volume_status(self.VOLUME_NAME,
|
||||
'Available'))
|
||||
|
||||
new_name = "edited_" + self.VOLUME_NAME
|
||||
volumes_page.edit_volume(self.VOLUME_NAME, new_name, "description")
|
||||
self.VOLUME_NAME = new_name
|
||||
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(self.VOLUME_NAME))
|
||||
self.assertTrue(volumes_page.is_volume_status(self.VOLUME_NAME,
|
||||
'Available'))
|
||||
|
||||
volumes_page.delete_volume(self.VOLUME_NAME)
|
||||
self.assertTrue(
|
||||
volumes_page.find_message_and_dismiss(messages.SUCCESS))
|
||||
self.assertFalse(
|
||||
volumes_page.find_message_and_dismiss(messages.ERROR))
|
||||
self.assertTrue(volumes_page.is_volume_deleted(self.VOLUME_NAME))
|
||||
|
||||
|
||||
class TestAdminVolumes(helpers.AdminTestCase):
|
||||
VOLUME_NAME = helpers.gen_random_resource_name("volume")
|
||||
|
||||
def test_volume_create_edit_delete_through_admin(self):
|
||||
"""This test case checks create, edit, delete volume functionality
|
||||
executed by admin user:
|
||||
Steps:
|
||||
1. Login to Horizon Dashboard as admin user
|
||||
2. Navigate to Project -> Compute -> Volumes page
|
||||
3. Create new volume
|
||||
4. Check that the volume is in the list
|
||||
5. Check that no Error messages present
|
||||
6. Edit the volume
|
||||
7. Check that the volume is still in the list
|
||||
8. Check that no Error messages present
|
||||
9. Go to Admin/System/Volumes page
|
||||
10. Delete the volume
|
||||
11. Check that the volume is absent in the list
|
||||
12. Check that no Error messages present
|
||||
"""
|
||||
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
|
||||
|
||||
volumes_page.create_volume(self.VOLUME_NAME)
|
||||
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(self.VOLUME_NAME))
|
||||
self.assertTrue(volumes_page.is_volume_status(self.VOLUME_NAME,
|
||||
'Available'))
|
||||
|
||||
new_name = "edited_" + self.VOLUME_NAME
|
||||
volumes_page.edit_volume(self.VOLUME_NAME, new_name, "description")
|
||||
self.VOLUME_NAME = new_name
|
||||
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(self.VOLUME_NAME))
|
||||
self.assertTrue(volumes_page.is_volume_status(self.VOLUME_NAME,
|
||||
'Available'))
|
||||
|
||||
volumes_admin_page = self.home_pg.go_to_system_volumes_volumespage()
|
||||
|
||||
volumes_admin_page.delete_volume(self.VOLUME_NAME)
|
||||
self.assertTrue(
|
||||
volumes_admin_page.find_message_and_dismiss(messages.SUCCESS))
|
||||
self.assertFalse(
|
||||
volumes_admin_page.find_message_and_dismiss(messages.ERROR))
|
||||
self.assertTrue(volumes_admin_page.is_volume_deleted(self.VOLUME_NAME))
|
Loading…
Reference in New Issue
Block a user