URL: https://github.com/freeipa/freeipa/pull/1679
Author: Rezney
 Title: #1679: WebUI tests: test_service
Action: opened

PR body:
"""
Extension of test_service WebUI tests.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1679/head:pr1679
git checkout pr1679
From e998332ac0f407a3421c137a7989e6f5df01e2c6 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/14] 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
---
 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 c7bcc8e25aff32319b93b49f046df5a0330c8541 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/14] 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
---
 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 d90def572873e0fe8b90889a8066158b1d99de78 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/14] ui_tests: add_service() support func in test_service

Add add_service() support func into test_service.

https://pagure.io/freeipa/issue/7441
---
 ipatests/test_webui/test_service.py | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index cc7f8b1ccb..ab88f865e0 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -70,6 +70,30 @@ 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.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 e78b98e44715f714164a7761ef939608cc4595ec 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/14] 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
---
 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 ab88f865e0..75d668b776 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -111,8 +111,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():
@@ -133,6 +133,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')
@@ -166,7 +169,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()
@@ -185,6 +195,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)
@@ -202,6 +217,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 397e932574c57506bfcabc2aac6008a6e050d5f5 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/14] ui_tests: add more test cases

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

https://pagure.io/freeipa/issue/7441
---
 ipatests/test_webui/test_service.py | 463 ++++++++++++++++++++++++++++++++++++
 1 file changed, 463 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 75d668b776..8a856984b6 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -23,6 +23,9 @@
 
 from ipatests.test_webui.ui_driver import UI_driver
 from ipatests.test_webui.ui_driver import screenshot
+from selenium.webdriver.common.keys import Keys
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.action_chains import ActionChains
 import pytest
 
 ENTITY = 'service'
@@ -352,3 +355,463 @@ 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_cifs_service(self):
+        """
+        Test add CIFS service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('cifs')
+        self.add_service('cifs')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_dns_service(self):
+        """
+        Test add DNS service using combobox
+        """
+        self.init_app()
+        temp_host = 'host-no-dns.ipa.test'
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+        pkey = self.get_service_pkey('DNS', host=temp_host)
+        self.add_service('DNS', host=temp_host, force=True)
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @screenshot
+    def test_add_ftp_service(self):
+        """
+        Test add FTP service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('ftp')
+        self.add_service('ftp')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_http_service(self):
+        """
+        Test add HTTP service using combobox
+        """
+        self.init_app()
+        temp_host = 'host-no-dns.ipa.test'
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+        pkey = self.get_service_pkey('HTTP', host=temp_host)
+        self.add_service('HTTP', host=temp_host, force=True)
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @screenshot
+    def test_add_imap_service(self):
+        """
+        Test add IMAP service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('imap')
+        self.add_service('imap')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_ldap_service(self):
+        """
+        Test add LDAP service using combobox
+        """
+        self.init_app()
+        temp_host = 'host-no-dns.ipa.test'
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+        pkey = self.get_service_pkey('ldap', host=temp_host)
+        self.add_service('ldap', host=temp_host, force=True)
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @screenshot
+    def test_add_libvirt_service(self):
+        """
+        Test add libvirt service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('libvirt')
+        self.add_service('libvirt')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_nfs_service(self):
+        """
+        Test add nfs service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('nfs')
+        self.add_service('nfs')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_qpidd_service(self):
+        """
+        Test add qpidd service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('qpidd')
+        self.add_service('qpidd')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_add_smtp_service(self):
+        """
+        Test add smtp service using combobox
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('smtp')
+        self.add_service('smtp')
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @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_force_add_service(self):
+        """
+        Test force add service with host without DNS record
+        """
+        temp_host = 'host-no-dns.ipa.test'
+
+        self.init_app()
+        self.navigate_to_entity('host')
+        self.facet_button_click('add')
+        self.fill_textbox('hostname', 'host-no-dns')
+        self.fill_textbox('dnszone', 'ipa.test')
+        self.check_option('force', 'checked')
+        self.dialog_button_click('add')
+
+        pkey = self.get_service_pkey('test-service-force', host=temp_host)
+        self.add_service('test-service-force', textbox='service',
+                         host=temp_host, force=True)
+        assert self.has_record(pkey)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @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, cancel=True)
+        assert self.has_record(pkey)
+
+    @screenshot
+    def test_delete_single_service(self):
+        """
+        Test delete single service
+        """
+        self.init_app()
+        pkey = self.get_service_pkey('single_service')
+        self.add_service('single_service', textbox='service')
+        assert self.has_record(pkey)
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+    @screenshot
+    def test_delete_multiple_services(self):
+        """
+        Test delete multiple services
+        """
+        self.init_app()
+        cifs_pkey = self.get_service_pkey('cifs')
+        nfs_pkey = self.get_service_pkey('nfs')
+        smtp_pkey = self.get_service_pkey('smtp')
+
+        for service in ('cifs', 'nfs', 'smtp'):
+            self.add_service(service)
+
+        for service in (cifs_pkey, nfs_pkey, smtp_pkey):
+            self.delete_record(service)
+            self.wait(0.5)
+            assert not self.has_record(service)
+
+    @screenshot
+    def test_cancel_add_delete_managedby_host(self):
+        """
+        Test cancel/add/delete managed by host
+        """
+        pkey = self.get_service_pkey('HTTP')
+        host = self.config.get('ipa_server')
+        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',
+                              cancel=True)
+        self.add_associations([temp_host], facet='managedby_host',
+                              delete=True)
+        self.delete_record(host, cancel=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_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, combobox_input='service')
+        self.dialog_button_click('add')
+        self.wait()
+        service_elem = self.find(".widget[name='service']", By.CSS_SELECTOR)
+        self.assert_field_required(parent=service_elem)
+
+    @screenshot
+    def test_add_service_no_DNS_for_host(self):
+        """
+        Add service for a host without dns
+        """
+        self.init_app()
+        temp_host = 'host-no-dns.ipa.test'
+        pkey = self.get_service_pkey('cifs', host=temp_host)
+        self.add_host('host-no-dns', 'ipa.test', force=True)
+        self.add_service('cifs', temp_host, force=True)
+
+        # service cleanup
+        self.delete_record(pkey)
+        self.assert_notification()
+        assert not self.has_record(pkey)
+
+        # host cleanup
+        self.navigate_to_entity('host')
+        self.delete_record(temp_host)
+
+    @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=False)
+        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 a895f0d6d2c950fd53a0ba611a08f4ae7c7210a9 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:45:23 +0100
Subject: [PATCH 06/14] 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
---
 ipatests/test_webui/test_service.py | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/ipatests/test_webui/test_service.py b/ipatests/test_webui/test_service.py
index 8a856984b6..286d4930c4 100644
--- a/ipatests/test_webui/test_service.py
+++ b/ipatests/test_webui/test_service.py
@@ -26,6 +26,7 @@
 from selenium.webdriver.common.keys import Keys
 from selenium.webdriver.common.by import By
 from selenium.webdriver.common.action_chains import ActionChains
+
 import pytest
 
 ENTITY = 'service'
@@ -97,6 +98,27 @@ def add_service(self, service,
         self.dialog_button_click('add')
         self.wait(0.3)
         self.assert_no_error_dialog()
+
+    def run_keytab_on_host(self, pkey, action):
+        """
+        Run ipa-get/rmkeytab command on UI host in order to test whether
+        we have the key un/provisioned.
+        """
+
+        kt_path = '/tmp/test.keytab'
+
+        if action == 'get':
+            cmd = '/usr/sbin/ipa-getkeytab -p {} -k {}'.format(pkey, kt_path)
+            self.run_cmd_on_ui_host(cmd)
+        elif action == 'rm':
+            cmd = '/usr/sbin/ipa-rmkeytab -p {} -k {}'.format(pkey, 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):
 

From c51d31b810c93947a1855c6ed42a6a8015548461 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:51:10 +0100
Subject: [PATCH 07/14] 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
---
 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 71efe6705c..b9c099e414 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1875,3 +1875,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)
+        if assert_text:
+            assert assert_text in is_present.text
+        assert is_present, "Notification not present"

From 30f6ea6c9637997a818bffebb28e8e73e1caf63a Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:52:45 +0100
Subject: [PATCH 08/14] 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
---
 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 b9c099e414..27bf5fcb20 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1876,6 +1876,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_required(self, parent=None):
+        """
+        Assert we got 'Required field' error message
+        """
+
+        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 7fe32a65181a1a32c33635f8eeda0aa20d2ab048 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 18:56:25 +0100
Subject: [PATCH 09/14] 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
---
 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 27bf5fcb20..6ef84266b6 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1615,6 +1615,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_for_request(n=5, d=2)
+        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 74a14d99be7165335878043b9566a0a2b681a028 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 19:02:45 +0100
Subject: [PATCH 10/14] ui_tests: add function to run cmd on UI host

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

https://pagure.io/freeipa/issue/7441
---
 ipatests/test_webui/ui_driver.py | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 6ef84266b6..8283090f9b 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -30,6 +30,7 @@
 import os
 from functools import wraps
 import unittest
+import paramiko
 
 # pylint: disable=import-error
 from six.moves.urllib.error import URLError
@@ -1643,6 +1644,31 @@ 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 command on the UI system using "admin" user's passwd from conf.
+
+        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 89c59a437cbdc6b534215faed994d27061f705c8 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 19:07:20 +0100
Subject: [PATCH 11/14] ui_tests: make associations cancelable

Adjust associations functions to simulate "cancel"
action.

https://pagure.io/freeipa/issue/7441
---
 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 8283090f9b..2457b6659e 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1415,7 +1415,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,
+            cancel=False):
         """
         Helper function for add_associations and delete_associations
         """
@@ -1430,6 +1431,9 @@ def prepare_associations(
             self.select_record(key, table_name='available')
             self.button_click('add')
 
+        if cancel:
+            self.dialog_button_click('cancel')
+            return
         self.dialog_button_click('add')
         self.wait_for_request()
 
@@ -1442,13 +1446,14 @@ def prepare_associations(
 
     def add_associations(
             self, pkeys, facet=None, delete=False, facet_btn='add',
-            member_pkeys=None):
+            member_pkeys=None, cancel=False):
         """
         Add associations
         """
         check_pkeys = self.prepare_associations(
-            pkeys, facet, facet_btn, member_pkeys)
-
+            pkeys, facet, facet_btn, member_pkeys, cancel=cancel)
+        if cancel:
+            return
         for key in check_pkeys:
             self.assert_record(key)
             if delete:

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

Add conditions to test cancel of delete record and
confirmation with "Enter" key.

https://pagure.io/freeipa/issue/7441
---
 ipatests/test_webui/ui_driver.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 2457b6659e..2ea06e9144 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -1072,7 +1072,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', cancel=False, confirm=True):
         """
         Delete records with given pkeys in currently opened search table.
         """
@@ -1097,6 +1097,11 @@ def delete_record(
                 self.facet_button_click(facet_btn)
             if fields:
                 self.fill_fields(fields)
+            if cancel:
+                self.dialog_button_click('cancel')
+                return
+            if not confirm:
+                return
             self.dialog_button_click('ok')
             self.wait_for_request(n=2)
             self.wait()

From 9847519ce4efa3d09d1f22fe311609289bcffdb0 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 22:14:49 +0100
Subject: [PATCH 13/14] 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
---
 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 2ea06e9144..196f13fd31 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -872,19 +872,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 ab77352ec7ce5a37081074fff6a2e2536a7cb701 Mon Sep 17 00:00:00 2001
From: Michal Reznik <mrez...@redhat.com>
Date: Tue, 13 Mar 2018 22:28:46 +0100
Subject: [PATCH 14/14] freeipa-pr-ci: enable WebUI tests

enable WebUI tests in PRCI
---
 .freeipa-pr-ci.yaml | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/.freeipa-pr-ci.yaml b/.freeipa-pr-ci.yaml
index b98a27835c..154e2212b5 100644
--- a/.freeipa-pr-ci.yaml
+++ b/.freeipa-pr-ci.yaml
@@ -3,6 +3,10 @@ topologies:
     name: build
     cpu: 2
     memory: 3800
+  ipaserver: &ipaserver
+    name: ipaserver
+    cpu: 1
+    memory: 2400
   master_1repl: &master_1repl
     name: master_1repl
     cpu: 4
@@ -23,7 +27,7 @@ jobs:
         git_refspec: '{git_refspec}'
         template: &ci-master-f27
           name: freeipa/ci-master-f27
-          version: 1.0.2
+          version: 1.0.3
         timeout: 1800
         topology: *build
 
@@ -62,3 +66,15 @@ jobs:
         template: *ci-master-f27
         timeout: 3600
         topology: *master_1repl
+
+  fedora-27/test_webui:
+    requires: [fedora-27/build]
+    priority: 50
+    job:
+      class: RunWebuiTests
+      args:
+        build_url: '{fedora-27/build_url}'
+        test_suite: test_webui/
+        template: *ci-master-f27
+        timeout: 7200
+        topology: *ipaserver
_______________________________________________
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