From 70c95fcdd54923ca173e9e83116616cbcfa221b2 Mon Sep 17 00:00:00 2001 From: Usman Muzaffar Date: Tue, 21 Aug 2018 17:39:36 +0530 Subject: [PATCH] Stabilise feature tests for continuous running on CI systems. Fixes #3136. --- docs/en_US/release_notes_3_3.rst | 1 + ...opy_selected_query_results_feature_test.py | 35 +++----- .../feature_tests/file_manager_test.py | 85 +++++++++++-------- .../pg_datatype_validation_test.py | 25 ++---- .../feature_tests/query_tool_journey_test.py | 43 ++++------ web/pgadmin/feature_tests/query_tool_tests.py | 44 ++++------ .../feature_tests/table_ddl_feature_test.py | 35 +++----- .../feature_tests/view_data_dml_queries.py | 28 ++---- .../xss_checks_panels_and_query_tool_test.py | 31 ++----- .../xss_checks_roles_control_test.py | 1 - .../tools/sqleditor/static/js/sqleditor.js | 16 ++++ web/pgadmin/utils/route.py | 4 + web/regression/feature_utils/pgadmin_page.py | 19 ++++- web/regression/runtests.py | 32 ++++++- 14 files changed, 193 insertions(+), 206 deletions(-) diff --git a/docs/en_US/release_notes_3_3.rst b/docs/en_US/release_notes_3_3.rst index b173d613a..531df4707 100644 --- a/docs/en_US/release_notes_3_3.rst +++ b/docs/en_US/release_notes_3_3.rst @@ -15,6 +15,7 @@ Features Bug fixes ********* +| `Bug #3136 `_ - Stabilise feature tests for continuous running on CI systems. | `Bug #3325 `_ - Fix sort/filter dialog issue where it incorrectly requires ASC/DESC. | `Bug #3407 `_ - Fix keyboard shortcuts layout in the preferences panel. | `Bug #3461 `_ - Ensure that refreshing a node also updates the Property list. diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py index ab54d2896..81228b59d 100644 --- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py +++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py @@ -8,10 +8,10 @@ ########################################################################## import pyperclip +import random from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys - from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest @@ -25,32 +25,29 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): ("Copy rows, column using button and keyboard shortcut", dict()) ] + test_table_name = "" + def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") + + # Create test table with random name to avoid same name conflicts in + # parallel execution + self.test_table_name = "test_table" + str(random.randint(1000, 3000)) + test_utils.create_table( - self.server, "acceptance_test_db", "test_table") + self.server, self.test_db, self.test_table_name) self.page.add_server(self.server) def runTest(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.open_query_tool() self.page.driver.switch_to_frame( self.page.driver.find_element_by_tag_name("iframe")) self.page.fill_codemirror_area_with( - "SELECT * FROM test_table ORDER BY some_column") + "SELECT * FROM %s ORDER BY some_column" % self.test_table_name) self.page.find_by_id("btn-flash").click() @@ -205,13 +202,3 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): def after(self): self.page.close_query_tool() self.page.remove_server(self.server) - - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") diff --git a/web/pgadmin/feature_tests/file_manager_test.py b/web/pgadmin/feature_tests/file_manager_test.py index 9cdce65d8..0c6e03047 100644 --- a/web/pgadmin/feature_tests/file_manager_test.py +++ b/web/pgadmin/feature_tests/file_manager_test.py @@ -11,11 +11,11 @@ from __future__ import print_function import os import time import sys + from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC -from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest @@ -28,15 +28,11 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): ] def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") + if os.name == 'nt': + self.skipTest("This test is skipped for Windows. As Windows " + "does not allow the '<' and '>' character while " + "specifying the file name.") + self.page.add_server(self.server) self.wait = WebDriverWait(self.page.driver, 10) self.XSS_FILE = '/tmp/.sql' @@ -47,14 +43,6 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): def after(self): self.page.close_query_tool('sql', False) self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'] - ) - test_utils.drop_database(connection, "acceptance_test_db") def runTest(self): print("Tests to check if File manager is vulnerable to XSS... ", @@ -72,7 +60,7 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): def _navigate_to_query_tool(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.open_query_tool() def _create_new_file(self): @@ -145,20 +133,49 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): # Added time.sleep so that the element to be clicked. time.sleep(0.05) - self.page.find_by_css_selector("#contents th[data-column='0']").click() - # Check for sort Ascending - self.wait.until( - EC.presence_of_element_located(( - By.CSS_SELECTOR, - "#contents th[data-column='0'].tablesorter-headerAsc") - ) - ) + + # Intermittently facing issue on first click it is not successful + # so tried couple of times. + iteration = 0 + success = False + while not success and iteration < 4: + self.page.find_by_xpath("//th[@data-column='0']" + "/div/span[text()='Name']").click() + # Check for sort Ascending + try: + self.wait.until( + EC.presence_of_element_located(( + By.CSS_SELECTOR, + "#contents th[data-column='0'].tablesorter-headerAsc") + )) + success = True + except Exception as e: + iteration += 1 + + if not success: + raise Exception("Unable to sort in ascending order while clicked " + "on 'Name' column") + + time.sleep(0.05) # Click and Check for sort Descending - self.page.find_by_css_selector("#contents th[data-column='0']").click() - self.wait.until( - EC.presence_of_element_located(( - By.CSS_SELECTOR, - "#contents th[data-column='0'].tablesorter-headerDesc") - ) - ) + # Intermittently facing issue on first click it is not successful + # so tried couple of times. + iteration = 0 + success = False + while not success and iteration < 4: + self.page.find_by_xpath("//th[@data-column='0']" + "/div/span[text()='Name']").click() + try: + self.wait.until( + EC.presence_of_element_located(( + By.CSS_SELECTOR, + "#contents th[data-column='0'].tablesorter-headerDesc") + )) + success = True + except Exception as e: + iteration += 1 + + if not success: + raise Exception("Unable to sort in descending order while clicked " + "on 'Name' column") diff --git a/web/pgadmin/feature_tests/pg_datatype_validation_test.py b/web/pgadmin/feature_tests/pg_datatype_validation_test.py index 3e34c175c..47f716067 100644 --- a/web/pgadmin/feature_tests/pg_datatype_validation_test.py +++ b/web/pgadmin/feature_tests/pg_datatype_validation_test.py @@ -10,6 +10,7 @@ import os import json import time + from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -18,7 +19,6 @@ from selenium.webdriver import ActionChains from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest - CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) try: @@ -48,8 +48,7 @@ class PGDataypeFeatureTest(BaseFeatureTest): self.server['db_password'], self.server['host'], self.server['port'], - self.server['sslmode'] - ) + self.server['sslmode']) self.timezone = int(test_utils.get_timezone_without_dst(connection)) @@ -66,9 +65,6 @@ class PGDataypeFeatureTest(BaseFeatureTest): else: self.timezone_hh_mm = '+{}'.format(self.timezone_hh_mm) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") - self.database_version = connection.server_version # For this test case we need to set "Insert bracket pairs?" @@ -76,6 +72,9 @@ class PGDataypeFeatureTest(BaseFeatureTest): # to add matching closing bracket by it self. self._update_preferences() + # close the db connection + connection.close() + def _update_preferences(self): self.page.find_by_id("mnu_file").click() self.page.find_by_id("mnu_preferences").click() @@ -137,32 +136,24 @@ class PGDataypeFeatureTest(BaseFeatureTest): def after(self): self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") def _schema_node_expandable(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) def _check_datatype(self): # Slick grid does not render all the column if viewport is not enough # wide. So execute test as batch of queries. + self.page.select_tree_item(self.test_db) self.page.open_query_tool() self._create_enum_type() for batch in config_data: query = self.construct_select_query(batch) self.page.fill_codemirror_area_with(query) self.page.find_by_id("btn-flash").click() - wait = WebDriverWait(self.page.driver, 5) + wait = WebDriverWait(self.page.driver, 5) wait.until(EC.presence_of_element_located( (By.XPATH, "//*[contains(@class,'column-type') and " diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py index ec120439a..1393e35e9 100644 --- a/web/pgadmin/feature_tests/query_tool_journey_test.py +++ b/web/pgadmin/feature_tests/query_tool_journey_test.py @@ -8,6 +8,7 @@ ########################################################################## import pyperclip +import random from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys @@ -25,26 +26,18 @@ class QueryToolJourneyTest(BaseFeatureTest): ("Tests the path through the query tool", dict()) ] + test_table_name = "" + def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") + self.test_table_name = "test_table" + str(random.randint(1000, 3000)) test_utils.create_table( - self.server, "acceptance_test_db", "test_table") + self.server, self.test_db, self.test_table_name) self.page.add_server(self.server) def runTest(self): self._navigate_to_query_tool() - self._execute_query( - "SELECT * FROM test_table ORDER BY value" - ) + "SELECT * FROM %s ORDER BY value " % self.test_table_name) self._test_copies_rows() self._test_copies_columns() @@ -100,11 +93,18 @@ class QueryToolJourneyTest(BaseFeatureTest): .perform() selected_history_entry = self.page.find_by_css_selector( "#query_list .selected") - self.assertIn("SELECT * FROM test_table ORDER BY value", + self.assertIn(("SELECT * FROM %s ORDER BY value" % + self.test_table_name), selected_history_entry.text) - selected_history_detail_pane = self.page.find_by_id("query_detail") - self.assertIn("SELECT * FROM test_table ORDER BY value", - selected_history_detail_pane.text) + + query_element = self.page.driver.\ + find_element_by_xpath( + "//div[@id='history_grid']//div[@class='entry selected']" + "/div[@class='query']") + + self.assertIn(("SELECT * FROM %s ORDER BY value" + % self.test_table_name), query_element.text) + newly_selected_history_entry = self.page.find_by_xpath( "//*[@id='query_list']/ul/li[2]") self.page.click_element(newly_selected_history_entry) @@ -167,7 +167,7 @@ class QueryToolJourneyTest(BaseFeatureTest): def _navigate_to_query_tool(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.open_query_tool() def _execute_query(self, query): @@ -180,10 +180,3 @@ class QueryToolJourneyTest(BaseFeatureTest): def after(self): self.page.close_query_tool() self.page.remove_server(self.server) - - connection = test_utils.get_db_connection(self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port']) - test_utils.drop_database(connection, "acceptance_test_db") diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index 226b32313..847ae5abf 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -8,7 +8,6 @@ ########################################################################## from __future__ import print_function -import time import sys from selenium.common.exceptions import StaleElementReferenceException @@ -32,20 +31,11 @@ class QueryToolFeatureTest(BaseFeatureTest): ] def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") self.page.wait_for_spinner_to_disappear() self.page.add_server(self.server) self._locate_database_tree_node() self.page.open_query_tool() + self.page.wait_for_spinner_to_disappear() self._reset_options() def runTest(self): @@ -116,15 +106,6 @@ class QueryToolFeatureTest(BaseFeatureTest): def after(self): self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") def _reset_options(self): # this will set focus to correct iframe. @@ -135,6 +116,10 @@ class QueryToolFeatureTest(BaseFeatureTest): ActionChains(self.driver).move_to_element( query_op.find_element_by_xpath( "//li[contains(.,'Explain Options')]")).perform() + self.page.driver.execute_script( + "arguments[0].scrollIntoView()", + self.page.find_by_xpath( + "//span[normalize-space(text())='Verbose']")) # disable Explain options and auto rollback only if they are enabled. for op in ('explain-verbose', 'explain-costs', @@ -156,7 +141,7 @@ class QueryToolFeatureTest(BaseFeatureTest): def _locate_database_tree_node(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) def _clear_query_tool(self): self.page.click_element( @@ -187,8 +172,6 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format( self.page.find_by_id("btn-flash").click() - # self.page.wait_for_query_tool_loading_indicator_to_disappear() - wait.until(EC.presence_of_element_located( (By.XPATH, '//span[@data-row="0" and text()="1"]')) @@ -210,8 +193,6 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format( file=sys.stderr, end="") self.page.find_by_id("btn-flash").click() - # self.page.wait_for_query_tool_loading_indicator_to_disappear() - wait.until(EC.presence_of_element_located( (By.XPATH, '//span[@data-row="0" and text()="1"]')) @@ -230,7 +211,7 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format( file=sys.stderr, end="") self.page.find_by_id("btn-flash").click() - # self.page.wait_for_query_tool_loading_indicator_to_disappear() + self.page.wait_for_query_tool_loading_indicator_to_disappear() wait.until(EC.presence_of_element_located( (By.XPATH, @@ -275,6 +256,11 @@ SELECT generate_series(1, 1000) as id order by id desc""" query_op.find_element_by_xpath( "//li[contains(.,'Explain Options')]")).perform() + self.page.driver.execute_script( + "arguments[0].scrollIntoView()", + self.page.find_by_xpath( + "//span[normalize-space(text())='Verbose']")) + self.page.find_by_id("btn-explain-verbose").click() self.page.find_by_id("btn-explain-costs").click() @@ -310,6 +296,11 @@ SELECT generate_series(1, 1000) as id order by id desc""" query_op.find_element_by_xpath( "//li[contains(.,'Explain Options')]")).perform() + self.page.driver.execute_script( + "arguments[0].scrollIntoView()", + self.page.find_by_xpath( + "//span[normalize-space(text())='Verbose']")) + self.page.find_by_id("btn-explain-buffers").click() self.page.find_by_id("btn-explain-timing").click() @@ -670,7 +661,6 @@ SELECT 1, pg_sleep(300)""" wait.until(WaitForAnyElementWithText( (By.CSS_SELECTOR, 'td.payload'), "Hello")) print("OK.", file=sys.stderr) - self._clear_query_tool() else: print("Skipped.", file=sys.stderr) diff --git a/web/pgadmin/feature_tests/table_ddl_feature_test.py b/web/pgadmin/feature_tests/table_ddl_feature_test.py index 187600191..dc4da1a99 100644 --- a/web/pgadmin/feature_tests/table_ddl_feature_test.py +++ b/web/pgadmin/feature_tests/table_ddl_feature_test.py @@ -7,6 +7,8 @@ # ########################################################################## +import random + from regression.feature_utils.base_feature_test import BaseFeatureTest from regression.python_test_utils import test_utils @@ -18,46 +20,29 @@ class TableDdlFeatureTest(BaseFeatureTest): ("Test table DDL generation", dict()) ] - def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") + test_table_name = "" - test_utils.create_database(self.server, "acceptance_test_db") + def before(self): self.page.add_server(self.server) def runTest(self): - test_utils.create_table( - self.server, "acceptance_test_db", "test_table") + self.test_table_name = "test_table" + str(random.randint(1000, 3000)) + test_utils.create_table(self.server, self.test_db, + self.test_table_name) self.page.toggle_open_server(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.toggle_open_tree_item('Schemas') self.page.toggle_open_tree_item('public') self.page.toggle_open_tree_item('Tables') - self.page.select_tree_item('test_table') + self.page.select_tree_item(self.test_table_name) self.page.click_tab("SQL") self.page.find_by_xpath( "//*[contains(@class,'CodeMirror-lines') and " - "contains(.,'CREATE TABLE public.test_table')]") + "contains(.,'CREATE TABLE public.%s')]" % self.test_table_name) def after(self): self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py index f5dc65905..3ff28de48 100644 --- a/web/pgadmin/feature_tests/view_data_dml_queries.py +++ b/web/pgadmin/feature_tests/view_data_dml_queries.py @@ -10,6 +10,7 @@ import json import os import time + from selenium.webdriver import ActionChains from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest @@ -87,27 +88,19 @@ CREATE TABLE public.defaults_{0} "COLLATE is not present in PG versions below v9.1" ) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") - # Create pre-requisite table for k, v in {1: 'id', 2: '"ID"'}.items(): test_utils.create_table_with_query( self.server, - "acceptance_test_db", + self.test_db, CheckForViewDataTest.defaults_query.format(k, v)) # Initialize an instance of WebDriverWait with timeout of 3 seconds self.wait = WebDriverWait(self.driver, 3) + # close the db connection + connection.close() + def runTest(self): self.page.wait_for_spinner_to_disappear() self.page.add_server(self.server) @@ -129,15 +122,6 @@ CREATE TABLE public.defaults_{0} def after(self): self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") @staticmethod def _get_cell_xpath(cell, row): @@ -227,7 +211,7 @@ CREATE TABLE public.defaults_{0} def _tables_node_expandable(self): self.page.toggle_open_tree_item(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.toggle_open_tree_item('Schemas') self.page.toggle_open_tree_item('public') self.page.toggle_open_tree_item('Tables') 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 4dc082c22..58fc956cb 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 @@ -29,26 +29,16 @@ class CheckForXssFeatureTest(BaseFeatureTest): scenarios = [ ("Test XSS check for panels and query tool", dict()) ] + test_table_name = "

X" def before(self): - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") - test_utils.create_database(self.server, "acceptance_test_db") test_utils.create_table( - self.server, "acceptance_test_db", "

X" + self.server, self.test_db, self.test_table_name ) - # This is needed to test dependents tab (eg: BackGrid) test_utils.create_constraint( - self.server, "acceptance_test_db", - "

X", + self.server, self.test_db, + self.test_table_name, "unique", "

Y" ) @@ -67,24 +57,15 @@ class CheckForXssFeatureTest(BaseFeatureTest): def after(self): self.page.remove_server(self.server) - connection = test_utils.get_db_connection( - self.server['db'], - self.server['username'], - self.server['db_password'], - self.server['host'], - self.server['port'], - self.server['sslmode'] - ) - test_utils.drop_database(connection, "acceptance_test_db") def _tables_node_expandable(self): self.page.toggle_open_server(self.server['name']) self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('acceptance_test_db') + self.page.toggle_open_tree_item(self.test_db) self.page.toggle_open_tree_item('Schemas') self.page.toggle_open_tree_item('public') self.page.toggle_open_tree_item('Tables') - self.page.select_tree_item("

X") + self.page.select_tree_item(self.test_table_name) def _check_xss_in_browser_tree(self): # Fetch the inner html & check for escaped characters diff --git a/web/pgadmin/feature_tests/xss_checks_roles_control_test.py b/web/pgadmin/feature_tests/xss_checks_roles_control_test.py index 21a202732..12e6861ef 100644 --- a/web/pgadmin/feature_tests/xss_checks_roles_control_test.py +++ b/web/pgadmin/feature_tests/xss_checks_roles_control_test.py @@ -7,7 +7,6 @@ # ########################################################################## -from selenium.webdriver import ActionChains from regression.python_test_utils import test_utils from regression.feature_utils.base_feature_test import BaseFeatureTest diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index 1316c7be5..0a3a2051c 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -499,6 +499,22 @@ define('tools.querytool', [ }; }); + /* If the screen width is small and we hover over the Explain Options, + * the submenu goes behind the screen on the right side. + * Below logic will make it appear on the left. + */ + $('.dropdown-submenu').on('mouseenter',function() { + var menu = $(this).find('ul.dropdown-menu'); + var menupos = $(menu).offset(); + + if (menupos.left + menu.width() > $(window).width()) { + var newpos = -$(menu).width(); + menu.css('left',newpos); + } + }).on('mouseleave', function() { + var menu = $(this).find('ul.dropdown-menu'); + menu.css('left',''); + }); self.reflectPreferences(); diff --git a/web/pgadmin/utils/route.py b/web/pgadmin/utils/route.py index f784e5348..31bcc76ab 100644 --- a/web/pgadmin/utils/route.py +++ b/web/pgadmin/utils/route.py @@ -115,3 +115,7 @@ class BaseTestGenerator(unittest.TestCase): @classmethod def setServerInformation(cls, server_information): cls.server_information = server_information + + @classmethod + def setTestDatabaseName(cls, database_name): + cls.test_db = database_name diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py index aacb925e6..eea9b2772 100644 --- a/web/regression/feature_utils/pgadmin_page.py +++ b/web/regression/feature_utils/pgadmin_page.py @@ -10,7 +10,7 @@ import time from selenium.common.exceptions import NoSuchElementException, \ - WebDriverException + WebDriverException, TimeoutException, NoSuchWindowException from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as EC @@ -27,10 +27,23 @@ class PgadminPage: self.driver = driver self.app_config = app_config self.timeout = 30 - self.app_start_timeout = 60 + self.app_start_timeout = 90 def reset_layout(self): - self.click_element(self.find_by_partial_link_text("File")) + attempt = 0 + while attempt < 4: + try: + self.click_element(self.find_by_partial_link_text("File")) + break + except (TimeoutException, NoSuchWindowException): + self.driver.refresh() + try: + WebDriverWait(self.driver, 3).until(EC.alert_is_present()) + self.driver.switch_to_alert().accept() + attempt = attempt + 1 + except TimeoutException: + attempt = attempt + 1 + self.find_by_partial_link_text("Reset Layout").click() self.click_modal('OK') self.wait_for_reloading_indicator_to_disappear() diff --git a/web/regression/runtests.py b/web/regression/runtests.py index 4cd4553f6..ceb7858d6 100644 --- a/web/regression/runtests.py +++ b/web/regression/runtests.py @@ -19,6 +19,7 @@ import signal import sys import traceback import json +import random from selenium import webdriver from selenium.webdriver.chrome.options import Options @@ -126,7 +127,8 @@ unit_test.runner.TextTestResult.addSuccess = test_utils.add_success scenarios.apply_scenario = test_utils.apply_scenario -def get_suite(module_list, test_server, test_app_client, server_information): +def get_suite(module_list, test_server, test_app_client, server_information, + test_db_name): """ This function add the tests to test suite and return modified test suite variable. @@ -156,6 +158,7 @@ def get_suite(module_list, test_server, test_app_client, server_information): obj.setTestServer(test_server) obj.setDriver(driver) obj.setServerInformation(server_information) + obj.setTestDatabaseName(test_db_name) scenario = scenarios.generate_scenarios(obj) pgadmin_suite.addTests(scenario) @@ -380,7 +383,6 @@ if __name__ == '__main__': except Exception as e: print(str(e)) sys.exit(1) - # Login the test client test_utils.login_tester_account(test_client) @@ -395,13 +397,32 @@ if __name__ == '__main__': # Create test server server_information = test_utils.create_parent_server_node(server) + # Create test database with random number to avoid conflict in + # parallel execution on different platforms. This database will be + # used across all feature tests. + test_db_name = "acceptance_test_db" + \ + str(random.randint(10000, 65535)) + connection = test_utils.get_db_connection( + server['db'], + server['username'], + server['db_password'], + server['host'], + server['port'], + server['sslmode'] + ) + + # Drop the database if already exists. + test_utils.drop_database(connection, test_db_name) + # Create database + test_utils.create_database(server, test_db_name) + if server['default_binary_paths'] is not None: test_utils.set_preference(server['default_binary_paths']) suite = get_suite(test_module_list, server, test_client, - server_information) + server_information, test_db_name) tests = unit_test.TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=2).run(suite) @@ -418,6 +439,11 @@ if __name__ == '__main__': if len(failed_cases) > 0: failure = True + # Drop the testing database created initially + if connection: + test_utils.drop_database(connection, test_db_name) + connection.close() + # Delete test server test_utils.delete_test_server(test_client) except SystemExit: