URL: https://github.com/freeipa/freeipa/pull/1741
Author: Rezney
 Title: #1741: [Backport][ipa-4-6] - Web ui services backport
Action: opened

PR body:
"""
Web ui services backport for 4.6
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1741/head:pr1741
git checkout pr1741
From f74077828b7b6ccb4189bb3373a1eb88e5169a46 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:05:03 +0100
Subject: [PATCH 01/13] ui_tests: change get_http_pkey() function

change get_http_pkey() function to more generic one in
order to get pkey for different services

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 602ae4d83b..b134b73e68 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -54,10 +54,11 @@ def load_file(self, path):
             content = file_d.read()
         return content
 
-    def get_http_pkey(self):
-        host = self.config.get('ipa_server')
+    def get_service_pkey(self, service, host=None):
+        if not host:
+            host = self.config.get('ipa_server')
         realm = self.config.get('ipa_realm')
-        pkey = 'HTTP/%s@%s' % (host, realm)
+        pkey = '{}/{}@{}'.format(service, host, realm)
         return pkey
 
 
@@ -265,7 +266,7 @@ def test_kerberos_flags(self):
         Test Kerberos flags
         http://www.freeipa.org/page/V3/Kerberos_Flags
         """
-        pkey = self.get_http_pkey()
+        pkey = self.get_service_pkey('HTTP')
         name = 'ipakrbokasdelegate'
         mod = {'mod': [('checkbox', name, None)]}
         checked = ['checked']

From 5cc3be5ee6856d8801866b24ca8506bb8ce1890b Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:09:08 +0100
Subject: [PATCH 02/13] ui_tests: add_host() support func in test_service

Add add_host() support func into test_service to
create temp hosts.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index b134b73e68..cc7f8b1ccb 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -61,6 +61,14 @@ def get_service_pkey(self, service, host=None):
         pkey = '{}/{}@{}'.format(service, host, realm)
         return pkey
 
+    def add_host(self, hostname, dns_zone, force=False):
+        self.navigate_to_entity('host')
+        self.facet_button_click('add')
+        self.fill_textbox('hostname', hostname)
+        self.fill_textbox('dnszone', dns_zone)
+        if force:
+            self.check_option('force', 'checked')
+        self.dialog_button_click('add')
 
 @pytest.mark.tier1
 class test_service(sevice_tasks):

From 6e0979cb83f791d060b9882e3573108215f5cfb0 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:17:18 +0100
Subject: [PATCH 03/13] ui_tests: add_service() support func in test_service

Add add_service() support func into test_service.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index cc7f8b1ccb..1faaf8d744 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -70,6 +70,31 @@ def add_host(self, hostname, dns_zone, force=False):
             self.check_option('force', 'checked')
         self.dialog_button_click('add')
 
+    def add_service(self, service,
+                    host=None,
+                    textbox=None,
+                    force=False,
+                    cancel=False,
+                    confirm=True):
+
+        if not host:
+            host = self.config.get('ipa_server')
+        self.navigate_to_entity(ENTITY)
+        self.facet_button_click('add')
+
+        self.select_combobox('service', service, combobox_input=textbox)
+        self.select_combobox('host', host)
+        if force:
+            self.wait(0.5)
+            self.check_option('force', 'checked')
+        if cancel:
+            self.dialog_button_click('cancel')
+            return
+        if not confirm:
+            return
+        self.dialog_button_click('add')
+        self.wait(0.3)
+        self.assert_no_error_dialog()
 @pytest.mark.tier1
 class test_service(sevice_tasks):
 

From a22e85dc845125568847cc8e64e4d5dff0c57576 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:23:11 +0100
Subject: [PATCH 04/13] ui_tests: add more test cases to test_certification

Add cases for:
"cancel_cert_request", "cancel_hold_cert", "cancel_remove_hold",
"cancel_revoke_cert" and "revoke_cert"

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 45 ++++++++++++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 3 deletions(-)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 1faaf8d744..9f2a04b446 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -112,8 +112,8 @@ def test_certificates(self):
         """
         Test service certificate actions
 
-        Requires to have CA installed and 'service_csr_path' configuration option
-        set.
+        Requires to have CA installed and 'service_csr_path' configuration
+        option set.
         """
 
         if not self.has_ca():
@@ -134,6 +134,9 @@ def test_certificates(self):
 
         # cert request
         self.action_list_action('request_cert', confirm=False)
+        # testing if cancel button works
+        self.dialog_button_click('cancel')
+        self.action_list_action('request_cert', confirm=False)
         self.assert_dialog()
         self.fill_text("textarea[name='csr'", csr)
         self.dialog_button_click('issue')
@@ -167,7 +170,14 @@ def test_certificates(self):
                                        parents_css_sel=cert_widget_sel,
                                        facet_actions=False)
 
-        # cert revoke
+        # cert revoke/hold cancel
+        self.action_list_action('revoke', confirm=False,
+                                parents_css_sel=cert_widget_sel)
+        self.wait()
+        self.select('select', '6')
+        self.dialog_button_click('cancel')
+
+        # cert revoke/hold
         self.action_list_action('revoke', confirm=False,
                                 parents_css_sel=cert_widget_sel)
         self.wait()
@@ -186,6 +196,11 @@ def test_certificates(self):
                                        parents_css_sel=cert_widget_sel,
                                        facet_actions=False)
 
+        # cert remove hold cancel
+        self.action_list_action('remove_hold', confirm=False,
+                                parents_css_sel=cert_widget_sel)
+        self.dialog_button_click('cancel')
+
         # cert remove hold
         self.action_list_action('remove_hold', confirm=False,
                                 parents_css_sel=cert_widget_sel)
@@ -203,6 +218,30 @@ def test_certificates(self):
                                        parents_css_sel=cert_widget_sel,
                                        facet_actions=False)
 
+        # cert revoke cancel
+        self.action_list_action('revoke', confirm=False,
+                                parents_css_sel=cert_widget_sel)
+        self.wait()
+        self.select('select', '1')
+        self.dialog_button_click('cancel')
+
+        # cert revoke
+        self.action_list_action('revoke', confirm=False,
+                                parents_css_sel=cert_widget_sel)
+        self.wait()
+        self.select('select', '1')
+        self.dialog_button_click('ok')
+
+        # check that revoke action is not enabled
+        self.assert_action_list_action('revoke', enabled=False,
+                                       parents_css_sel=cert_widget_sel,
+                                       facet_actions=False)
+
+        # check that remove_hold action not is enabled
+        self.assert_action_list_action('remove_hold', enabled=False,
+                                       parents_css_sel=cert_widget_sel,
+                                       facet_actions=False)
+
         # cleanup
         self.navigate_to_entity(ENTITY, 'search')
         self.delete_record(pkey, data.get('del'))

From 48241419c490b915721eacce194b7ede043aa308 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:24:48 +0100
Subject: [PATCH 05/13] ui_tests: add more test cases

Add more test cases to test_services. Details in the ticket.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 286 ++++++++++++++++++++++++++++++++++++
 1 file changed, 286 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 9f2a04b446..d121ad9777 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -25,6 +25,13 @@
 from ipatests.test_webui.ui_driver import screenshot
 import pytest
 
+try:
+    from selenium.webdriver.common.keys import Keys
+    from selenium.webdriver.common.by import By
+    from selenium.webdriver.common.action_chains import ActionChains
+except ImportError:
+    pass
+
 ENTITY = 'service'
 
 
@@ -95,6 +102,8 @@ def add_service(self, service,
         self.dialog_button_click('add')
         self.wait(0.3)
         self.assert_no_error_dialog()
+
+
 @pytest.mark.tier1
 class test_service(sevice_tasks):
 
@@ -353,3 +362,280 @@ def test_kerberos_flags(self):
         self.validate_fields([('checkbox', name, checked)])
         self.mod_record(ENTITY, mod)
         self.validate_fields([('checkbox', name, [])])
+
+    @screenshot
+    def test_add_remove_services(self):
+        """
+        Test add/remove common services on default host
+        """
+        self.init_app()
+
+        services = ['cifs', 'ftp', 'imap', 'libvirt', 'nfs', 'qpidd', 'smtp']
+        added_services = []
+
+        # add services
+        for service in services:
+            pkey = self.get_service_pkey(service)
+            self.add_service(service)
+            self.wait(0.5)
+            assert self.has_record(pkey)
+            added_services.append(pkey)
+
+        # delete single service
+        svc_tbd = added_services.pop()
+        self.delete_record(svc_tbd)
+        self.assert_notification()
+        assert not self.has_record(svc_tbd)
+
+        # delete multiple services (rest of them)
+        self.delete_record(added_services)
+        self.assert_notification()
+        for service in added_services:
+            assert not self.has_record(service)
+
+    @screenshot
+    def test_add_remove_services_force(self):
+        """
+        Test add/remove services using force (on different host)
+        """
+        self.init_app()
+
+        services = ['DNS', 'HTTP', 'ldap']
+        added_services = []
+
+        # add temp host without DNS
+        temp_host = 'host-no-dns.ipa.test'
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+
+        for service in services:
+            pkey = self.get_service_pkey(service, host=temp_host)
+            self.add_service(service, host=temp_host, force=True)
+            assert self.has_record(pkey)
+            added_services.append(pkey)
+
+        # delete single service
+        svc_tbd = added_services.pop()
+        self.delete_record(svc_tbd)
+        self.assert_notification()
+        assert not self.has_record(svc_tbd)
+
+        # delete multiple services (rest of them)
+        self.delete_record(added_services)
+        self.assert_notification()
+        for service in added_services:
+            assert not self.has_record(service)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @screenshot
+    def test_add_custom_service(self):
+        """
+        Test add custom service using textbox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('test_service')
+        self.add_service('test_service', textbox='service')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_cancel_adding_service(self):
+        """
+        Test cancel when adding a service
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('cifs')
+        self.add_service('cifs', cancel=True)
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_cancel_delete_service(self):
+        """
+        Test cancel deleting a service
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('HTTP')
+        self.navigate_to_entity(ENTITY)
+        self.delete_record(pkey, confirm_btn='cancel')
+        assert self.has_record(pkey)
+
+    @screenshot
+    def test_cancel_add_delete_managedby_host(self):
+        """
+        Test cancel/add/delete managed by host
+        """
+        pkey = self.get_service_pkey('HTTP')
+        temp_host = 'host-no-dns.ipa.test'
+        self.init_app()
+
+        # add another host for "managedby" testing
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+
+        self.navigate_to_record(pkey, entity=ENTITY)
+        self.add_associations([temp_host], facet='managedby_host',
+                              confirm_btn='cancel')
+        self.add_associations([temp_host], facet='managedby_host',
+                              delete=True)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @screenshot
+    def test_add_service_missing_hostname_field(self):
+        """
+        Test add service "hostname" field required
+        """
+        self.init_app()
+        self.navigate_to_entity(ENTITY)
+        self.facet_button_click('add')
+        self.select_combobox('service', 'cifs', combobox_input='service')
+        self.dialog_button_click('add')
+        host_elem = self.find(".widget[name='host']", By.CSS_SELECTOR)
+        self.assert_field_validation_required(parent=host_elem)
+
+    @screenshot
+    def test_add_service_missing_service_field(self):
+        """
+        Test add service "service field required
+        """
+        self.init_app()
+        host = self.config.get('ipa_server')
+        self.navigate_to_entity(ENTITY)
+        self.facet_button_click('add')
+        self.select_combobox('host', host)
+        self.dialog_button_click('add')
+        self.wait()
+        service_elem = self.find(".widget[name='service']", By.CSS_SELECTOR)
+        self.assert_field_validation_required(parent=service_elem)
+
+    @screenshot
+    def test_search_services(self):
+        """
+        Search different services
+        """
+        # keywords to search (find_record accepts data dict)
+        http_search = {'pkey': self.get_service_pkey('HTTP')}
+        ldap_search = {'pkey': self.get_service_pkey('ldap')}
+        dns_search = {'pkey': self.get_service_pkey('DNS')}
+        self.init_app()
+        self.navigate_to_entity(ENTITY)
+        self.find_record('service', http_search)
+        self.find_record('service', ldap_search)
+        self.find_record('service', dns_search)
+
+    @screenshot
+    def test_dropdown(self):
+        """
+        Test service combobox dropdowns with UP/DOWN arrows
+        """
+        self.init_app()
+        self.navigate_to_entity(ENTITY)
+        self.facet_button_click('add')
+
+        actions = ActionChains(self.driver)
+        actions.send_keys(Keys.ARROW_DOWN)
+        # all actions are performed at once with perform()
+        actions.send_keys(Keys.ARROW_DOWN).perform()
+        actions.send_keys(Keys.ENTER)
+        actions.send_keys(Keys.TAB)
+        actions.send_keys(Keys.ARROW_DOWN)
+        actions.send_keys(Keys.ARROW_DOWN)
+        actions.send_keys(Keys.ENTER).perform()
+
+        # evaluate value fields are not empty
+        service_cb = "input[name='service']"
+        service = self.find(service_cb, By.CSS_SELECTOR)
+        assert service.get_attribute('value') != ""
+        host_cb = "[name='host'].combobox-widget"
+        host = self.find(host_cb, By.CSS_SELECTOR)
+        assert host.get_attribute('value') != ""
+
+    @screenshot
+    def test_add_service_using_enter(self):
+        """
+        Add a service using enter key
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('smtp')
+        self.add_service('smtp', confirm=False)
+        actions = ActionChains(self.driver)
+        actions.send_keys(Keys.ENTER).perform()
+        self.wait(1)
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_delete_service_using_enter(self):
+        """
+        Delete a service using enter key
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('smtp')
+        self.add_service('smtp')
+        assert self.has_record(pkey)
+        self.delete_record(pkey, confirm_btn=None)
+        actions = ActionChains(self.driver)
+        actions.send_keys(Keys.ENTER).perform()
+        self.wait(1)
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_provision_unprovision_keytab(self):
+        """
+        Test provision / unprovision keytab
+
+        Requires to run a ipa-get/rmkeytab on UI host.
+        """
+        if not self.has_ca():
+            self.skip('CA is not configured')
+
+        csr_path = self.config.get('service_csr_path')
+        if not csr_path:
+            self.skip('CSR file is not configured')
+
+        csr = self.load_file(csr_path)
+
+        self.init_app()
+        pkey = self.get_service_pkey('cifs')
+
+        self.navigate_to_entity(ENTITY)
+
+        # provision service
+        self.add_service('cifs')
+        self.navigate_to_record(pkey, entity=ENTITY)
+        self.action_list_action('request_cert', confirm=False)
+        self.assert_dialog()
+        self.fill_text("textarea[name='csr'", csr)
+        self.dialog_button_click('issue')
+        self.run_keytab_on_host(pkey, 'get')
+        self.wait(1)
+        self.facet_button_click('refresh')
+
+        # assert key present
+        no_key_selector = 'div[name="kerberos-key-valid"] label'
+        provisioned_assert = 'Kerberos Key Present, Service Provisioned'
+        self.assert_text(no_key_selector, provisioned_assert)
+
+        # unprovision service
+        self.action_list_action('unprovision', confirm_btn='unprovision')
+        self.facet_button_click('refresh')
+        self.run_keytab_on_host(pkey, 'rm')
+
+        # assert key not present
+        no_key_selector = 'div[name="kerberos-key-missing"] label'
+        provisioned_assert = 'Kerberos Key Not Present'
+        self.assert_text(no_key_selector, provisioned_assert)
+
+        # service cleanup
+        self.navigate_to_entity(ENTITY)
+        self.delete_record(pkey)

From 35293e9ff978c74ac889b53aef15adf46f0008ec Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:51:10 +0100
Subject: [PATCH 06/13] ui_tests: add assert_notification()

Add assert_notification() function to check whether
we have a notification of particular type/

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 1cee05060c..7f49b71842 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1850,3 +1850,21 @@ def assert_action_list_action(self, action, visible=True, enabled=True,
             is_enabled = not self.has_class(li, 'disabled')
             assert is_enabled == enabled, ('Invalid enabled state of action item %s. '
                                            'Expected: %s') % (action, str(visible))
+
+    def assert_notification(self, type='success', assert_text=None):
+        """
+        Assert whether we have a notification of particular type
+
+        type: type for assertion
+        assert_text: assert particular text when True
+
+        Returns True if selector/text found
+        """
+
+        notification_type = 'div.notification-area .alert-{}'.format(type)
+        # wait for a half sec for notification to appear
+        self.wait(0.5)
+        is_present = self.find(notification_type, By.CSS_SELECTOR)
+        assert is_present, "Notification not present"
+        if assert_text:
+            assert assert_text in is_present.text

From 9b0e5c824654f2f3035f04fea0ba6987643cb11a Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:52:45 +0100
Subject: [PATCH 07/13] ui_tests: add assert_field_required()

Add assert_field_required() to check whether we
got 'Required field' error message.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 7f49b71842..afb777cdfb 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1851,6 +1851,19 @@ def assert_action_list_action(self, action, visible=True, enabled=True,
             assert is_enabled == enabled, ('Invalid enabled state of action item %s. '
                                            'Expected: %s') % (action, str(visible))
 
+    def assert_field_validation_required(self, parent=None):
+        """
+        Assert we got 'Required field' error message in field validation
+        """
+
+        if not parent:
+            parent = self.get_form()
+
+        req_field_css = '.help-block[name="error_link"]'
+
+        res = self.find(req_field_css, By.CSS_SELECTOR, context=parent)
+        assert 'Required field' in res.text, 'No "Required field" error found'
+
     def assert_notification(self, type='success', assert_text=None):
         """
         Assert whether we have a notification of particular type

From 26ec6013ca886a1d32293758320cfe6ff883db96 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:56:25 +0100
Subject: [PATCH 08/13] ui_tests: add funcs to add/remove users public SSH key

Add funcs to add/remove users public SSH key.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index afb777cdfb..f09d00a4a4 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1590,6 +1590,34 @@ def get_t_vals(t):
             # add multiple at once and test table delete button
             self.add_table_associations(table, keys, delete=True)
 
+    def add_sshkey_to_user(self, user, ssh_key):
+        """
+        Add ssh public key to particular user
+
+        user (str): user to add the key to
+        ssh_key (str): public ssh key
+        """
+        self.navigate_to_entity('user')
+        self.navigate_to_record(user)
+
+        ssh_pub = 'div[name="ipasshpubkey"] button[name="add"]'
+        self.find(ssh_pub, By.CSS_SELECTOR).click()
+        self.wait()
+        self.driver.switch_to.active_element.send_keys(ssh_key)
+        self.dialog_button_click('update')
+        self.facet_button_click('save')
+
+    def delete_user_sshkey(self, user):
+        """
+        Delete ssh public key of particular user
+        """
+        self.navigate_to_entity('user')
+        self.navigate_to_record(user)
+
+        ssh_pub = 'div[name="ipasshpubkey"] button[name="remove"]'
+        self.find(ssh_pub, By.CSS_SELECTOR).click()
+        self.facet_button_click('save')
+
     def has_class(self, el, cls):
         """
         Check if el has CSS class

From 9be366c623d9c03d8f5cee2b24970f40ffd972fc Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 19:02:45 +0100
Subject: [PATCH 09/13] ui_tests: add function to run cmd on UI host

Run shell command on the UI system using "admin"
user's passwd from conf.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index f09d00a4a4..cf7d6ee549 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -31,6 +31,7 @@
 import os
 from functools import wraps
 from nose.plugins.skip import SkipTest
+import paramiko
 
 # pylint: disable=import-error
 from six.moves.urllib.error import URLError
@@ -1618,6 +1619,33 @@ def delete_user_sshkey(self, user):
         self.find(ssh_pub, By.CSS_SELECTOR).click()
         self.facet_button_click('save')
 
+    def run_cmd_on_ui_host(self, cmd):
+        """
+        Run "shell" command on the UI system using "admin" user's passwd from
+        conf.
+        Use only where API does not fit.
+
+        cmd (str): command to run
+        """
+
+        login = self.config.get('ipa_admin')
+        hostname = self.config.get('ipa_server')
+        password = self.config.get('ipa_password')
+
+        try:
+            ssh = paramiko.SSHClient()
+            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+            ssh.connect(hostname=hostname, username=login, password=password)
+            ssh.exec_command(cmd)
+        except paramiko.AuthenticationException:
+            self.skip('Authentication to server {} failed'.format(hostname))
+        except paramiko.SSHException as e:
+            self.skip('Unable to establish SSH connection: {}'.format(e))
+        except Exception as e:
+            self.skip('Unable to proceed: {}'.format(e))
+        finally:
+            ssh.close()
+
     def has_class(self, el, cls):
         """
         Check if el has CSS class

From 6c7c243af23a3f196712d030d6f8e2e86d4dbb2c Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 19:07:20 +0100
Subject: [PATCH 10/13] ui_tests: make associations cancelable

Adjust associations functions to simulate "cancel"
action.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index cf7d6ee549..a26f46268c 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1390,7 +1390,8 @@ def add_table_record(self, name, data, parent=None):
         self.wait_for_request()
 
     def prepare_associations(
-            self, pkeys, facet=None, facet_btn='add', member_pkeys=None):
+            self, pkeys, facet=None, facet_btn='add', member_pkeys=None,
+            confirm_btn='add'):
         """
         Helper function for add_associations and delete_associations
         """
@@ -1405,7 +1406,7 @@ def prepare_associations(
             self.select_record(key, table_name='available')
             self.button_click('add')
 
-        self.dialog_button_click('add')
+        self.dialog_button_click(confirm_btn)
         self.wait_for_request()
 
         if member_pkeys:
@@ -1417,12 +1418,16 @@ def prepare_associations(
 
     def add_associations(
             self, pkeys, facet=None, delete=False, facet_btn='add',
-            member_pkeys=None):
+            member_pkeys=None, confirm_btn='add'):
         """
         Add associations
         """
         check_pkeys = self.prepare_associations(
-            pkeys, facet, facet_btn, member_pkeys)
+            pkeys, facet, facet_btn, member_pkeys, confirm_btn=confirm_btn)
+
+        # we need to return if we want to "cancel" to avoid assert record fail
+        if confirm_btn == 'cancel':
+            return
 
         for key in check_pkeys:
             self.assert_record(key)

From 3b61ca7c33d3ac70e75301d5cef5dd13c780a649 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 22:04:07 +0100
Subject: [PATCH 11/13] ui_tests: test cancel and delete without button

Add "confirm_btn" to cancel dialog and if "None" return
for confirmation with "Enter" key.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index a26f46268c..61523c5754 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1047,7 +1047,7 @@ def navigate_to_record(self, pkey, parent=None, table_name=None, entity=None, fa
 
     def delete_record(
             self, pkeys, fields=None, parent=None, table_name=None,
-            facet_btn='remove'):
+            facet_btn='remove', confirm_btn='ok'):
         """
         Delete records with given pkeys in currently opened search table.
         """
@@ -1072,7 +1072,9 @@ def delete_record(
                 self.facet_button_click(facet_btn)
             if fields:
                 self.fill_fields(fields)
-            self.dialog_button_click('ok')
+            if not confirm_btn:
+                return
+            self.dialog_button_click(confirm_btn)
             self.wait_for_request(n=2)
             self.wait()
 

From 78d19db35b73b820814057525ff9c90be3d85705 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 22:14:49 +0100
Subject: [PATCH 12/13] ui_tests: select_combobox() fixes

Move strict "search_btn" element finding to later so we
do not fail when using combobox without search button.
Also switch open_btn.click() before fill_textbox() as it
is used to close the selection.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/ui_driver.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 61523c5754..acf865b3e2 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -847,19 +847,19 @@ def select_combobox(self, name, value, parent=None, combobox_input=None):
         self.wait_for_request()
 
         list_cnt = self.find('.combobox-widget-list', By.CSS_SELECTOR, cb, strict=True)
-        search_btn = self.find('a[name=search] i', By.CSS_SELECTOR, cb, strict=True)
         opt_s = "select[name=list] option[value='%s']" % value
         option = self.find(opt_s, By.CSS_SELECTOR, cb)
 
         if combobox_input:
             if not option:
-                self.fill_textbox(combobox_input, value, cb)
                 open_btn.click()
+                self.fill_textbox(combobox_input, value, cb)
         else:
             if not option:
                 # try to search
                 self.fill_textbox('filter', value, cb)
-
+                search_btn = self.find('a[name=search] i', By.CSS_SELECTOR, cb,
+                                       strict=True)
                 search_btn.click()
                 self.wait_for_request()
                 option = self.find(opt_s, By.CSS_SELECTOR, cb, strict=True)

From 8f68e89bbcbaf413d63b3c7e1a5100036b6ae865 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Wed, 14 Mar 2018 23:11:47 +0100
Subject: [PATCH 13/13] ui_tests: run ipa-get/rmkeytab command on UI host

Run ipa-get/rmkeytab command on UI host in order to test whether
we have the key un/provisioned.

https://pagure.io/freeipa/issue/7441

Reviewed-By: Petr Vobornik <pvobo...@redhat.com>
---
 ipatests/test_webui/test_service.py | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index d121ad9777..621ebe60cd 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -103,6 +103,32 @@ def add_service(self, service,
         self.wait(0.3)
         self.assert_no_error_dialog()
 
+    def run_keytab_on_host(self, principal, action):
+        """
+        Run ipa-get/rmkeytab command on UI host in order to test whether
+        we have the key un/provisioned.
+
+        Actions:
+
+        'get' for /usr/sbin/ipa-getkeytab
+        'rm' for /usr/sbin/ipa-rmkeytab
+        """
+
+        kt_path = '/tmp/test.keytab'
+
+        if action == 'get':
+            cmd = '/usr/sbin/ipa-getkeytab -p {} -k {}'.format(principal,
+                                                               kt_path)
+            self.run_cmd_on_ui_host(cmd)
+        elif action == 'rm':
+            cmd = '/usr/sbin/ipa-rmkeytab -p {} -k {}'.format(principal,
+                                                              kt_path)
+            kt_rm_cmd = 'rm -f {}'.format(kt_path)
+            self.run_cmd_on_ui_host(cmd)
+            self.run_cmd_on_ui_host(kt_rm_cmd)
+        else:
+            raise ValueError("Bad action specified")
+
 
 @pytest.mark.tier1
 class test_service(sevice_tasks):
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to