# -*- coding: utf-8 -*-
import attr
from cached_property import cached_property
from navmazing import NavigateToAttribute, NavigateToSibling
from widgetastic.widget import Text
from widgetastic_manageiq import Table
from widgetastic_patternfly import CandidateNotFound, Input, Button
from cfme.exceptions import ItemNotFound
from cfme.modeling.base import BaseCollection, BaseEntity
from cfme.utils.appliance.implementations.ui import navigator, CFMENavigateStep, navigate_to
from . import AutomateExplorerView, check_tree_path
from .domain import DomainDetailsView, Domain
[docs]class NamespaceDetailsView(AutomateExplorerView):
title = Text('#explorer_title_text')
namespaces = Table('#ns_details_grid')
@property
def is_displayed(self):
return (
self.in_explorer and
self.title.text == 'Automate Namespace "{}"'.format(self.context['object'].name) and
self.datastore.is_opened and
check_tree_path(
self.datastore.tree.currently_selected,
self.context['object'].tree_path))
[docs]class NamespaceAddView(NamespaceForm):
add_button = Button('Add')
@property
def is_displayed(self):
return (
self.in_explorer and
self.datastore.is_opened and
check_tree_path(
self.datastore.tree.currently_selected,
self.context['object'].tree_path) and
self.title.text == 'Adding a new Automate Namespace')
[docs]class NamespaceEditView(NamespaceForm):
save_button = Button('Save')
@property
def is_displayed(self):
return (
self.in_explorer and
self.datastore.is_opened and
check_tree_path(
self.datastore.tree.currently_selected,
self.context['object'].tree_path) and
self.title.text == 'Editing Automate Namespace "{}"'.format(self.obj.name))
[docs]class Namespace(BaseEntity):
def __init__(self, collection, name, description=None):
from .klass import ClassCollection
self._collections = {
'namespaces': NamespaceCollection,
'classes': ClassCollection
}
super(Namespace, self).__init__(collection)
self.name = name
if description is not None:
self.description = description
__repr__ = object.__repr__
@cached_property
def description(self):
return self.db_object.description
@cached_property
def db_id(self):
table = self.appliance.db.client['miq_ae_namespaces']
try:
return self.appliance.db.client.session.query(table.id).filter(
table.name == self.name,
table.parent_id == self.parent_obj.db_id)[0] # noqa
except IndexError:
raise ItemNotFound('Namespace named {} not found in the database'.format(self.name))
@property
def db_object(self):
table = self.appliance.db.client['miq_ae_namespaces']
return self.appliance.db.client.session.query(table).filter(table.id == self.db_id).first()
@property
def parent_obj(self):
return self.parent.parent
@property
def domain(self):
return self.parent_obj.domain
@property
def tree_path(self):
return self.parent_obj.tree_path + [self.name]
@cached_property
def namespaces(self):
return self.collections.namespaces
@cached_property
def classes(self):
return self.collections.classes
[docs] def delete(self, cancel=False):
# Ensure this has correct data
self.description
# Do it!
details_page = navigate_to(self, 'Details')
details_page.configuration.item_select('Remove this Namespace', handle_alert=not cancel)
if cancel:
assert details_page.is_displayed
details_page.flash.assert_no_error()
else:
if self.browser.product_version < '5.7':
# Domain list in 5.6 and lower
from .domain import DomainCollection, DomainListView
dc = DomainCollection(self.appliance)
result_view = self.create_view(DomainListView, dc)
elif isinstance(self.parent_obj, Domain):
result_view = self.create_view(DomainDetailsView, self.parent_obj)
else:
result_view = self.create_view(NamespaceDetailsView, self.parent_obj)
assert result_view.is_displayed
result_view.flash.assert_no_error()
result_view.flash.assert_message(
'Automate Namespace "{}": Delete successful'.format(self.description or self.name))
[docs] def update(self, updates):
view = navigate_to(self, 'Edit')
changed = view.fill(updates)
if changed:
view.save_button.click()
else:
view.cancel_button.click()
view = self.create_view(NamespaceDetailsView, override=updates)
assert view.is_displayed
view.flash.assert_no_error()
if changed:
if self.appliance.version >= '5.8.2':
text = (
updates.get('description', self.description) or
updates.get('name', self.name))
view.flash.assert_message(
'Automate Namespace "{}" was saved'.format(text))
else:
view.flash.assert_message(
'Automate Namespace "{}" was saved'.format(updates.get('name', self.name)))
else:
view.flash.assert_message(
'Edit of Automate Namespace "{}" was cancelled by the user'.format(self.name))
@property
def exists(self):
try:
navigate_to(self, 'Details')
return True
except CandidateNotFound:
return False
[docs] def delete_if_exists(self):
if self.exists:
self.delete()
@attr.s
[docs]class NamespaceCollection(BaseCollection):
ENTITY = Namespace
@property
def tree_path(self):
return self.parent.tree_path
[docs] def create(self, name=None, description=None, cancel=False):
add_page = navigate_to(self, 'Add')
fill_dict = {
k: v
for k, v in {'name': name, 'description': description}.items()
if v is not None}
add_page.fill(fill_dict)
if cancel:
add_page.cancel_button.click()
add_page.flash.assert_no_error()
add_page.flash.assert_message('Add of new Automate Namespace was cancelled by the user')
return None
else:
add_page.add_button.click()
add_page.flash.assert_no_error()
if self.appliance.version >= '5.8.2':
add_page.flash.assert_message(
'Automate Namespace "{}" was added'.format(description or name))
else:
add_page.flash.assert_message('Automate Namespace "{}" was added'.format(name))
return self.instantiate(name=name, description=description)
[docs] def delete(self, *namespaces):
all_page = navigate_to(self.parent.parent, 'Details')
namespaces = list(namespaces)
parents = set()
# Check if the parent is the same
for namespace in namespaces:
parents.add(namespace.parent.parent)
if len(parents) > 1:
raise ValueError('You passed namespaces that are not under one parent.')
checked_namespaces = []
if not all_page.namespaces.is_displayed:
raise ValueError('No namespace found!')
all_page.namespaces.uncheck_all()
for row in all_page.namespaces.rows(_row__attr_startswith=('data-click-id', 'aen-')):
name = row[2].text
for namespace in namespaces:
if namespace.name == name:
checked_namespaces.append(namespace)
row[0].check()
break
if set(namespaces) == set(checked_namespaces):
break
if set(namespaces) != set(checked_namespaces):
raise ValueError('Some of the namespaces were not found in the UI.')
if isinstance(self.parent, Domain):
all_page.configuration.item_select('Remove Namespaces', handle_alert=True)
else:
all_page.configuration.item_select('Remove selected Items', handle_alert=True)
all_page.flash.assert_no_error()
for namespace in checked_namespaces:
all_page.flash.assert_message(
'Automate Namespace "{}": Delete successful'.format(
namespace.description or namespace.name))
@navigator.register(NamespaceCollection)
[docs]class Add(CFMENavigateStep):
VIEW = NamespaceAddView
prerequisite = NavigateToAttribute('parent', 'Details')
[docs] def step(self):
self.prerequisite_view.configuration.item_select('Add a New Namespace')
@navigator.register(Namespace)
[docs]class Details(CFMENavigateStep):
VIEW = NamespaceDetailsView
prerequisite = NavigateToAttribute('domain', 'Details')
[docs] def step(self):
self.prerequisite_view.datastore.tree.click_path(*self.obj.tree_path)
@navigator.register(Namespace)
[docs]class Edit(CFMENavigateStep):
VIEW = NamespaceEditView
prerequisite = NavigateToSibling('Details')
[docs] def step(self):
self.prerequisite_view.configuration.item_select('Edit this Namespace')