From d927a517aa87ed64217077714b0021cceed62df9 Mon Sep 17 00:00:00 2001 From: Yogesh Mahajan Date: Thu, 21 May 2020 19:44:28 +0530 Subject: [PATCH] Fixed feature test failures on the selenium grid for concurrent execution. --- tools/update_selenoid_browsers.py | 11 ++- .../feature_tests/file_manager_test.py | 4 + .../pg_datatype_validation_test.py | 12 ++- .../xss_checks_panels_and_query_tool_test.py | 40 +++++++--- web/regression/feature_utils/pgadmin_page.py | 73 +++++++++++++++---- .../python_test_utils/test_utils.py | 30 ++++++-- web/regression/runtests.py | 2 +- 7 files changed, 132 insertions(+), 40 deletions(-) diff --git a/tools/update_selenoid_browsers.py b/tools/update_selenoid_browsers.py index c06762116..bf0c39850 100644 --- a/tools/update_selenoid_browsers.py +++ b/tools/update_selenoid_browsers.py @@ -92,14 +92,17 @@ def get_browser_version(browser_name, executable_path): # Mozilla Firefox 75.0 if 'esr' in version_str: firefox_version = '.'.join( - version_str.split()[-1].split('.')[:-2]) + '.0' + version_str.split('esr')[0].split()[-1].split('.')[:-1]) else: firefox_version = '.'.join( - version_str.split()[-1].split('.')[:-1]) + '.0' + version_str.split()[-1].split('.')[:-1]) + + if firefox_version.count('.') == 0: + firefox_version = firefox_version + '.0' # Make sure browser version has only 1 decimal point if firefox_version.count('.') != 1: - print('The specified Chrome executable output an unexpected ' + print('The specified Firefox executable output an unexpected ' 'version string: {}.'.format(version_str)) sys.exit(1) browser_version_val = firefox_version @@ -215,7 +218,7 @@ def edit_browsers_json(browser_name, browser_version): data_to_insert = dict( {browser_version: { 'image': 'selenoid/vnc_firefox:' + browser_version, - 'port': '4444', 'path': '/'}}) + 'port': '4444', 'path': '/wd/hub'}}) (existing_data['firefox']['versions']).update(data_to_insert) updated_data = existing_data else: diff --git a/web/pgadmin/feature_tests/file_manager_test.py b/web/pgadmin/feature_tests/file_manager_test.py index 33f86ad86..157e9d4fb 100644 --- a/web/pgadmin/feature_tests/file_manager_test.py +++ b/web/pgadmin/feature_tests/file_manager_test.py @@ -71,6 +71,8 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): self.page.find_by_css_selector(QueryToolLocators.btn_save_file) \ .click() # Set the XSS value in input + WebDriverWait(self.driver, 10).until(EC.presence_of_element_located( + (By.CSS_SELECTOR, ".change_file_types"))) self.page.find_by_css_selector('.change_file_types') self.page.fill_input_by_css_selector( QueryToolLocators.input_file_path_css, self.XSS_FILE) @@ -82,6 +84,8 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): load_file = self.page.find_by_css_selector( QueryToolLocators.btn_load_file_css) load_file.click() + WebDriverWait(self.driver, 10).until(EC.presence_of_element_located( + (By.CSS_SELECTOR, ".change_file_types"))) self.page.find_by_css_selector('.change_file_types') self.page.fill_input_by_css_selector( QueryToolLocators.input_file_path_css, diff --git a/web/pgadmin/feature_tests/pg_datatype_validation_test.py b/web/pgadmin/feature_tests/pg_datatype_validation_test.py index baccc7003..9d6e1efa0 100644 --- a/web/pgadmin/feature_tests/pg_datatype_validation_test.py +++ b/web/pgadmin/feature_tests/pg_datatype_validation_test.py @@ -86,9 +86,15 @@ class PGDataypeFeatureTest(BaseFeatureTest): NavMenuLocators.file_menu_css) file_menu.click() - pref_menu_item = self.page.find_by_css_selector( - NavMenuLocators.preference_menu_item_css) - pref_menu_item.click() + # pref_menu_item = self.page.find_by_css_selector( + # NavMenuLocators.preference_menu_item_css) + # pref_menu_item.click() + + self.page.retry_click( + (By.CSS_SELECTOR, NavMenuLocators.preference_menu_item_css), + (By.XPATH, NavMenuLocators.specified_preference_tree_node + .format('Browser')) + ) wait = WebDriverWait(self.page.driver, 10) diff --git a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py index 69c3cba80..a715a8c61 100644 --- a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py +++ b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py @@ -14,7 +14,8 @@ import random from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest from selenium.webdriver import ActionChains -from selenium.common.exceptions import StaleElementReferenceException +from selenium.common.exceptions import StaleElementReferenceException, \ + WebDriverException from regression.feature_utils.locators import QueryToolLocators from regression.feature_utils.tree_area_locators import TreeAreaLocators @@ -68,10 +69,19 @@ class CheckForXssFeatureTest(BaseFeatureTest): # sometime the tab for dependent does not show info, so refreshing # the page and then again collapsing until the table node - self.page.refresh_page() - self.page.toggle_open_servers_group() - self._tables_node_expandable() - self._check_xss_in_dependents_tab() + retry = 2 + while retry > 0: + try: + self.page.refresh_page() + self.page.toggle_open_servers_group() + self._tables_node_expandable() + self._check_xss_in_dependents_tab() + retry = 0 + except WebDriverException as e: + print("Exception in dependent check {0}".format(retry)) + if retry == 1: + raise e + retry -= 1 # Query tool self.page.open_query_tool() @@ -145,12 +155,22 @@ class CheckForXssFeatureTest(BaseFeatureTest): "\n\tChecking the Dependents tab for XSS vulnerabilities", file=sys.stderr, end="" ) - self.page.click_tab("Dependents") - source_code = self.page.find_by_xpath( - "//*[@id='5']/table/tbody/tr/td/div/div/div[2]/" - "table/tbody/tr/td[2]" - ).get_attribute('innerHTML') + retry = 2 + while retry > 0: + try: + self.page.click_tab("Dependents") + source_code = \ + self.page.find_by_xpath("//*[@id='5']/table/tbody/tr/td/" + "div/div/div[2]/table/tbody/tr/" + "td[2]").get_attribute('innerHTML') + retry = 0 + except WebDriverException as e: + print("Exception in dependent tab {0}") + self.page.click_tab("Dependencies") + if retry == 1: + raise e + retry -= 1 self._check_escaped_characters( source_code, diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py index cce6a27c8..babc78149 100644 --- a/web/regression/feature_utils/pgadmin_page.py +++ b/web/regression/feature_utils/pgadmin_page.py @@ -14,7 +14,7 @@ import sys from selenium import webdriver from selenium.common.exceptions import NoSuchElementException, \ WebDriverException, TimeoutException, NoSuchWindowException, \ - StaleElementReferenceException + StaleElementReferenceException, ElementNotInteractableException from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC @@ -71,12 +71,24 @@ class PgadminPage: def add_server(self, server_config): self.find_by_xpath( "//*[@class='aciTreeText' and contains(.,'Servers')]").click() - self.driver.find_element_by_link_text("Object").click() - ActionChains(self.driver) \ - .move_to_element(self.driver.find_element_by_link_text("Create")) \ - .perform() - self.find_by_partial_link_text("Server...").click() + if self.driver.name == 'firefox': + ActionChains(self.driver).context_click(self.find_by_xpath( + "//*[@class='aciTreeText' and contains(.,'Servers')]"))\ + .perform() + ActionChains(self.driver).move_to_element( + self.find_by_xpath("//li/span[text()='Create']")).perform() + self.find_by_xpath("//li/span[text()='Server...']").click() + else: + self.driver.find_element_by_link_text("Object").click() + ActionChains(self.driver).move_to_element( + self.driver.find_element_by_link_text("Create")).perform() + self.find_by_partial_link_text("Server...").click() + + WebDriverWait(self.driver, 5).until(EC.visibility_of_element_located( + (By.XPATH, "//div[text()='Create - Server']"))) + + # After server dialogue opens self.fill_input_by_field_name("name", server_config['name'], loose_focus=True) self.find_by_partial_link_text("Connection").click() @@ -162,6 +174,11 @@ class PgadminPage: self.click_element(self.find_by_xpath( '//button[contains(@class, "ajs-button") and ' 'contains(.,"Don\'t save")]')) + + if self.check_if_element_exist_by_xpath( + "//button[text()='Rollback']", 1): + self.click_element( + self.find_by_xpath("//button[text()='Rollback']")) self.driver.switch_to.default_content() def clear_query_tool(self): @@ -200,6 +217,12 @@ class PgadminPage: def check_execute_option(self, option): """"This function will check auto commit or auto roll back based on user input. If button is already checked, no action will be taken""" + query_options = self.driver.find_element_by_css_selector( + QueryToolLocators.btn_query_dropdown) + expanded = query_options.get_attribute("aria-expanded") + if expanded == "false": + query_options.click() + retry = 3 if option == 'auto_commit': check_status = self.driver.find_element_by_css_selector( @@ -232,6 +255,12 @@ class PgadminPage: def uncheck_execute_option(self, option): """"This function will uncheck auto commit or auto roll back based on user input. If button is already unchecked, no action will be taken""" + query_options = self.driver.find_element_by_css_selector( + QueryToolLocators.btn_query_dropdown) + expanded = query_options.get_attribute("aria-expanded") + if expanded == "false": + query_options.click() + retry = 3 if option == 'auto_commit': check_status = self.driver.find_element_by_css_selector( @@ -917,17 +946,29 @@ class PgadminPage: except (NoSuchElementException, WebDriverException): return False time.sleep(1) - self.driver.switch_to.default_content() - self.driver.switch_to_frame( - self.driver.find_element_by_tag_name("iframe")) - self.find_by_xpath("//a[text()='Query Editor']").click() - codemirror_ele = WebDriverWait( - self.driver, timeout=self.timeout, poll_frequency=0.01)\ - .until(find_codemirror, - "Timed out waiting for codemirror to appear") + self.wait_for_query_tool_loading_indicator_to_disappear(12) - time.sleep(1) - codemirror_ele.click() + retry = 2 + while retry > 0: + try: + self.driver.switch_to.default_content() + WebDriverWait(self.driver, 10).until( + EC.frame_to_be_available_and_switch_to_it( + (By.TAG_NAME, "iframe"))) + self.find_by_xpath("//a[text()='Query Editor']").click() + + codemirror_ele = WebDriverWait( + self.driver, timeout=self.timeout, poll_frequency=0.01) \ + .until(find_codemirror, + "Timed out waiting for codemirror to appear") + codemirror_ele.click() + retry = 0 + except WebDriverException as e: + print("Exception in filling code mirror {0} ".format(retry)) + print(str(e)) + if retry == 0: + raise e + retry -= 1 # Use send keys if input_keys true, else use javascript to set content if input_keys: diff --git a/web/regression/python_test_utils/test_utils.py b/web/regression/python_test_utils/test_utils.py index b292472b6..78dbfa6af 100644 --- a/web/regression/python_test_utils/test_utils.py +++ b/web/regression/python_test_utils/test_utils.py @@ -29,6 +29,7 @@ import json from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.support import expected_conditions as ec +import selenium.common.exceptions import config import regression @@ -1262,7 +1263,8 @@ def get_selenium_grid_status_and_browser_list(selenoid_url): if browser["version"] is None: print("Specified version of browser is None. Hence " "latest version of {0} available with selenoid " - "server will be used.\n".format(browser["name"])) + "server will be used.\n".format(browser["name"]), + file=sys.stderr) browser_list.append(browser) elif browser["version"] in versions.keys(): browser_list.append(browser) @@ -1273,10 +1275,11 @@ def get_selenium_grid_status_and_browser_list(selenoid_url): print("Specified Version = {0}".format( browser["version"])) else: - print("{0} is NOT available".format(browser["name"])) + print("{0} is NOT available".format(browser["name"]), + file=sys.stderr) except Exception as e: (str(e)) - print("Unable to find Selenoid Status") + print("Unable to find Selenoid Status", file=sys.stderr) return selenoid_status, browser_list @@ -1299,7 +1302,7 @@ def is_feature_test_included(arguments): return feature_test_tobe_included -def launch_url_in_browser(driver_instance, url, title='pgAdmin 4', timeout=40): +def launch_url_in_browser(driver_instance, url, title='pgAdmin 4', timeout=50): """ Function launches urls in specified driver instance :param driver_instance:browser instance @@ -1338,7 +1341,6 @@ def get_remote_webdriver(hub_url, browser, browser_ver, test_name): test_name = browser + browser_ver + "_" + test_name + "-" + time.strftime( "%m_%d_%y_%H_%M_%S", time.localtime()) driver_local = None - desired_capabilities = { "version": browser_ver, "enableVNC": True, @@ -1347,7 +1349,8 @@ def get_remote_webdriver(hub_url, browser, browser_ver, test_name): "videoName": test_name + ".mp4", "logName": test_name + ".log", "name": test_name, - "timeZone": "Asia/Kolkata" + "timeZone": "Asia/Kolkata", + "sessionTimeout": "180s" } if browser == 'firefox': @@ -1467,3 +1470,18 @@ def get_selenium_grid_status_json(selenoid_url): print("Unable to find Selenoid Status.Kindly check url passed -'{0}'". format(selenoid_url)) return None + + +def quit_webdriver(driver): + """ + Function closes webdriver instance + :param driver: + """ + try: + driver.quit() + except selenium.common.exceptions.InvalidSessionIdException: + print("Driver object is already closed.") + except Exception as e: + print("Some Other exception occurred.") + traceback.print_exc(file=sys.stderr) + print(str(e)) diff --git a/web/regression/runtests.py b/web/regression/runtests.py index 8759be301..d233b1c63 100644 --- a/web/regression/runtests.py +++ b/web/regression/runtests.py @@ -510,7 +510,7 @@ def execute_test(test_module_list_passed, server_passed, driver_passed): # Delete web-driver instance thread_name = "parallel_tests" + server_passed['name'] if threading.currentThread().getName() == thread_name: - driver_passed.quit() + test_utils.quit_webdriver(driver_passed) time.sleep(20) # Print info about completed tests