horizon/openstack_dashboard/test/integration_tests/pages/project/volumes/volumespage.py

276 lines
11 KiB
Python

# 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 selenium.webdriver.common.by import By
from openstack_dashboard.test.integration_tests.pages import basepage
from openstack_dashboard.test.integration_tests.pages.project.compute \
import instancespage
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")
CREATE_VOLUME_SNAPSHOT_FORM_FIELDS = ("name", "description")
EXTEND_VOLUME_FORM_FIELDS = ("new_size",)
UPLOAD_VOLUME_FORM_FIELDS = ("image_name", "disk_format")
@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')
def edit_volume(self, edit_button, row):
edit_button.click()
return forms.FormRegion(self.driver, self.conf,
field_mappings=self.EDIT_VOLUME_FORM_FIELDS)
@tables.bind_row_action('snapshots')
def create_snapshot(self, create_snapshot_button, row):
create_snapshot_button.click()
return forms.FormRegion(
self.driver, self.conf,
field_mappings=self.CREATE_VOLUME_SNAPSHOT_FORM_FIELDS)
@tables.bind_row_action('extend')
def extend_volume(self, extend_button, row):
extend_button.click()
return forms.FormRegion(self.driver, self.conf,
field_mappings=self.EXTEND_VOLUME_FORM_FIELDS)
@tables.bind_row_action('launch_volume_ng')
def launch_as_instance(self, launch_button, row):
launch_button.click()
return instancespage.LaunchInstanceForm(self.driver, self.conf)
@tables.bind_row_action('upload_to_image')
def upload_volume_to_image(self, upload_button, row):
upload_button.click()
return forms.FormRegion(self.driver, self.conf,
field_mappings=self.UPLOAD_VOLUME_FORM_FIELDS)
@tables.bind_row_action('attachments')
def manage_attachments(self, manage_attachments, row):
manage_attachments.click()
return VolumeAttachForm(self.driver, self.conf)
class VolumesPage(basepage.BaseNavigationPage):
VOLUMES_TABLE_NAME_COLUMN = 'Name'
VOLUMES_TABLE_STATUS_COLUMN = 'Status'
VOLUMES_TABLE_TYPE_COLUMN = 'Type'
VOLUMES_TABLE_SIZE_COLUMN = 'Size'
VOLUMES_TABLE_ATTACHED_COLUMN = 'Attached To'
def __init__(self, driver, conf):
super().__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)
def _get_rows_with_volumes_names(self, names):
return [self.volumes_table.get_row(self.VOLUMES_TABLE_NAME_COLUMN, n)
for n in names]
@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()
self.wait_till_spinner_disappears()
def delete_volumes(self, volumes_names):
for volume_name in volumes_names:
self._get_row_with_volume_name(volume_name).mark()
confirm_delete_volumes_form = self.volumes_table.delete_volume()
confirm_delete_volumes_form.submit()
self.wait_till_spinner_disappears()
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):
def cell_getter():
row = self._get_row_with_volume_name(name)
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):
return self.volumes_table.is_row_deleted(
lambda: self._get_row_with_volume_name(name))
def are_volumes_deleted(self, volumes_names):
return self.volumes_table.are_rows_deleted(
lambda: self._get_rows_with_volumes_names(volumes_names))
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
def create_volume_snapshot(self, volume, snapshot, description='test'):
from openstack_dashboard.test.integration_tests.pages.project.\
volumes.snapshotspage import SnapshotsPage
row = self._get_row_with_volume_name(volume)
snapshot_form = self.volumes_table.create_snapshot(row)
snapshot_form.name.text = snapshot
if description is not None:
snapshot_form.description.text = description
snapshot_form.submit()
return SnapshotsPage(self.driver, self.conf)
def extend_volume(self, name, new_size):
row = self._get_row_with_volume_name(name)
extend_volume_form = self.volumes_table.extend_volume(row)
extend_volume_form.new_size.value = new_size
extend_volume_form.submit()
def upload_volume_to_image(self, name, image_name, disk_format):
row = self._get_row_with_volume_name(name)
upload_volume_form = self.volumes_table.upload_volume_to_image(row)
upload_volume_form.image_name.text = image_name
upload_volume_form.disk_format.value = disk_format
upload_volume_form.submit()
def get_size(self, name):
row = self._get_row_with_volume_name(name)
size = str(row.cells[self.VOLUMES_TABLE_SIZE_COLUMN].text)
return int(''.join(filter(str.isdigit, size)))
def launch_instance(self, name, instance_name, available_zone=None):
row = self._get_row_with_volume_name(name)
instance_form = self.volumes_table.launch_as_instance(row)
if available_zone is None:
available_zone = self.conf.launch_instances.available_zone
instance_form.availability_zone.value = available_zone
instance_form.name.text = instance_name
instance_form.submit()
def get_attach_instance(self, name):
row = self._get_row_with_volume_name(name)
attach_instance = row.cells[self.VOLUMES_TABLE_ATTACHED_COLUMN].text
return attach_instance
def attach_volume_to_instance(self, volume, instance):
row = self._get_row_with_volume_name(volume)
attach_form = self.volumes_table.manage_attachments(row)
attach_form.attach_instance(instance)
def is_volume_attached_to_instance(self, volume, instance):
row = self._get_row_with_volume_name(volume)
return row.cells[
self.VOLUMES_TABLE_ATTACHED_COLUMN].text.endswith(instance)
def detach_volume_from_instance(self, volume, instance):
row = self._get_row_with_volume_name(volume)
attachment_form = self.volumes_table.manage_attachments(row)
detach_form = attachment_form.detach(volume, instance)
detach_form.submit()
class VolumeAttachForm(forms.BaseFormRegion):
_attach_to_instance_selector = (By.CSS_SELECTOR, 'div > .themable-select')
_attachments_table_selector = (By.CSS_SELECTOR, 'table[id="attachments"]')
_detach_template = 'tr[data-display="Volume {0} on instance {1}"] button'
@property
def attachments_table(self):
return self._get_element(*self._attachments_table_selector)
@property
def instance_selector(self):
src_elem = self._get_element(*self._attach_to_instance_selector)
return forms.ThemableSelectFormFieldRegion(
self.driver, self.conf, src_elem=src_elem,
strict_options_match=False)
def detach(self, volume, instance):
detach_button = self.attachments_table.find_element(
By.CSS_SELECTOR, self._detach_template.format(volume, instance))
detach_button.click()
return forms.BaseFormRegion(self.driver, self.conf)
def attach_instance(self, instance_name):
self.instance_selector.text = instance_name
self.submit()