On 07/18/2013 01:34 PM, Petr Vobornik wrote:
[PATCH] 431 Web UI integration tests: Add trust tests

[PATCH] 432 Web UI integration tests: Add ui_driver method descriptions

[PATCH] 433 Web UI integration tests: Verify data after add and mod

[PATCH] 434 Web UI integration tests: Compute range sizes to avoid overlaps

Heavily inspired by code from xmlrpc tests.

To obtain ranges, this patch also adds method to execute FreeIPA command
through Web UI.
It uses Web UI instead of ipalib so it doesn't need to care about
authentication on a test-runner machine.

All: https://fedorahosted.org/freeipa/ticket/3744

And now the patches...
--
Petr Vobornik
From ff5099854390ea538f9eda221a82ee98edf7efee Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Wed, 26 Jun 2013 15:18:05 +0200
Subject: [PATCH] Web UI integration tests: Add trust tests

https://fedorahosted.org/freeipa/ticket/3744
---
 ipatests/test_webui/test_realmdomains.py |  2 +-
 ipatests/test_webui/test_trust.py        | 92 ++++++++++++++++++++++++++++++++
 ipatests/test_webui/ui_driver.py         | 40 ++++++++++----
 3 files changed, 124 insertions(+), 10 deletions(-)
 create mode 100644 ipatests/test_webui/test_trust.py

diff --git a/ipatests/test_webui/test_realmdomains.py b/ipatests/test_webui/test_realmdomains.py
index ea898411890e6c92d619377670266201d4012494..7173e13b730556146db27632921a2a007a56e284 100644
--- a/ipatests/test_webui/test_realmdomains.py
+++ b/ipatests/test_webui/test_realmdomains.py
@@ -41,7 +41,7 @@ class test_realmdomains(UI_driver):
         self.wait_for_request()
 
         # delete
-        self.delete_multivalued('associateddomain', 'itest.bar')
+        self.del_multivalued('associateddomain', 'itest.bar')
         self.facet_button_click('update')
         self.dialog_button_click('force')
         self.wait_for_request()
diff --git a/ipatests/test_webui/test_trust.py b/ipatests/test_webui/test_trust.py
new file mode 100644
index 0000000000000000000000000000000000000000..989c83d61e7209483d41fa2cc3c678ca6874a33a
--- /dev/null
+++ b/ipatests/test_webui/test_trust.py
@@ -0,0 +1,92 @@
+# Authors:
+#   Petr Vobornik <pvobo...@redhat.com>
+#
+# Copyright (C) 2013  Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Trust tests
+"""
+
+from ipatests.test_webui.ui_driver import UI_driver
+
+ENTITY = 'trust'
+CONFIG_ENTITY = 'trustconfig'
+
+CONFIG_DATA = {
+    'mod': [
+        ['combobox', 'ipantfallbackprimarygroup', 'admins'],
+    ]
+}
+
+CONFIG_DATA2 = {
+    'mod': [
+        ['combobox', 'ipantfallbackprimarygroup', 'Default SMB Group']
+    ]
+}
+
+class test_trust(UI_driver):
+
+    def __init__(self, *args, **kwargs):
+        super(test_trust, self).__init__(args, kwargs)
+
+        if not self.has_trusts():
+            self.skip('Trusts not configured')
+
+    def get_data(self):
+
+        domain = self.config.get('ad_domain')
+        admin = self.config.get('ad_admin')
+        psw = self.config.get('ad_password')
+
+        data = {
+            'pkey': domain,
+            'add': [
+                ('textbox', 'realm_server', domain),
+                ('textbox', 'realm_admin', admin),
+                ('password', 'realm_passwd', psw),
+            ],
+            'mod': [
+                ('multivalued', 'ipantsidblacklistincoming', [
+                    ('del', 'S-1-5-18'),
+                    ('add', 'S-1-5-21'),
+                ]),
+                ('multivalued', 'ipantsidblacklistoutgoing', [
+                    ('del', 'S-1-5-18'),
+                    ('add', 'S-1-5-21'),
+                ]),
+            ],
+        }
+
+        return data
+
+
+    def test_crud(self):
+        """
+        Basic basic CRUD: trust
+
+        Test establishing trust by using Windows admin credentials
+        """
+        self.init_app()
+        data = self.get_data()
+        self.basic_crud(ENTITY, data)
+
+    def test_config_mod(self):
+        self.init_app()
+        self.navigate_to_entity(CONFIG_ENTITY)
+
+        self.mod_record(CONFIG_ENTITY, CONFIG_DATA)
+        self.mod_record(CONFIG_ENTITY, CONFIG_DATA2)
diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index e7551dea5ebf54d007d18afa806a1cb4d43d2e69..4a0ca1cd12e6d363bcbabf79902b32137bb792f9 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -86,6 +86,7 @@ class UI_driver(object):
             raise nose.SkipTest('Selenium not installed')
 
     def __init__(self, driver=None, config=None):
+        self.request_timeout = 30
         self.driver = driver
         self.config = config
         if not config:
@@ -261,7 +262,7 @@ class UI_driver(object):
 
         for i in range(n):
             self.wait(implicit)
-            WebDriverWait(self.driver, 10).until_not(lambda d: runner.has_active_request())
+            WebDriverWait(self.driver, self.request_timeout).until_not(lambda d: runner.has_active_request())
             self.wait()
         self.wait(d)
 
@@ -586,7 +587,7 @@ class UI_driver(object):
         last = inputs[-1]
         last.send_keys(value)
 
-    def delete_multivalued(self, name, value, parent=None):
+    def del_multivalued(self, name, value, parent=None):
         if not parent:
             parent = self.get_form()
         s = "div[name='%s'].multivalued-widget" % name
@@ -604,7 +605,19 @@ class UI_driver(object):
                 self.wait()
                 clicked = True
 
-        assert clicked, 'Value was not removed'
+        assert clicked, 'Value was not removed: %s' % value
+
+    def fill_multivalued(self, name, instructions, parent=None):
+        """
+        Add or delete a value from multivalued field
+        """
+        for instruction in instructions:
+            t = instruction[0]
+            value = instruction[1]
+            if t == 'add':
+                self.add_multivalued(name, value, parent)
+            else:
+                self.del_multivalued(name, value, parent)
 
 
     def check_option(self, name, value=None, parent=None):
@@ -661,7 +674,7 @@ class UI_driver(object):
         self.wait()
 
 
-    def get_undo_button(self, field, parent):
+    def get_undo_buttons(self, field, parent):
         """
         Get field undo button
         """
@@ -669,8 +682,8 @@ class UI_driver(object):
         if not parent:
             parent = self.get_form()
         s = "div[name='%s'].field span.undo" % (field)
-        undo = self.find(s, By.CSS_SELECTOR, parent, strict=True)
-        return undo
+        undos = self.find(s, By.CSS_SELECTOR, parent, strict=True, all=True)
+        return undos
 
     def get_rows(self, parent=None):
         """
@@ -821,6 +834,8 @@ class UI_driver(object):
                 self.add_table_record(key, val, parent)
             elif type == 'add_table_association':
                 self.add_table_associations(key, val, parent)
+            elif type == 'multivalued':
+                self.fill_multivalued(key, val, parent)
             elif type == 'table':
                 self.select_record(val, parent, key)
             self.wait()
@@ -1266,9 +1281,16 @@ class UI_driver(object):
         """
         Assert that undo button is or is not visible
         """
-        undo = self.get_undo_button(field, parent)
-        state = undo.is_displayed()
-        assert state == visible, 'Undo button has invalid state. Field: %s' % field
+        undos = self.get_undo_buttons(field, parent)
+        state = False
+        for undo in undos:
+            if undo.is_displayed():
+                state = True
+                break
+        if visible:
+            assert state, "Undo button not visible. Field: %s" % field
+        else:
+            assert not state, "Undo button visible. Field: %s" % field
 
     def assert_visible(self, selector, parent=None, negative=False):
         """
-- 
1.8.3.1

From 98edd947838fec1c2680f395ed23e8c7e013205c Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Wed, 26 Jun 2013 16:10:35 +0200
Subject: [PATCH] Web UI integration tests: Add ui_driver method descriptions

https://fedorahosted.org/freeipa/ticket/3744
---
 ipatests/test_webui/ui_driver.py | 91 ++++++++++++++++++++++++++++++++++------
 1 file changed, 78 insertions(+), 13 deletions(-)

diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 4a0ca1cd12e6d363bcbabf79902b32137bb792f9..20ccd93a7ff1b1b8a0cf9b47efe0eac7db133ba6 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -231,16 +231,28 @@ class UI_driver(object):
         return result
 
     def files_loaded(self):
+        """
+        Test if dependencies were loaded. (Checks if UI has been rendered)
+        """
         indicator = self.find("span.network-activity-indicator", By.CSS_SELECTOR)
         return indicator is not None
 
     def has_ca(self):
+        """
+        FreeIPA server was installed without CA.
+        """
         return 'no_ca' not in self.config
 
     def has_dns(self):
+        """
+        FreeIPA server was installed without DNS.
+        """
         return 'no_dns' not in self.config
 
     def has_trusts(self):
+        """
+        FreeIPA server was installed with Trusts.
+        """
         return 'has_trusts' in self.config
 
     def has_active_request(self):
@@ -252,6 +264,9 @@ class UI_driver(object):
         return displayed
 
     def wait(self, seconds=0.2):
+        """
+        Wait specific amount of seconds
+        """
         time.sleep(seconds)
 
     def wait_for_request(self, implicit=0.2, n=1, d=0):
@@ -285,6 +300,9 @@ class UI_driver(object):
         self.wait_for_request(n=5)
 
     def load(self):
+        """
+        Navigate to Web UI first page and wait for loading of all dependencies.
+        """
         self.driver.get(self.get_base_url())
         runner = self
         WebDriverWait(self.driver, 10).until(lambda d: runner.files_loaded())
@@ -315,7 +333,7 @@ class UI_driver(object):
 
     def get_auth_dialog(self):
         """
-        Return reference to authentication dialog
+        Get reference to authentication dialog
         """
         return self.find('unauthorized_dialog', 'id')
 
@@ -381,6 +399,9 @@ class UI_driver(object):
         return '/'.join(url)
 
     def get_base_url(self):
+        """
+        Get FreeIPA Web UI url
+        """
         host = self.config.get('ipa_server')
         if not host:
             self.skip('FreeIPA server hostname not configured')
@@ -472,7 +493,6 @@ class UI_driver(object):
         """
         Click on link with given text and parent.
         """
-
         if not parent:
             parent = self.get_form()
 
@@ -500,6 +520,9 @@ class UI_driver(object):
         self._button_click(s, dialog, name)
 
     def action_button_click(self, name, parent):
+        """
+        Click on .action-button
+        """
         if not parent:
             parent = self.get_form()
 
@@ -507,6 +530,9 @@ class UI_driver(object):
         self._button_click(s, parent, name)
 
     def button_click(self, name, parent=None):
+        """
+        Click on .ui-button
+        """
         if not parent:
             parent = self.get_form()
 
@@ -531,6 +557,9 @@ class UI_driver(object):
         return form
 
     def select(self, selector, value, parent=None):
+        """
+        Select option with given value in select element
+        """
         if not parent:
             parent = self.get_form()
         el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
@@ -541,7 +570,6 @@ class UI_driver(object):
         Clear and enter text into input defined by selector.
         Use for non-standard fields.
         """
-
         if not parent:
             parent = self.get_form()
         tb = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
@@ -549,7 +577,9 @@ class UI_driver(object):
         tb.send_keys(value)
 
     def fill_input(self, name, value, type="text", parent=None):
-
+        """
+        Type into input element specified by name and type.
+        """
         s = "div[name='%s'] input[type='%s'][name='%s']" % (name, type, name)
         self.fill_text(s, value, parent)
 
@@ -574,7 +604,7 @@ class UI_driver(object):
 
     def add_multivalued(self, name, value, parent=None):
         """
-        Adds new value to multivalued textbox
+        Add new value to multivalued textbox
         """
         if not parent:
             parent = self.get_form()
@@ -588,6 +618,9 @@ class UI_driver(object):
         last.send_keys(value)
 
     def del_multivalued(self, name, value, parent=None):
+        """
+        Mark value in multivalued textbox as deleted.
+        """
         if not parent:
             parent = self.get_form()
         s = "div[name='%s'].multivalued-widget" % name
@@ -624,7 +657,6 @@ class UI_driver(object):
         """
         Find checkbox or radio with name which matches ^NAME\d$
         """
-
         if not parent:
             parent = self.get_form()
         s =  "//input[@type='checkbox' or 'radio'][contains(@name, '%s')]" % name
@@ -678,7 +710,6 @@ class UI_driver(object):
         """
         Get field undo button
         """
-
         if not parent:
             parent = self.get_form()
         s = "div[name='%s'].field span.undo" % (field)
@@ -689,7 +720,6 @@ class UI_driver(object):
         """
         Return all rows of search table.
         """
-
         if not parent:
             parent = self.get_form()
 
@@ -699,6 +729,9 @@ class UI_driver(object):
         return rows
 
     def navigate_to_row_record(self, row, pkey_column=None):
+        """
+        Navigate to record by clicking on a link.
+        """
         s = 'a'
         if pkey_column:
             s = "div[name='%s'] a" % pkey_column
@@ -708,6 +741,9 @@ class UI_driver(object):
         self.wait_for_request()
 
     def get_table_selector(self, name=None):
+        """
+        Construct table selector
+        """
         s = "table"
         if name:
             s += "[name='%s']" % name
@@ -728,6 +764,9 @@ class UI_driver(object):
         self.wait()
 
     def has_record(self, pkey, parent=None, table_name=None):
+        """
+        Check if table contains specific record.
+        """
         if not parent:
             parent = self.get_form()
 
@@ -741,7 +780,6 @@ class UI_driver(object):
         Clicks on record with given pkey in search table and thus cause
         navigation to the record.
         """
-
         if entity:
             self.navigate_to_entity(entity, facet)
 
@@ -843,6 +881,13 @@ class UI_driver(object):
                 self.assert_undo_button(key, True, parent)
 
     def find_record(self, entity, data, facet='search', dummy='XXXXXXX'):
+        """
+        Test search functionality of search facet.
+
+        1. search for non-existent value and test if result set is empty.
+        2. search for specific pkey and test if it's present on the page
+        3. reset search page by not using search criteria
+        """
 
         self.assert_facet(entity, facet)
 
@@ -1045,7 +1090,6 @@ class UI_driver(object):
         """
         Add associations
         """
-
         if facet:
             self.switch_to_facet(facet)
 
@@ -1066,7 +1110,9 @@ class UI_driver(object):
                 self.assert_record(key, negative=True)
 
     def add_table_associations(self, table_name, pkeys, parent=False, delete=False):
-
+        """
+        Add value to table (association|rule|...)
+        """
         if not parent:
             parent = self.get_form()
 
@@ -1093,7 +1139,9 @@ class UI_driver(object):
                 self.assert_record(key, parent, table_name, negative=True)
 
     def action_list_action(self, name):
-
+        """
+        Execute action list action
+        """
         cont = self.find(".active-facet .facet-action-list", By.CSS_SELECTOR, strict=True)
         select = self.find("select[name=action]", By.CSS_SELECTOR, cont, strict=True)
         Select(select).select_by_value(name)
@@ -1101,6 +1149,9 @@ class UI_driver(object):
         self.wait()
 
     def action_panel_action(self, panel_name, action):
+        """
+        Execute action from action panel with given name.
+        """
         s = "div[data-name='%s'].action-panel" % panel_name
         s += " a[data-name='%s']" % action
         link = self.find(s, By.CSS_SELECTOR, strict=True)
@@ -1108,6 +1159,9 @@ class UI_driver(object):
         self.wait()
 
     def enable_action(self):
+        """
+        Execute and test 'enable' action panel action.
+        """
         title = self.find('.active-facet div.facet-title', By.CSS_SELECTOR, strict=True)
         self.action_list_action('enable')
         self.wait_for_request(n=2)
@@ -1115,6 +1169,9 @@ class UI_driver(object):
         self.assert_class(title, 'disabled', negative=True)
 
     def disable_action(self):
+        """
+        Execute and test 'disable' action panel action.
+        """
         title = self.find('.active-facet div.facet-title', By.CSS_SELECTOR, strict=True)
         self.action_list_action('disable')
         self.wait_for_request(n=2)
@@ -1122,6 +1179,9 @@ class UI_driver(object):
         self.assert_class(title, 'disabled')
 
     def delete_action(self, entity, pkey, facet='search'):
+        """
+        Execute and test 'delete' action panel action.
+        """
         self.action_list_action('delete')
         self.wait_for_request(n=4)
         self.assert_no_error_dialog()
@@ -1132,7 +1192,6 @@ class UI_driver(object):
         """
         Test functionality of rule table widgets in a facet
         """
-
         def get_t_vals(t):
             table = t[0]
             k = t[1]
@@ -1186,6 +1245,9 @@ class UI_driver(object):
 
 
     def skip(self, reason):
+        """
+        Skip tests
+        """
         raise nose.SkipTest(reason)
 
     def assert_text(self, selector, value, parent=None):
@@ -1343,5 +1405,8 @@ class UI_driver(object):
             assert valid, "Element doesn't contain required class: %s" % cls
 
     def assert_rule_tables_enabled(self, tables, enabled):
+        """
+        Assert that rule table is editable - values can be added and removed.
+        """
         for table in tables:
             self.assert_table_button_enabled('add', table, enabled)
-- 
1.8.3.1

From e5607a5eece97373c5cbefbe3cf2197b03cca85e Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Thu, 27 Jun 2013 09:45:17 +0200
Subject: [PATCH] Web UI integration tests: Verify data after add and mod

https://fedorahosted.org/freeipa/ticket/3744
---
 ipatests/test_webui/data_user.py |  16 ++++++
 ipatests/test_webui/ui_driver.py | 119 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 128 insertions(+), 7 deletions(-)

diff --git a/ipatests/test_webui/data_user.py b/ipatests/test_webui/data_user.py
index c44eb430791d3ab7fa7f44d37ec8d6d905cecef6..f7fa3c7d2a1fd2c7b9f2dfe4fd483da0414ab5c7 100644
--- a/ipatests/test_webui/data_user.py
+++ b/ipatests/test_webui/data_user.py
@@ -28,9 +28,25 @@ DATA = {
         ('textbox', 'givenname', 'Name'),
         ('textbox', 'sn', 'Surname'),
     ],
+    'add_v': [
+        ('textbox', 'givenname', 'Name'),
+        ('textbox', 'sn', 'Surname'),
+        ('label', 'uid', PKEY),
+    ],
     'mod': [
         ('textbox', 'givenname','OtherName'),
         ('textbox', 'sn','OtherSurname'),
+        ('multivalued', 'telephonenumber', [
+            ('add', '123456789'),
+            ('add', '987654321'),
+        ]),
+        ('combobox', 'manager', 'admin'),
+    ],
+    'mod_v': [
+        ('textbox', 'givenname','OtherName'),
+        ('textbox', 'sn','OtherSurname'),
+        ('multivalued', 'telephonenumber', ['123456789', '987654321']),
+        ('combobox', 'manager', 'admin'),
     ],
 }
 
diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 20ccd93a7ff1b1b8a0cf9b47efe0eac7db133ba6..19363b8963afd1e4c444f2613edee6c8d0ac64b7 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -705,6 +705,60 @@ class UI_driver(object):
 
         self.wait()
 
+    def get_text(self, selector, parent=None):
+        if not parent:
+            parent = self.get_form()
+
+        el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
+        return el.text
+
+    def get_value(self, selector, parent=None):
+        if not parent:
+            parent = self.get_form()
+        el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
+        value = el.get_attribute('value')
+        return value
+
+    def get_field_text(self, name, parent=None, element='label'):
+
+        s = "div[name='%s'] %s[name='%s']" % (name, element, name)
+        return self.get_text(s, parent)
+
+    def get_field_value(self, name, parent=None, element='input'):
+        s = "div[name='%s'] %s[name='%s']" % (name, element, name)
+        return self.get_value(s, parent)
+
+    def get_multivalued_value(self, name, parent=None):
+
+        s = "div[name='%s'] div[name='value'] input[name^='%s']" % (name, name)
+        els = self.find(s, By.CSS_SELECTOR, parent, all=True)
+        values = []
+        for el in els:
+            values.append(el.get_attribute('value'))
+        return values
+
+    def get_field_checked(self, name, parent=None):
+        if not parent:
+            parent = self.get_form()
+        s = "div[name='%s'] input[name='%s']" % (name, name)
+        els = self.find(s, By.CSS_SELECTOR, parent, strict=True, all=True)
+        values = []
+        for el in els:
+            if el.is_selected():
+                values.append(el.get_attribute('value'))
+        return values
+
+    def get_field_selected(self, name, parent=None):
+        if not parent:
+            parent = self.get_form()
+        s = "div[name='%s'] select[name='%s']" % (name, name)
+        el = self.find(s, By.CSS_SELECTOR, parent, strict=True)
+        select = Select(el)
+        selected = select.all_selected_options
+        values = []
+        for opt in selected:
+            values.append(opt.get_attribute('value'))
+        return values
 
     def get_undo_buttons(self, field, parent):
         """
@@ -880,6 +934,60 @@ class UI_driver(object):
             if undo:
                 self.assert_undo_button(key, True, parent)
 
+    def validate_fields(self, fields, parent=None, undo=False):
+        """
+        Validate that fields on a page or dialog have desired values.
+        """
+        if not fields:
+            return
+        if not parent:
+            parent = self.get_form()
+
+        for field in fields:
+            ftype = field[0]
+            key = field[1]
+            expected = field[2]
+            actual = None
+
+            if ftype == 'label':
+                actual = self.get_field_text(key, parent)
+            elif ftype == 'textbox':
+                actual = self.get_field_value(key, parent, 'input')
+            elif ftype == 'textarea':
+                actual = self.get_field_value(key, parent, 'textarea')
+            elif ftype == 'password':
+                actual = self.get_field_value(key, parent, 'input')
+            elif ftype == 'radio':
+                actual = self.get_field_checked(key, parent)
+            elif ftype == 'checkbox':
+                actual = self.get_field_checked(key, parent)
+            elif ftype == 'combobox':
+                actual = self.get_field_value(key, parent, 'input')
+            elif ftype == 'multivalued':
+                actual = self.get_multivalued_value(key, parent)
+            elif ftype == 'table_record':
+                if self.has_record(expected, parent, key):
+                    actual = expected
+
+            valid = False
+            if type(expected) == list:
+                # compare lists:
+                if type(actual) == list and len(expected) == len(actual):
+                    if expected:
+                        valid = True
+                        for val in expected:
+                            if val not in actual:
+                                valid = False
+                                break
+                    else:
+                        valid = True
+            else:
+                # compare other values, usually strings:
+                valid = actual == expected
+
+            assert valid, "Values don't match. Expected: '%s', Got: '%s'" % (expected, actual)
+
+
     def find_record(self, entity, data, facet='search', dummy='XXXXXXX'):
         """
         Test search functionality of search facet.
@@ -1056,9 +1164,9 @@ class UI_driver(object):
 
         # 4. Mod values
         if data.get('mod'):
-            # TODO: assert values
+            self.validate_fields(data.get('add_v'))
             self.mod_record(entity, data, details_facet, update_btn)
-            # TODO: assert modified values
+            self.validate_fields(data.get('mod_v'))
 
         if not breadcrumb:
             self.navigate_to_entity(entity, search_facet)
@@ -1254,11 +1362,8 @@ class UI_driver(object):
         """
         Assert read-only text value in details page or in a form
         """
-        if not parent:
-            parent = self.get_form()
-
-        el = self.find(selector, By.CSS_SELECTOR, parent, strict=True)
-        text = el.text.strip()
+        text = self.get_text(selector, parent)
+        text = text.strip()
         value = value.strip()
         assert text == value, "Invalid value: '%s' Expected: %s" % (text, value)
 
-- 
1.8.3.1

From 9639f27d31dd5b5ac3937012e8b0f1388d40aa9e Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Wed, 17 Jul 2013 10:47:57 +0200
Subject: [PATCH] Web UI integration tests: Compute range sizes to avoid
 overlaps

Heavily inspired by code from xmlrpc tests.

To obtain ranges, this patch also adds method to execute FreeIPA command through Web UI.
It uses Web UI instead of ipalib so it doesn't need to care about authentication on a test-runner machine.

https://fedorahosted.org/freeipa/ticket/3744
---
 ipatests/test_webui/test_range.py | 68 +++++++++++++++++++++++++++++++--------
 ipatests/test_webui/ui_driver.py  | 25 ++++++++++++++
 2 files changed, 79 insertions(+), 14 deletions(-)

diff --git a/ipatests/test_webui/test_range.py b/ipatests/test_webui/test_range.py
index baa53cbaa293536c8500ec2a3eaaec7360072085..ce367c70a5083b1f63f9c75832bb1b7aa315171e 100644
--- a/ipatests/test_webui/test_range.py
+++ b/ipatests/test_webui/test_range.py
@@ -25,25 +25,65 @@ from ipatests.test_webui.ui_driver import UI_driver
 
 ENTITY = 'idrange'
 PKEY = 'itest-range'
-DATA = {
-    'pkey': PKEY,
-    'add': [
-        ('textbox', 'cn', PKEY),
-        ('textbox', 'ipabaseid', '900000'),
-        ('textbox', 'ipaidrangesize', '99999'),
-        ('textbox', 'ipabaserid', '10000'),
-        ('textbox', 'ipasecondarybaserid', '200000'),
-    ],
-    'mod': [
-        ('textbox', 'ipaidrangesize', '100000'),
-    ],
-}
 
 class test_range(UI_driver):
 
+    def get_shifts(self, idranges=None):
+
+        if not idranges:
+            result = self.execute_api_from_ui('idrange_find', [], {})
+            idranges = result['result']['result']
+
+        id_shift = 0
+        rid_shift = 0
+
+        for idrange in idranges:
+            size = int(idrange['ipaidrangesize'][0])
+            base_id = int(idrange['ipabaseid'][0])
+
+            id_end = base_id + size
+            rid_end = 0
+
+            if 'ipabaserid' in idrange:
+                base_rid = int(idrange['ipabaserid'][0])
+                rid_end = base_rid + size
+
+            if 'ipasecondarybaserid' in idrange:
+                secondary_base_rid = int(idrange['ipasecondarybaserid'][0])
+                rid_end = max(base_rid, secondary_base_rid) + size
+
+            if id_shift < id_end:
+                id_shift = id_end + 1000000
+
+            if rid_shift < rid_end:
+                rid_shift = rid_end + 1000000
+
+        self.id_shift = id_shift
+        self.rid_shift = rid_shift
+        self.sec_rid_shift = rid_shift + 1000;
+        self.shift = 0;
+
+    def get_data(self, pkey, size=50, shift=100):
+        self.shift += shift;
+        data = {
+            'pkey': pkey,
+            'add': [
+                ('textbox', 'cn', pkey),
+                ('textbox', 'ipabaseid', str(self.id_shift + self.shift)),
+                ('textbox', 'ipaidrangesize', str(size)),
+                ('textbox', 'ipabaserid', str(self.rid_shift + self.shift)),
+                ('textbox', 'ipasecondarybaserid', str(self.sec_rid_shift + self.shift)),
+            ],
+            'mod': [
+                ('textbox', 'ipaidrangesize', str(size+1)),
+            ],
+        }
+        return data
+
     def test_crud(self):
         """
         Basic CRUD: range
         """
         self.init_app()
-        self.basic_crud(ENTITY, DATA)
+        self.get_shifts()
+        self.basic_crud(ENTITY, self.get_data(PKEY))
diff --git a/ipatests/test_webui/ui_driver.py b/ipatests/test_webui/ui_driver.py
index 19363b8963afd1e4c444f2613edee6c8d0ac64b7..9ea2ba7322f1f219e6213ab34de12d3464ca864f 100644
--- a/ipatests/test_webui/ui_driver.py
+++ b/ipatests/test_webui/ui_driver.py
@@ -489,6 +489,31 @@ class UI_driver(object):
             }
         return info
 
+    def execute_api_from_ui(self, method, args, options, timeout=30):
+        """
+        Executes FreeIPA API command/method from Web UI
+        """
+        script = """
+        var method = arguments[0];
+        var args = arguments[1];
+        var options = arguments[2];
+        var callback = arguments[arguments.length - 1];
+        var IPA = require('freeipa/ipa');
+
+        var cmd = IPA.command({
+            method: method,
+            args: args,
+            options: options,
+            on_success: callback,
+            on_error: callback
+        });
+
+        cmd.execute();
+        """
+        self.driver.set_script_timeout(timeout)
+        result = self.driver.execute_async_script(script, *[method, args, options])
+        return result
+
     def click_on_link(self, text, parent=None):
         """
         Click on link with given text and parent.
-- 
1.8.3.1

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to