# -*- coding: utf-8 -*-
from lxml.html import document_fromstring
import os
from time import sleep
from widgetastic.widget import View, Text, TextInput, Checkbox, ParametrizedView
from widgetastic_patternfly import (
Dropdown, BootstrapSelect, Tab, FlashMessages, Input, CheckableBootstrapTreeview)
from widgetastic_manageiq import BreadCrumb, PaginationPane
from cfme.base.login import BaseLoggedInPage
from cfme.exceptions import TemplateNotFound
from widgetastic_manageiq import (
Calendar, SummaryTable, Button, ItemsToolBarViewSelector, Table, MultiBoxSelect, RadioGroup,
CheckableManageIQTree, VersionPick, Version, BaseEntitiesView, NonJSBaseEntity, BaseListEntity,
BaseQuadIconEntity, BaseTileIconEntity, JSBaseEntity, BaseNonInteractiveEntitiesView)
[docs]class InstanceQuadIconEntity(BaseQuadIconEntity):
""" Provider child of Quad Icon entity
"""
@property
def data(self):
br = self.browser
try:
if br.product_version > '5.8':
state = br.get_attribute('style', self.QUADRANT.format(pos='b'))
state = state.split('"')[1]
else:
state = br.get_attribute('src', self.QUADRANT.format(pos='b'))
state = os.path.split(state)[1]
state = os.path.splitext(state)[0]
except IndexError:
state = ''
if br.is_displayed(self.QUADRANT.format(pos='g')):
policy = br.get_attribute('src', self.QUADRANT.format(pos='g'))
else:
policy = None
return {
"os": br.get_attribute('src', self.QUADRANT.format(pos='a')),
"state": state,
"vendor": br.get_attribute('src', self.QUADRANT.format(pos='c')),
"no_snapshot": br.text(self.QUADRANT.format(pos='d')),
"policy": policy,
}
[docs]class InstanceTileIconEntity(BaseTileIconEntity):
""" Provider child of Tile Icon entity
"""
quad_icon = ParametrizedView.nested(InstanceQuadIconEntity)
[docs]class InstanceListEntity(BaseListEntity):
""" Provider child of List entity
"""
pass
[docs]class NonJSInstanceEntity(NonJSBaseEntity):
""" Provider child of Proxy entity
"""
quad_entity = InstanceQuadIconEntity
list_entity = InstanceListEntity
tile_entity = InstanceTileIconEntity
[docs]class JSInstanceEntity(JSBaseEntity):
@property
def data(self):
data_dict = super(JSInstanceEntity, self).data
if 'quadicon' in data_dict and data_dict['quadicon']:
quad_data = document_fromstring(data_dict['quadicon'])
data_dict['os'] = quad_data.xpath(self.QUADRANT.format(pos="a"))[0].get('src')
data_dict['vendor'] = quad_data.xpath(self.QUADRANT.format(pos="c"))[0].get('src')
data_dict['no_snapshot'] = quad_data.xpath(self.QUADRANT.format(pos="d"))[0].text
try:
state = quad_data.xpath(self.QUADRANT.format(pos="b"))[0].get('style')
try:
state = state.split('"')[1]
except IndexError:
state = state.split("'")[1]
state = os.path.split(state)[1]
state = os.path.splitext(state)[0]
except IndexError:
state = ''
data_dict['state'] = state
try:
policy = quad_data.xpath(self.QUADRANT.format(pos="g"))[0].get('src')
except:
policy = None
data_dict['policy'] = policy
return data_dict
[docs]def InstanceEntity(): # noqa
""" Temporary wrapper for Instance Entity during transition to JS based Entity
"""
return VersionPick({
Version.lowest(): NonJSInstanceEntity,
'5.9': JSInstanceEntity,
})
[docs]class SelectTable(Table):
"""Wigdet for non-editable table. used for selecting value"""
[docs] def fill(self, values):
"""Clicks on item - fill by selecting required value"""
value = values.get('name', '<None>')
changed = False
if value != self.currently_selected:
changed = True
self.row(name=value).click()
return changed
@property
def currently_selected(self):
"""Return Name of the selected row"""
selected = self.browser.elements(
".//tr[@class='selected']/td[1]",
parent=self)
result = map(self.browser.text, selected)
if len(result) == 0:
self.logger.info('Nothing is currently selected')
return None
else:
return result[0]
[docs] def read(self):
return self.currently_selected
[docs] def read_content(self):
"""This is a default Table.read() method for those who will need table content"""
return super(SelectTable, self).read()
[docs]class VMEntities(BaseEntitiesView):
"""
Entities view for vms/instances collection destinations
"""
@property
def entity_class(self):
return InstanceEntity().pick(self.browser.product_version)
paginator = PaginationPane()
adv_search_clear = Text('//div[@id="main-content"]//h1//span[@id="clear_search"]/a')
[docs]class VMDetailsEntities(View):
"""
Details entities view for vms/instances details destinations
VM's have 3-4 more tables, should inherit and add them there.
"""
title = Text('//div[@id="main-content"]//h1//span[@id="explorer_title_text"]')
flash = FlashMessages('.//div[@id="flash_msg_div"]'
'/div[@id="flash_text_div" or contains(@class, "flash_text_div")]')
properties = SummaryTable(title='Properties')
lifecycle = SummaryTable(title='Lifecycle')
relationships = SummaryTable(title='Relationships')
vmsafe = SummaryTable(title='VMsafe')
attributes = SummaryTable(title='Custom Attributes') # Only displayed when assigned
compliance = SummaryTable(title='Compliance')
power_management = SummaryTable(title='Power Management')
security = SummaryTable(title='Security')
configuration = SummaryTable(title='Configuration')
diagnostics = SummaryTable(title='Diagnostics')
smart_management = SummaryTable(title='Smart Management')
[docs]class ProvisionView(BaseLoggedInPage):
"""
The provisioning view, with nested ProvisioningForm as `form` attribute.
Handles template selection before Provisioning form with `before_fill` method
"""
title = Text('#explorer_title_text')
breadcrumb = BreadCrumb()
@View.nested
class form(BasicProvisionFormView): # noqa
"""First page of provision form is image selection
Second page of form is tabbed with nested views
"""
image_table = Table('//div[@id="pre_prov_div"]//table')
continue_button = Button('Continue') # Continue button on 1st page, image selection
submit_button = Button('Submit') # Submit for 2nd page, tabular form
cancel_button = Button('Cancel')
def before_fill(self, values):
# Provision from image is a two part form,
# this completes the image selection before the tabular parent form is filled
template_name = values.get('template_name',
self.parent_view.context['object'].template_name)
provider_name = self.parent_view.context['object'].provider.name
try:
row = self.image_table.row(name=template_name,
provider=provider_name)
except IndexError:
raise TemplateNotFound('Cannot find template "{}" for provider "{}"'
.format(template_name, provider_name))
row.click()
self.continue_button.click()
# TODO timing, wait_displayed is timing out and can't get it to stop in is_displayed
sleep(3)
self.flush_widget_cache()
@property
def is_displayed(self):
return False
[docs]class RetirementView(BaseLoggedInPage):
"""
Set Retirement date view for vms/instances
The title actually as Instance|VM.VM_TYPE string in it, otherwise the same
"""
title = Text('#explorer_title_text')
@View.nested
class form(View): # noqa
"""The form portion of the view"""
retirement_date = Calendar(name='retirementDate')
# TODO This is just an anchor with an image, weaksauce
# remove_date = Button()
retirement_warning = BootstrapSelect(id='retirementWarning')
entities = View.nested(BaseNonInteractiveEntitiesView)
save_button = Button('Save')
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# TODO match quadicon and title
return False
[docs]class EditView(BaseLoggedInPage):
"""
Edit vms/instance page
The title actually as Instance|VM.VM_TYPE string in it, otherwise the same
"""
title = Text('#explorer_title_text')
@View.nested
class form(View): # noqa
"""The form portion of the view"""
custom_identifier = TextInput(id='custom_1')
description = TextInput(id='description')
parent_vm = BootstrapSelect(id='chosen_parent')
# MultiBoxSelect element only has table ID in CFME 5.8+
# https://bugzilla.redhat.com/show_bug.cgi?id=1463265
child_vms = MultiBoxSelect(id='child-vm-select')
save_button = Button('Save')
reset_button = Button('Reset')
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# Only name is displayed
return False
[docs]class SetOwnershipView(BaseLoggedInPage):
"""
Set vms/instance ownership page
The title actually as Instance|VM.VM_TYPE string in it, otherwise the same
"""
@View.nested
class form(View): # noqa
user_name = BootstrapSelect('user_name')
group_name = BootstrapSelect('group_name')
entities = View.nested(BaseNonInteractiveEntitiesView)
save_button = Button('Save')
reset_button = Button('Reset')
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# TODO match quadicon using entities, no provider match through icon asset yet
return False
[docs]class ManagementEngineView(BaseLoggedInPage):
"""
Edit management engine relationship page
The title actually as Instance|VM.VM_TYPE string in it, otherwise the same
"""
@View.nested
class form(View): # noqa
server = BootstrapSelect('server_id')
save_button = Button('Save')
reset_button = Button('Reset')
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# Only the name is displayed
return False
[docs]class ManagePoliciesView(BaseLoggedInPage):
"""
Manage policies page
"""
@View.nested
class form(View): # noqa
policy_profiles = CheckableManageIQTree(tree_id='protectbox')
entities = View.nested(BaseNonInteractiveEntitiesView)
save_button = Button('Save')
reset_button = Button('Reset')
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# TODO match quadicon using entities, no provider match through icon asset yet
return False
[docs]class PolicySimulationView(BaseLoggedInPage):
"""
Policy Simulation page for vms/instances
"""
@View.nested
class form(View): # noqa
policy = BootstrapSelect('policy_id')
# TODO policies table, ability to remove
entities = View.nested(BaseNonInteractiveEntitiesView)
cancel_button = Button('Cancel')
@property
def is_displayed(self):
# TODO match quadicon
return False
[docs]class RightSizeView(BaseLoggedInPage):
"""
Right Size recommendations page for vms/instances
"""
# TODO new table widget for right-size tables
# They're H3 headers with the table as following-sibling
@property
def is_displayed(self):
# Only name is displayed
return False