From 4c661d88ca965cb387d9e25d45af549de6768232 Mon Sep 17 00:00:00 2001 From: Jaroslav Henner Date: Wed, 1 Jul 2020 14:12:55 +0200 Subject: [PATCH] Fix test_run_datastore_analysis test. This fixes the SSA on datastores by navigating to the datastores from provider and then starting the test. Also Resolve circular imports Fixes: File "/cfme/cfme_tests/cfme/utils/providers.py", line 16, in from cfme.common.provider import all_types ImportError: Error importing plugin "cfme.markers.env": cannot import name 'all_types' from 'cfme.common.provider' (/cfme/cfme_tests/cfme/common/provider.py) --- cfme/common/datastore_views.py | 173 ++++++++++++++ cfme/common/host_views.py | 8 + cfme/common/provider.py | 13 ++ cfme/infrastructure/datastore.py | 217 +++--------------- cfme/infrastructure/host.py | 2 +- .../cloud_infra_common/test_relationships.py | 4 +- .../infrastructure/test_datastore_analysis.py | 125 +++++----- cfme/tests/webui/test_general_ui.py | 4 +- 8 files changed, 303 insertions(+), 243 deletions(-) create mode 100644 cfme/common/datastore_views.py diff --git a/cfme/common/datastore_views.py b/cfme/common/datastore_views.py new file mode 100644 index 0000000000..56cffc898d --- /dev/null +++ b/cfme/common/datastore_views.py @@ -0,0 +1,173 @@ +from lxml.html import document_fromstring +from widgetastic.widget import Text +from widgetastic.widget import View +from widgetastic_patternfly import Accordion +from widgetastic_patternfly import Dropdown + +from cfme.common import BaseLoggedInPage +from cfme.common.vm_views import VMEntities +from widgetastic_manageiq import BaseEntitiesView +from widgetastic_manageiq import CompareToolBarActionsView +from widgetastic_manageiq import ItemsToolBarViewSelector +from widgetastic_manageiq import JSBaseEntity +from widgetastic_manageiq import ManageIQTree +from widgetastic_manageiq import Search +from widgetastic_manageiq import SummaryTable +from widgetastic_manageiq import Table + + +class DatastoreEntity(JSBaseEntity): + @property + def data(self): + data_dict = super().data + try: + if 'quadicon' in data_dict and data_dict['quadicon']: + quad_data = document_fromstring(data_dict['quadicon']) + data_dict['type'] = quad_data.xpath(self.QUADRANT.format(pos="a"))[0].get('alt') + data_dict['no_vm'] = quad_data.xpath(self.QUADRANT.format(pos="b"))[0].text + data_dict['no_host'] = quad_data.xpath(self.QUADRANT.format(pos="c"))[0].text + return data_dict + except IndexError: + return {} + + +class DatastoreEntities(BaseEntitiesView): + """ + represents central view where all QuadIcons, etc are displayed + """ + @property + def entity_class(self): + return DatastoreEntity + + +class DatastoreToolBar(View): + """ + represents datastore toolbar and its controls + """ + configuration = Dropdown(text='Configuration') + policy = Dropdown(text='Policy') + monitoring = Dropdown("Monitoring") + download = Dropdown(text='Download') + view_selector = View.nested(ItemsToolBarViewSelector) + + +class DatastoreSideBar(View): + """ + represents left side bar. it usually contains navigation, filters, etc + """ + @View.nested + class datastores(Accordion): # noqa + ACCORDION_NAME = "Datastores" + tree = ManageIQTree() + + @View.nested + class clusters(Accordion): # noqa + ACCORDION_NAME = "Datastore Clusters" + tree = ManageIQTree() + + +class DatastoresView(BaseLoggedInPage): + """ + represents whole All Datastores page + """ + toolbar = View.nested(DatastoreToolBar) + sidebar = View.nested(DatastoreSideBar) + search = View.nested(Search) + including_entities = View.include(DatastoreEntities, use_parent=True) + + @property + def is_displayed(self): + return (super(BaseLoggedInPage, self).is_displayed and + self.navigation.currently_selected == ['Compute', 'Infrastructure', + 'Datastores'] and + self.entities.title.text == 'All Datastores') + + +class HostAllDatastoresView(DatastoresView): + + @property + def is_displayed(self): + return ( + self.logged_in_as_current_user and + self.navigation.currently_selected == ["Compute", "Infrastructure", "Hosts"] and + self.entities.title.text == "{} (All Datastores)".format(self.context["object"].name) + ) + + +class ProviderAllDatastoresView(DatastoresView): + """ + This view is used in test_provider_relationships + """ + + @property + def is_displayed(self): + msg = "{} (All Datastores)".format(self.context["object"].name) + return ( + self.logged_in_as_current_user and + self.navigation.currently_selected == ["Compute", "Infrastructure", "Providers"] and + self.entities.title.text == msg + ) + + +class DatastoreManagedVMsView(BaseLoggedInPage): + """ + This view represents All VMs and Templates page for datastores + """ + toolbar = View.nested(DatastoreToolBar) + including_entities = View.include(VMEntities, use_parent=True) + + @property + def is_displayed(self): + return ( + super(BaseLoggedInPage, self).is_displayed + and self.navigation.currently_selected == ["Compute", "Infrastructure", "Datastores"] + and self.entities.title.text == f'{self.context["object"].name} (All VMs and Instances)' + and self.context["object"].name in self.breadcrumb.active_location + ) + + +class DatastoreDetailsView(BaseLoggedInPage): + """ + represents Datastore Details page + """ + title = Text('//div[@id="main-content"]//h1') + toolbar = View.nested(DatastoreToolBar) + sidebar = View.nested(DatastoreSideBar) + + @View.nested + class entities(View): # noqa + """ + represents Details page when it is switched to Summary aka Tables view + """ + properties = SummaryTable(title="Properties") + registered_vms = SummaryTable(title="Information for Registered VMs") + relationships = SummaryTable(title="Relationships") + content = SummaryTable(title="Content") + smart_management = SummaryTable(title="Smart Management") + + @property + def is_displayed(self): + return (super(BaseLoggedInPage, self).is_displayed and + self.navigation.currently_selected == ['Compute', 'Infrastructure', + 'Datastores'] and + self.title.text == 'Datastore "{name}"'.format(name=self.context['object'].name)) + + +class DatastoresCompareView(BaseLoggedInPage): + """Compare VM / Template page.""" + # TODO: This table doesn't read properly, fix it. + table = Table('//*[@id="compare-grid"]/table') + title = Text('//*[@id="main-content"]//h1') + + @View.nested + class toolbar(View): + actions = View.nested(CompareToolBarActionsView) + download = Dropdown(text="Download") + + @property + def is_displayed(self): + return ( + self.logged_in_as_current_user + and self.title.text == "Compare VM or Template" + and self.navigation.currently_selected == ["Compute", "Infrastructure", "Datastores"] + ) diff --git a/cfme/common/host_views.py b/cfme/common/host_views.py index 3bafdd3452..11e7d52d0a 100644 --- a/cfme/common/host_views.py +++ b/cfme/common/host_views.py @@ -12,6 +12,7 @@ from cfme.common import BaseLoggedInPage from cfme.common import CompareView from cfme.common import TimelinesView +from cfme.exceptions import displayed_not_implemented from cfme.utils.log import logger from cfme.utils.version import Version from cfme.utils.version import VersionPicker @@ -431,3 +432,10 @@ class HostVmmInfoView(HostsView): def is_displayed(self): active_loc = f"{self.context['object'].name} (VM Monitor Information)" return self.breadcrumb.active_location == active_loc + + +class RegisteredHostsView(HostsView): + """ + represents Hosts related to some datastore + """ + is_displayed = displayed_not_implemented diff --git a/cfme/common/provider.py b/cfme/common/provider.py index a481986439..00e1e8b13c 100644 --- a/cfme/common/provider.py +++ b/cfme/common/provider.py @@ -17,6 +17,7 @@ from cfme.base.credential import TokenCredential from cfme.common import CustomButtonEventsMixin from cfme.common import Taggable +from cfme.common.datastore_views import ProviderAllDatastoresView from cfme.exceptions import AddProviderError from cfme.exceptions import HostStatsNotContains from cfme.exceptions import ProviderHasNoKey @@ -26,6 +27,7 @@ from cfme.utils import conf from cfme.utils import ParamClassName from cfme.utils.appliance import Navigatable +from cfme.utils.appliance.implementations.ui import CFMENavigateStep from cfme.utils.appliance.implementations.ui import navigate_to from cfme.utils.appliance.implementations.ui import navigator from cfme.utils.log import logger @@ -1374,3 +1376,14 @@ class DefaultEndpointForm(View): change_password = Text(locator='.//a[normalize-space(.)="Change stored password"]') validate = Button('Validate') + + +@navigator.register(BaseProvider, 'DatastoresOfProvider') +class DatastoresOfProvider(CFMENavigateStep): + VIEW = ProviderAllDatastoresView + + def prerequisite(self): + return navigate_to(self.obj, 'Details') + + def step(self, *args, **kwargs): + self.prerequisite_view.entities.summary('Relationships').click_at('Datastores') diff --git a/cfme/infrastructure/datastore.py b/cfme/infrastructure/datastore.py index 1a5cba327a..32c7f7ecc8 100644 --- a/cfme/infrastructure/datastore.py +++ b/cfme/infrastructure/datastore.py @@ -1,21 +1,16 @@ """ A model of an Infrastructure Datastore in CFME """ import attr -from lxml.html import document_fromstring from navmazing import NavigateToAttribute from navmazing import NavigateToSibling -from widgetastic.widget import Text -from widgetastic.widget import View -from widgetastic_patternfly import Accordion -from widgetastic_patternfly import Dropdown -from cfme.common import BaseLoggedInPage from cfme.common import CustomButtonEventsMixin from cfme.common import Taggable from cfme.common.candu_views import DatastoreInfraUtilizationView -from cfme.common.host_views import HostsView -from cfme.common.vm_views import VMEntities -from cfme.exceptions import displayed_not_implemented +from cfme.common.datastore_views import DatastoreDetailsView +from cfme.common.datastore_views import DatastoreManagedVMsView +from cfme.common.datastore_views import DatastoresView +from cfme.common.host_views import RegisteredHostsView from cfme.exceptions import ItemNotFound from cfme.exceptions import MenuItemNotFound from cfme.modeling.base import BaseCollection @@ -29,178 +24,6 @@ from cfme.utils.providers import get_crud_by_name from cfme.utils.wait import TimedOutError from cfme.utils.wait import wait_for -from widgetastic_manageiq import BaseEntitiesView -from widgetastic_manageiq import CompareToolBarActionsView -from widgetastic_manageiq import ItemsToolBarViewSelector -from widgetastic_manageiq import JSBaseEntity -from widgetastic_manageiq import ManageIQTree -from widgetastic_manageiq import Search -from widgetastic_manageiq import SummaryTable -from widgetastic_manageiq import Table - - -class DatastoreToolBar(View): - """ - represents datastore toolbar and its controls - """ - configuration = Dropdown(text='Configuration') - policy = Dropdown(text='Policy') - monitoring = Dropdown("Monitoring") - download = Dropdown(text='Download') - view_selector = View.nested(ItemsToolBarViewSelector) - - -class DatastoreSideBar(View): - """ - represents left side bar. it usually contains navigation, filters, etc - """ - @View.nested - class datastores(Accordion): # noqa - ACCORDION_NAME = "Datastores" - tree = ManageIQTree() - - @View.nested - class clusters(Accordion): # noqa - ACCORDION_NAME = "Datastore Clusters" - tree = ManageIQTree() - - -class DatastoreEntity(JSBaseEntity): - @property - def data(self): - data_dict = super().data - try: - if 'quadicon' in data_dict and data_dict['quadicon']: - quad_data = document_fromstring(data_dict['quadicon']) - data_dict['type'] = quad_data.xpath(self.QUADRANT.format(pos="a"))[0].get('alt') - data_dict['no_vm'] = quad_data.xpath(self.QUADRANT.format(pos="b"))[0].text - data_dict['no_host'] = quad_data.xpath(self.QUADRANT.format(pos="c"))[0].text - return data_dict - except IndexError: - return {} - - -class DatastoreEntities(BaseEntitiesView): - """ - represents central view where all QuadIcons, etc are displayed - """ - @property - def entity_class(self): - return DatastoreEntity - - -class DatastoresView(BaseLoggedInPage): - """ - represents whole All Datastores page - """ - toolbar = View.nested(DatastoreToolBar) - sidebar = View.nested(DatastoreSideBar) - search = View.nested(Search) - including_entities = View.include(DatastoreEntities, use_parent=True) - - @property - def is_displayed(self): - return (super(BaseLoggedInPage, self).is_displayed and - self.navigation.currently_selected == ['Compute', 'Infrastructure', - 'Datastores'] and - self.entities.title.text == 'All Datastores') - - -class HostAllDatastoresView(DatastoresView): - - @property - def is_displayed(self): - return ( - self.logged_in_as_current_user and - self.navigation.currently_selected == ["Compute", "Infrastructure", "Hosts"] and - self.entities.title.text == "{} (All Datastores)".format(self.context["object"].name) - ) - - -class ProviderAllDatastoresView(DatastoresView): - """ - This view is used in test_provider_relationships - """ - - @property - def is_displayed(self): - msg = "{} (All Datastores)".format(self.context["object"].name) - return ( - self.logged_in_as_current_user and - self.navigation.currently_selected == ["Compute", "Infrastructure", "Providers"] and - self.entities.title.text == msg - ) - - -class DatastoreManagedVMsView(BaseLoggedInPage): - """ - This view represents All VMs and Templates page for datastores - """ - toolbar = View.nested(DatastoreToolBar) - including_entities = View.include(VMEntities, use_parent=True) - - @property - def is_displayed(self): - return ( - super(BaseLoggedInPage, self).is_displayed - and self.navigation.currently_selected == ["Compute", "Infrastructure", "Datastores"] - and self.entities.title.text == f'{self.context["object"].name} (All VMs and Instances)' - and self.context["object"].name in self.breadcrumb.active_location - ) - - -class DatastoreDetailsView(BaseLoggedInPage): - """ - represents Datastore Details page - """ - title = Text('//div[@id="main-content"]//h1') - toolbar = View.nested(DatastoreToolBar) - sidebar = View.nested(DatastoreSideBar) - - @View.nested - class entities(View): # noqa - """ - represents Details page when it is switched to Summary aka Tables view - """ - properties = SummaryTable(title="Properties") - registered_vms = SummaryTable(title="Information for Registered VMs") - relationships = SummaryTable(title="Relationships") - content = SummaryTable(title="Content") - smart_management = SummaryTable(title="Smart Management") - - @property - def is_displayed(self): - return (super(BaseLoggedInPage, self).is_displayed and - self.navigation.currently_selected == ['Compute', 'Infrastructure', - 'Datastores'] and - self.title.text == 'Datastore "{name}"'.format(name=self.context['object'].name)) - - -class RegisteredHostsView(HostsView): - """ - represents Hosts related to some datastore - """ - is_displayed = displayed_not_implemented - - -class DatastoresCompareView(BaseLoggedInPage): - """Compare VM / Template page.""" - # TODO: This table doesn't read properly, fix it. - table = Table('//*[@id="compare-grid"]/table') - title = Text('//*[@id="main-content"]//h1') - - @View.nested - class toolbar(View): - actions = View.nested(CompareToolBarActionsView) - download = Dropdown(text="Download") - - @property - def is_displayed(self): - return ( - self.logged_in_as_current_user - and self.title.text == "Compare VM or Template" - and self.navigation.currently_selected == ["Compute", "Infrastructure", "Datastores"] - ) @attr.s @@ -343,6 +166,28 @@ def run_smartstate_analysis(self, wait_for_task_result=False): task.wait_for_finished() return task + def run_smartstate_analysis_from_provider(self, wait_for_task_result=False): + """ Runs smartstate analysis of this datastore with navigating trough the provider + + Note: + The host must have valid credentials already set up for this to work. + """ + view = navigate_to(self.provider, 'DatastoresOfProvider') + try: + view.entities.get_entity(name=self.name, surf_pages=True).ensure_checked() + except ItemNotFound: + raise ValueError(f'Could not find datastore {self.name} in the UI') + + view.toolbar.configuration.item_select('Perform SmartState Analysis', handle_alert=True) + view.flash.assert_success_message( + f'"{self.name}": scan successfully initiated') + + if wait_for_task_result: + task = self.appliance.collections.tasks.instantiate( + name=f"SmartState Analysis for [{self.name}]", tab='MyOtherTasks') + task.wait_for_finished() + return task + def wait_candu_data_available(self, timeout=900): """Waits until C&U data are available for this Datastore @@ -418,16 +263,13 @@ def delete(self, *datastores): message='Wait for Datastore to be deleted') def run_smartstate_analysis(self, *datastores): - datastores = list(datastores) - - checked_datastores = list() + datastores = set(datastores) view = navigate_to(self, 'All') for datastore in datastores: try: view.entities.get_entity(name=datastore.name, surf_pages=True).ensure_checked() - checked_datastores.append(datastore) except ItemNotFound: raise ValueError(f'Could not find datastore {datastore.name} in the UI') @@ -436,6 +278,11 @@ def run_smartstate_analysis(self, *datastores): view.flash.assert_success_message( f'"{datastore.name}": scan successfully initiated') + def run_smartstate_analysis_from_provider(self, *datastores: Datastore): + """ Runs smartstate analysis of this datastore with navigating trough the provider """ + for datastore in datastores: + datastore.run_smartstate_analysis_from_provider(wait_for_task_result=False) + @navigator.register(DatastoreCollection, 'All') class All(CFMENavigateStep): diff --git a/cfme/infrastructure/host.py b/cfme/infrastructure/host.py index 0e83e7b485..1969d999c9 100644 --- a/cfme/infrastructure/host.py +++ b/cfme/infrastructure/host.py @@ -13,6 +13,7 @@ from cfme.common import PolicyProfileAssignable from cfme.common import Taggable from cfme.common.candu_views import HostInfraUtilizationView +from cfme.common.datastore_views import HostAllDatastoresView from cfme.common.host_views import HostAddView from cfme.common.host_views import HostDetailsView from cfme.common.host_views import HostDevicesView @@ -33,7 +34,6 @@ from cfme.common.host_views import ProviderHostsCompareView from cfme.exceptions import ItemNotFound from cfme.exceptions import RestLookupError -from cfme.infrastructure.datastore import HostAllDatastoresView from cfme.modeling.base import BaseCollection from cfme.modeling.base import BaseEntity from cfme.networks.views import OneHostSubnetView diff --git a/cfme/tests/cloud_infra_common/test_relationships.py b/cfme/tests/cloud_infra_common/test_relationships.py index 80921fd7dd..4640fb825c 100644 --- a/cfme/tests/cloud_infra_common/test_relationships.py +++ b/cfme/tests/cloud_infra_common/test_relationships.py @@ -14,14 +14,14 @@ from cfme.cloud.provider.openstack import OpenStackProvider from cfme.cloud.stack import ProviderStackAllView from cfme.cloud.tenant import ProviderTenantAllView +from cfme.common.datastore_views import HostAllDatastoresView +from cfme.common.datastore_views import ProviderAllDatastoresView from cfme.common.host_views import ProviderAllHostsView from cfme.common.provider_views import InfraProviderDetailsView from cfme.common.vm_views import HostAllVMsView from cfme.common.vm_views import ProviderAllVMsView from cfme.infrastructure.cluster import ClusterDetailsView from cfme.infrastructure.cluster import ProviderAllClustersView -from cfme.infrastructure.datastore import HostAllDatastoresView -from cfme.infrastructure.datastore import ProviderAllDatastoresView from cfme.infrastructure.provider import InfraProvider from cfme.infrastructure.provider.rhevm import RHEVMProvider from cfme.infrastructure.provider.virtualcenter import VMwareProvider diff --git a/cfme/tests/infrastructure/test_datastore_analysis.py b/cfme/tests/infrastructure/test_datastore_analysis.py index 7f700e10fd..bd3759bb20 100644 --- a/cfme/tests/infrastructure/test_datastore_analysis.py +++ b/cfme/tests/infrastructure/test_datastore_analysis.py @@ -1,15 +1,16 @@ import pytest -from widgetastic_patternfly import DropdownDisabled from cfme import test_requirements -from cfme.exceptions import MenuItemNotFound +from cfme.infrastructure.datastore import Datastore from cfme.infrastructure.provider.rhevm import RHEVMProvider from cfme.infrastructure.provider.virtualcenter import VMwareProvider from cfme.utils import testgen from cfme.utils.appliance.implementations.ui import navigate_to +from cfme.utils.blockers import GH from cfme.utils.log import logger from cfme.utils.wait import wait_for + pytestmark = [test_requirements.smartstate] DATASTORE_TYPES = ('vmfs', 'nfs', 'iscsi') @@ -56,41 +57,51 @@ def pytest_generate_tests(metafunc): testgen.parametrize(metafunc, argnames, new_argvalues, ids=new_idlist, scope="module") -@pytest.fixture(scope='module') -def datastore(appliance, provider, datastore_type, datastore_name): - return appliance.collections.datastores.instantiate(name=datastore_name, - provider=provider, - type=datastore_type) - - -@pytest.fixture(scope='module') -def datastores_hosts_setup(provider, datastore): - hosts = datastore.hosts.all() - for host in hosts: - host_data = [data - for data in provider.data.get("hosts", {}) - if data.get("name") == host.name] - if not host_data: - pytest.skip(f"No host data for provider {provider} and datastore {datastore}") - host.update_credentials_rest(credentials=host_data[0]['credentials']) - else: - pytest.skip(f"No hosts attached to the datastore selected for testing: {datastore}") +@pytest.fixture +def datastore(temp_appliance_preconfig_funcscope, provider, datastore_type, datastore_name)\ + -> Datastore: + with temp_appliance_preconfig_funcscope as appliance: + return appliance.collections.datastores.instantiate(name=datastore_name, + provider=provider, + type=datastore_type) + + +@pytest.fixture +def datastores_hosts_setup(setup_provider_temp_appliance, provider, datastore): + updated_hosts = [] + for host in datastore.hosts.all(): + try: + host_data, = [data + for data in provider.data.get("hosts", {}) + if data.get("name") == host.name] + except ValueError as exc: + pytest.skip(f"Data for host {host} in provider {provider} and datastore {datastore} " + f"couldn't be determined: {exc}.") + else: + host.update_credentials_rest(credentials=host_data['credentials']) + updated_hosts.append(host) + + if not updated_hosts: + pytest.skip(f"No hosts attached to the datastore {datastore} was selected for testing.") yield - for host in hosts: + for host in updated_hosts: host.remove_credentials_rest() -@pytest.fixture(scope='function') +@pytest.fixture() def clear_all_tasks(appliance): # clear table col = appliance.collections.tasks.filter({'tab': 'AllTasks'}) col.delete_all() +# Note that it seems like that if there is SSA already ongoing and we attempt to start another one, +# we get "SmartState Analysis action does not apply to selected items" flash message. Therefore +# I the temp_appliance is used here to work around this difficulty. @pytest.mark.tier(2) -def test_run_datastore_analysis(setup_provider, datastore, soft_assert, datastores_hosts_setup, - clear_all_tasks, appliance): - """Tests smarthost analysis +def test_run_datastore_analysis(setup_provider_temp_appliance, datastore, soft_assert, + clear_all_tasks, temp_appliance_preconfig_funcscope): + """Tests SmartState analysis Metadata: test_flag: datastore_analysis @@ -101,30 +112,38 @@ def test_run_datastore_analysis(setup_provider, datastore, soft_assert, datastor caseimportance: critical initialEstimate: 1/3h """ - # Initiate analysis - try: - datastore.run_smartstate_analysis(wait_for_task_result=True) - except (MenuItemNotFound, DropdownDisabled): - # TODO need to update to cover all detastores - pytest.skip(f'Smart State analysis is disabled for {datastore.name} datastore') - details_view = navigate_to(datastore, 'DetailsFromProvider') - # c_datastore = details_view.entities.properties.get_text_of("Datastore Type") - - # Check results of the analysis and the datastore type - # TODO need to clarify datastore type difference - # soft_assert(c_datastore == datastore.type.upper(), - # 'Datastore type does not match the type defined in yaml:' + - # 'expected "{}" but was "{}"'.format(datastore.type.upper(), c_datastore)) - - wait_for(lambda: details_view.entities.content.get_text_of(CONTENT_ROWS_TO_CHECK[0]), - delay=15, timeout="3m", - fail_condition='0', - fail_func=appliance.server.browser.refresh) - managed_vms = details_view.entities.relationships.get_text_of('Managed VMs') - if managed_vms != '0': - for row_name in CONTENT_ROWS_TO_CHECK: - value = details_view.entities.content.get_text_of(row_name) - soft_assert(value != '0', - f'Expected value for {row_name} to be non-empty') - else: - assert details_view.entities.content.get_text_of(CONTENT_ROWS_TO_CHECK[-1]) != '0' + temp_appliance_preconfig_funcscope.browser_steal = True + with temp_appliance_preconfig_funcscope as appliance: + # Initiate analysis + # Note that it would be great to test both navigation paths. + if GH(('ManageIQ/manageiq', 20367)).blocks: + datastore.run_smartstate_analysis_from_provider() + else: + datastore.run_smartstate_analysis() + + # c_datastore = details_view.entities.properties.get_text_of("Datastore Type") + # Check results of the analysis and the datastore type + # TODO need to clarify datastore type difference + # soft_assert(c_datastore == datastore.type.upper(), + # 'Datastore type does not match the type defined in yaml:' + + # 'expected "{}" but was "{}"'.format(datastore.type.upper(), c_datastore)) + + if datastore.provider.one_of(RHEVMProvider) and GH(('ManageIQ/manageiq', 20366)).blocks: + # or (datastore.provider.one_of(VMwareProvider) and + # Version(datastore.provider.version) == '6.5'): # Why is that needed? + return + + details_view = navigate_to(datastore, 'DetailsFromProvider') + wait_for(lambda: details_view.entities.content.get_text_of(CONTENT_ROWS_TO_CHECK[0]), + delay=15, timeout="6m", + fail_condition='0', + fail_func=appliance.server.browser.refresh) + + managed_vms = details_view.entities.relationships.get_text_of('Managed VMs') + if managed_vms != '0': + for row_name in CONTENT_ROWS_TO_CHECK: + value = details_view.entities.content.get_text_of(row_name) + soft_assert(value != '0', + f'Expected value for {row_name} to be non-empty') + else: + assert details_view.entities.content.get_text_of(CONTENT_ROWS_TO_CHECK[-1]) != '0' diff --git a/cfme/tests/webui/test_general_ui.py b/cfme/tests/webui/test_general_ui.py index e1db273858..fd5c5613c9 100644 --- a/cfme/tests/webui/test_general_ui.py +++ b/cfme/tests/webui/test_general_ui.py @@ -6,6 +6,8 @@ from cfme import test_requirements from cfme.base.ui import LoginPage from cfme.cloud.provider import CloudProvider +from cfme.common.datastore_views import DatastoresCompareView +from cfme.common.datastore_views import ProviderAllDatastoresView from cfme.common.host_views import ProviderAllHostsView from cfme.common.provider import BaseProvider from cfme.common.provider_views import CloudProviderAddView @@ -20,8 +22,6 @@ from cfme.infrastructure.config_management import ConfigManagerProvider from cfme.infrastructure.config_management.ansible_tower import AnsibleTowerProvider from cfme.infrastructure.config_management.satellite import SatelliteProvider -from cfme.infrastructure.datastore import DatastoresCompareView -from cfme.infrastructure.datastore import ProviderAllDatastoresView from cfme.infrastructure.provider import InfraProvider from cfme.infrastructure.provider import ProviderClustersView from cfme.infrastructure.provider import ProviderTemplatesView