Hi,
Please find attached patch to improve feature test execution time.
Now on my machine overall execution time is cut down to 280 seconds from
400+ seconds
Changes:
1. Removed fixed python time.sleeps where ever possible.
2. Removed connect to server test cases.
3. Query tool test cases:
i. Merged 3 test cases On demand result on scroll, grid select all and
column select all.
ii. Merged 3 test cases Explain query, Explain query with verbose and
Explain query with cost.
iii. Merged 3 test cases Explain analyze query, Explain analyze with
buffers and Explain analyze with timing.
4. Improved debugger XSS test case execution time.
--
*Harshal Dhumal*
*Sr. Software Engineer*
EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/web/pgadmin/feature_tests/connect_to_server_feature_test.py b/web/pgadmin/feature_tests/connect_to_server_feature_test.py
deleted file mode 100644
index 97e96f2..0000000
--- a/web/pgadmin/feature_tests/connect_to_server_feature_test.py
+++ /dev/null
@@ -1,84 +0,0 @@
-##########################################################################
-#
-# pgAdmin 4 - PostgreSQL Tools
-#
-# Copyright (C) 2013 - 2017, The pgAdmin Development Team
-# This software is released under the PostgreSQL Licence
-#
-##########################################################################
-
-import time
-from selenium.webdriver import ActionChains
-
-import config as app_config
-from regression.feature_utils.base_feature_test import BaseFeatureTest
-from regression.python_test_utils import test_utils
-
-
-class ConnectsToServerFeatureTest(BaseFeatureTest):
- """
- Tests that a database connection can be created from the UI
- """
- scenarios = [
- ("Test database connection", 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_utils.create_database(self.server, "acceptance_test_db")
- test_utils.create_table(self.server, "acceptance_test_db", "test_table")
-
- def runTest(self):
- """This function tests that a database connection can be created from
- the UI"""
- self.assertEqual(app_config.APP_NAME, self.page.driver.title)
- self.page.wait_for_spinner_to_disappear()
-
- self._connects_to_server()
- self._tables_node_expandable()
-
- 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 _connects_to_server(self):
- self.page.find_by_xpath("//*[@class='aciTreeText' and .='Servers']").click()
- time.sleep(2)
- self.page.driver.find_element_by_link_text("Object").click()
- ActionChains(self.page.driver) \
- .move_to_element(self.page.driver.find_element_by_link_text("Create")) \
- .perform()
- self.page.find_by_partial_link_text("Server...").click()
-
- server_config = self.server
- self.page.fill_input_by_field_name("name", server_config['name'])
- self.page.find_by_partial_link_text("Connection").click()
- self.page.fill_input_by_field_name("host", server_config['host'])
- self.page.fill_input_by_field_name("port", server_config['port'])
- self.page.fill_input_by_field_name("username", server_config['username'])
- self.page.fill_input_by_field_name("password", server_config['db_password'])
- self.page.find_by_xpath("//button[contains(.,'Save')]").click()
-
- 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')
- # wait until all database dependant modules/js are loaded.
- time.sleep(5)
- self.page.toggle_open_tree_item('Schemas')
- self.page.toggle_open_tree_item('public')
- self.page.toggle_open_tree_item('Tables')
- self.page.toggle_open_tree_item('test_table')
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 1809d45..d01bf66 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,7 +8,6 @@
##########################################################################
import pyperclip
-import time
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
@@ -42,16 +41,16 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
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')
- time.sleep(5)
- self.page.find_by_partial_link_text("Tools").click()
- self.page.find_by_partial_link_text("Query Tool").click()
- self.page.click_tab('Query -')
- time.sleep(5)
- ActionChains(self.page.driver).send_keys("SELECT * FROM test_table ORDER BY some_column").perform()
- self.page.driver.switch_to_frame(self.page.driver.find_element_by_tag_name("iframe"))
+ 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")
+
self.page.find_by_id("btn-flash").click()
- time.sleep(5)
self._copies_rows()
self._copies_columns()
self._copies_row_using_keyboard_shortcut()
diff --git a/web/pgadmin/feature_tests/pg_datatype_validation_test.py b/web/pgadmin/feature_tests/pg_datatype_validation_test.py
index f700aab..46a1beb 100644
--- a/web/pgadmin/feature_tests/pg_datatype_validation_test.py
+++ b/web/pgadmin/feature_tests/pg_datatype_validation_test.py
@@ -6,7 +6,6 @@
# This software is released under the PostgreSQL Licence
#
##########################################################################
-import time
from selenium.webdriver import ActionChains
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
@@ -38,7 +37,7 @@ class PGDataypeFeatureTest(BaseFeatureTest):
def runTest(self):
self.page.wait_for_spinner_to_disappear()
- self._connects_to_server()
+ self.page.add_server(self.server)
self._schema_node_expandable()
# Check data types
@@ -55,31 +54,6 @@ class PGDataypeFeatureTest(BaseFeatureTest):
self.server['sslmode'])
test_utils.drop_database(connection, "acceptance_test_db")
- def _connects_to_server(self):
- self.page.find_by_xpath(
- "//*[@class='aciTreeText' and .='Servers']"
- ).click()
- time.sleep(2)
- self.page.driver.find_element_by_link_text("Object").click()
- ActionChains(self.page.driver) \
- .move_to_element(
- self.page.driver.find_element_by_link_text("Create")
- ).perform()
- self.page.find_by_partial_link_text("Server...").click()
-
- server_config = self.server
- self.page.fill_input_by_field_name("name", server_config['name'])
- self.page.find_by_partial_link_text("Connection").click()
- self.page.fill_input_by_field_name("host", server_config['host'])
- self.page.fill_input_by_field_name("port", server_config['port'])
- self.page.fill_input_by_field_name(
- "username", server_config['username']
- )
- self.page.fill_input_by_field_name(
- "password", server_config['db_password']
- )
- self.page.find_by_xpath("//button[contains(.,'Save')]").click()
-
def _schema_node_expandable(self):
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py
index 0795028..dbe287b 100644
--- a/web/pgadmin/feature_tests/query_tool_journey_test.py
+++ b/web/pgadmin/feature_tests/query_tool_journey_test.py
@@ -8,7 +8,6 @@
##########################################################################
import pyperclip
-import time
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
@@ -39,7 +38,11 @@ class QueryToolJourneyTest(BaseFeatureTest):
def runTest(self):
self._navigate_to_query_tool()
- self._execute_query("SELECT * FROM test_table ORDER BY value")
+
+ self.page.fill_codemirror_area_with(
+ "SELECT * FROM test_table ORDER BY value"
+ )
+ self.page.find_by_id("btn-flash").click()
self._test_copies_rows()
self._test_copies_columns()
@@ -47,7 +50,6 @@ class QueryToolJourneyTest(BaseFeatureTest):
def _test_copies_rows(self):
pyperclip.copy("old clipboard contents")
- time.sleep(5)
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(self.page.driver.find_element_by_tag_name("iframe"))
self.page.find_by_xpath("//*[contains(@class, 'slick-row')]/*[1]").click()
@@ -72,7 +74,8 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.__clear_query_tool()
editor_input = self.page.find_by_id("output-panel")
self.page.click_element(editor_input)
- self._execute_query("SELECT * FROM shoes")
+ self.page.fill_codemirror_area_with("SELECT * FROM shoes")
+ self.page.find_by_id("btn-flash").click()
self.page.click_tab("History")
selected_history_entry = self.page.find_by_css_selector("#query_list .selected")
@@ -94,7 +97,8 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.__clear_query_tool()
self.page.click_element(editor_input)
for _ in range(15):
- self._execute_query("SELECT * FROM hats")
+ self.page.fill_codemirror_area_with("SELECT * FROM hats")
+ self.page.find_by_id("btn-flash").click()
self.page.click_tab("History")
query_we_need_to_scroll_to = self.page.find_by_xpath(
@@ -126,13 +130,6 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.toggle_open_tree_item('Databases')
self.page.toggle_open_tree_item('acceptance_test_db')
self.page.open_query_tool()
- time.sleep(5)
-
- def _execute_query(self, query):
- ActionChains(self.page.driver).send_keys(query).perform()
- self.page.driver.switch_to.default_content()
- self.page.driver.switch_to_frame(self.page.driver.find_element_by_tag_name("iframe"))
- self.page.find_by_id("btn-flash").click()
def _assert_clickable(self, element):
self.page.click_element(element)
diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py
index 8e13817..c747beb 100644
--- a/web/pgadmin/feature_tests/query_tool_tests.py
+++ b/web/pgadmin/feature_tests/query_tool_tests.py
@@ -38,68 +38,28 @@ class QueryToolFeatureTest(BaseFeatureTest):
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._connects_to_server()
+ self.page.add_server(self.server)
self._locate_database_tree_node()
self.page.open_query_tool()
def runTest(self):
# on demand result set on scrolling.
- print("\nOn demand result set on scrolling... ",
+ print("\nOn demand query result... ",
file=sys.stderr, end="")
self._on_demand_result()
- print("OK.",
- file=sys.stderr)
- self._clear_query_tool()
-
- # on demand result set on grid select all.
- print("On demand result set on grid select all... ",
- file=sys.stderr, end="")
- self._on_demand_result_select_all_grid()
- print("OK.",
- file=sys.stderr)
self._clear_query_tool()
- # on demand result set on column select all.
- print("On demand result set on column select all... ",
+ # explain query with verbose and cost
+ print("Explain query with verbose and cost... ",
file=sys.stderr, end="")
- self._on_demand_result_select_all_column()
- print("OK.",
- file=sys.stderr)
- self._clear_query_tool()
-
- # explain query
- print("Explain query... ", file=sys.stderr, end="")
- self._query_tool_explain()
- print("OK.", file=sys.stderr)
- self._clear_query_tool()
-
- # explain query with verbose
- print("Explain query with verbose... ", file=sys.stderr, end="")
- self._query_tool_explain_verbose()
+ self._query_tool_explain_with_verbose_and_cost()
print("OK.", file=sys.stderr)
self._clear_query_tool()
- # explain query with costs
- print("Explain query with costs... ", file=sys.stderr, end="")
- self._query_tool_explain_cost()
- print("OK.", file=sys.stderr)
- self._clear_query_tool()
-
- # explain analyze query
- print("Explain analyze query... ", file=sys.stderr, end="")
- self._query_tool_explain_analyze()
- print("OK.", file=sys.stderr)
- self._clear_query_tool()
-
- # explain analyze query with buffers
- print("Explain analyze query with buffers... ", file=sys.stderr, end="")
- self._query_tool_explain_analyze_buffers()
- print("OK.", file=sys.stderr)
- self._clear_query_tool()
-
- # explain analyze query with timing
- print("Explain analyze query with timing... ", file=sys.stderr, end="")
- self._query_tool_explain_analyze_timing()
+ # explain analyze query with buffers and timing
+ print("Explain analyze query with buffers and timing... ",
+ file=sys.stderr, end="")
+ self._query_tool_explain_analyze_with_buffers_and_timing()
print("OK.", file=sys.stderr)
self._clear_query_tool()
@@ -137,32 +97,6 @@ class QueryToolFeatureTest(BaseFeatureTest):
self.server['sslmode'])
test_utils.drop_database(connection, "acceptance_test_db")
- def _connects_to_server(self):
- self.page.find_by_xpath(
- "//*[@class='aciTreeText' and .='Servers']").click()
- time.sleep(2)
- self.page.driver.find_element_by_link_text("Object").click()
- ActionChains(self.page.driver) \
- .move_to_element(
- self.page.driver.find_element_by_link_text("Create"))\
- .perform()
- self.page.find_by_partial_link_text("Server...").click()
-
- server_config = self.server
- self.page.fill_input_by_field_name("name", server_config['name'])
- self.page.find_by_partial_link_text("Connection").click()
- self.page.fill_input_by_field_name("host", server_config['host'])
- self.page.fill_input_by_field_name("port", server_config['port'])
- self.page.fill_input_by_field_name(
- "username",
- server_config['username']
- )
- self.page.fill_input_by_field_name(
- "password",
- server_config['db_password']
- )
- self.page.find_by_xpath("//button[contains(.,'Save')]").click()
-
def _locate_database_tree_node(self):
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
@@ -180,14 +114,24 @@ class QueryToolFeatureTest(BaseFeatureTest):
)
self.page.click_modal('Yes')
+ def _wait_until_canvas_updates(self, canvas, old_height):
+ # loop until canvas height changes or upto 5 seconds.
+ cur_time = time.time()
+ while canvas.size['height'] == old_height \
+ and cur_time + 5 > time.time():
+ pass
+
def _on_demand_result(self):
ON_DEMAND_CHUNKS = 2
- query = """-- On demand query result on scroll
-SELECT generate_series(1, {}) as id""".format(
+ row_id_to_find = config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS
+
+ query = """-- On demand query result on scroll, grid select all, column select all
+SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format(
config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS)
+ print("\nOn demand result set on scrolling... ",
+ file=sys.stderr, end="")
wait = WebDriverWait(self.page.driver, 10)
- time.sleep(1)
self.page.fill_codemirror_area_with(query)
self.page.find_by_id("btn-flash").click()
@@ -197,154 +141,83 @@ SELECT generate_series(1, {}) as id""".format(
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
+ old_height = canvas.size['height']
# scroll to bottom to fetch next chunk of result set.
self.driver.execute_script(
"pgAdmin.SqlEditor.jquery('.slick-viewport').scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas').height());"
)
- # wait for ajax to complete.
- time.sleep(1)
- # again scroll to bottom to bring last row of next chunk in
- # viewport.
- self.driver.execute_script(
- "pgAdmin.SqlEditor.jquery('.slick-viewport').scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas').height());"
- )
-
- row_id_to_find = config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS
-
- canvas.find_element_by_xpath(
- '//span[text()="{}"]'.format(row_id_to_find)
- )
-
- def _on_demand_result_select_all_grid(self):
- ON_DEMAND_CHUNKS = 3
- query = """-- On demand query result on grid select all
-SELECT generate_series(1, {}) as id""".format(
- config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS)
+ self._wait_until_canvas_updates(canvas, old_height)
- wait = WebDriverWait(self.page.driver, 10)
-
- self.page.fill_codemirror_area_with(query)
+ self._check_ondemand_result(row_id_to_find, canvas)
+ print("OK.", file=sys.stderr)
+ print("On demand result set on grid select all... ",
+ 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.CSS_SELECTOR, ".slick-header-column"))).click()
-
- # wait for until all records are fetched and selected.
- time.sleep(1)
- # scroll to bottom to bring last row of next chunk in
- # viewport.
- self.driver.execute_script(
- "pgAdmin.SqlEditor.jquery('.slick-viewport').scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas').height());"
- )
-
canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
-
- row_id_to_find = config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS
+ (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
- canvas.find_element_by_xpath(
- '//span[text()="{}"]'.format(row_id_to_find)
- )
+ old_height = canvas.size['height']
- def _on_demand_result_select_all_column(self):
- ON_DEMAND_CHUNKS = 4
- query = """-- On demand query result on column select all
-SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format(
- config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS)
+ wait.until(EC.presence_of_element_located(
+ (By.CSS_SELECTOR, ".slick-header-column"))).click()
- wait = WebDriverWait(self.page.driver, 10)
+ self._wait_until_canvas_updates(canvas, old_height)
- self.page.fill_codemirror_area_with(query)
+ self._check_ondemand_result(row_id_to_find, canvas)
+ print("OK.", file=sys.stderr)
+ print("On demand result set on column select all... ",
+ file=sys.stderr, end="")
self.page.find_by_id("btn-flash").click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
- # click on first data column to select all column.
+ canvas = wait.until(EC.presence_of_element_located(
+ (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
+
+ old_height = canvas.size['height']
+ # click on first data column to select all column.
wait.until(EC.presence_of_element_located(
(
By.XPATH,
"//span[contains(@class, 'column-name') and contains(., 'id1')]"))
).click()
- # wait for until all records are fetched and selected.
- time.sleep(1)
- # scroll to bottom to bring last row of next chunk in
- # viewport.
+ self._wait_until_canvas_updates(canvas, old_height)
+
+ self._check_ondemand_result(row_id_to_find, canvas)
+ print("OK.", file=sys.stderr)
+
+ def _check_ondemand_result(self, row_id_to_find, canvas):
+ # scroll to bottom to bring last row of next chunk in viewport.
self.driver.execute_script(
"pgAdmin.SqlEditor.jquery('.slick-viewport').scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas').height());"
)
- canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
-
- row_id_to_find = config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS
-
canvas.find_element_by_xpath(
'//span[text()="{}"]'.format(row_id_to_find)
)
- def _query_tool_explain(self):
- query = """-- Explain query
+ def _query_tool_explain_with_verbose_and_cost(self):
+ query = """-- Explain query with verbose and cost
SELECT generate_series(1, 1000) as id order by id desc"""
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with(query)
- self.page.find_by_id("btn-query-dropdown").click()
- self.page.find_by_id("btn-explain").click()
-
- self.page.wait_for_query_tool_loading_indicator_to_disappear()
-
- self.page.click_tab('Data Output')
-
- canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
- # Search for Plan word in result
- canvas.find_element_by_xpath("//*[contains(string(),'Plan')]")
-
- def _query_tool_explain_verbose(self):
- query = """-- Explain query with verbose
-SELECT generate_series(1, 1000) as id order by id desc"""
-
- wait = WebDriverWait(self.page.driver, 10)
- self.page.fill_codemirror_area_with(query)
query_op = self.page.find_by_id("btn-query-dropdown")
query_op.click()
ActionChains(self.driver).move_to_element(
query_op.find_element_by_xpath(
"//li[contains(.,'Explain Options')]")).perform()
- self.page.find_by_id("btn-explain-verbose").click()
- self.page.find_by_id("btn-explain").click()
- self.page.wait_for_query_tool_loading_indicator_to_disappear()
- self.page.click_tab('Data Output')
- canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
- # Search for 'Output' word in result
- canvas.find_element_by_xpath("//*[contains(string(), 'Output')]")
- def _query_tool_explain_cost(self):
- query = """-- Explain query with costs
-SELECT generate_series(1, 1000) as id order by id desc"""
-
- wait = WebDriverWait(self.page.driver, 10)
-
- self.page.fill_codemirror_area_with(query)
- query_op = self.page.find_by_id("btn-query-dropdown")
- query_op.click()
-
- ActionChains(self.driver).move_to_element(
- query_op.find_element_by_xpath(
- "//li[contains(.,'Explain Options')]")).perform()
+ self.page.find_by_id("btn-explain-verbose").click()
self.page.find_by_id("btn-explain-costs").click()
@@ -357,32 +230,15 @@ SELECT generate_series(1, 1000) as id order by id desc"""
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
)
- # Search for 'Total Cost word in result
- canvas.find_element_by_xpath("//*[contains(string(),'Total Cost')]")
- def _query_tool_explain_analyze(self):
- query = """-- Explain analyze query
-SELECT generate_series(1, 1000) as id order by id desc"""
-
- wait = WebDriverWait(self.page.driver, 10)
-
- self.page.fill_codemirror_area_with(query)
-
- self.page.find_by_id("btn-query-dropdown").click()
- self.page.find_by_id("btn-explain-analyze").click()
-
- self.page.wait_for_query_tool_loading_indicator_to_disappear()
-
- self.page.click_tab('Data Output')
+ # Search for 'Output' word in result (verbose option)
+ canvas.find_element_by_xpath("//*[contains(string(), 'Output')]")
- canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
- # Search for Actual Rows word in result
- canvas.find_element_by_xpath("//*[contains(string(),'Actual Rows')]")
+ # Search for 'Total Cost' word in result (cost option)
+ canvas.find_element_by_xpath("//*[contains(string(),'Total Cost')]")
- def _query_tool_explain_analyze_buffers(self):
- query = """-- Explain analyze query with buffers
+ def _query_tool_explain_analyze_with_buffers_and_timing(self):
+ query = """-- Explain analyze query with buffers and timing
SELECT generate_series(1, 1000) as id order by id desc"""
wait = WebDriverWait(self.page.driver, 10)
@@ -398,32 +254,6 @@ SELECT generate_series(1, 1000) as id order by id desc"""
self.page.find_by_id("btn-explain-buffers").click()
- self.page.find_by_id("btn-explain-analyze").click()
-
- self.page.wait_for_query_tool_loading_indicator_to_disappear()
-
- self.page.click_tab('Data Output')
-
- canvas = wait.until(EC.presence_of_element_located(
- (By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
- )
- # Search for 'Shared Read Blocks' word in result
- canvas.find_element_by_xpath("//*[contains(string(), 'Shared Read Blocks')]")
-
- def _query_tool_explain_analyze_timing(self):
- query = """-- Explain analyze query with timing
-SELECT generate_series(1, 1000) as id order by id desc"""
-
- wait = WebDriverWait(self.page.driver, 10)
-
- self.page.fill_codemirror_area_with(query)
- query_op = self.page.find_by_id("btn-query-dropdown")
- query_op.click()
-
- ActionChains(self.driver).move_to_element(
- query_op.find_element_by_xpath(
- "//li[contains(.,'Explain Options')]")).perform()
-
self.page.find_by_id("btn-explain-timing").click()
self.page.find_by_id("btn-explain-analyze").click()
@@ -435,8 +265,15 @@ SELECT generate_series(1, 1000) as id order by id desc"""
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
)
- # Search for 'Actual Total Time' word in result
- canvas.find_element_by_xpath("//*[contains(string(), 'Actual Total Time')]")
+ # Search for 'Shared Read Blocks' word in result (buffers option)
+ canvas.find_element_by_xpath(
+ "//*[contains(string(), 'Shared Read Blocks')]"
+ )
+
+ # Search for 'Actual Total Time' word in result (timing option)
+ canvas.find_element_by_xpath(
+ "//*[contains(string(), 'Actual Total Time')]"
+ )
def _query_tool_auto_commit_disabled(self):
table_name = 'query_tool_auto_commit_disabled_table'
diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py
index e8cf598..0b2da0c 100644
--- a/web/pgadmin/feature_tests/view_data_dml_queries.py
+++ b/web/pgadmin/feature_tests/view_data_dml_queries.py
@@ -199,8 +199,6 @@ CREATE TABLE public.defaults
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')
- # wait until all database dependant modules/js are loaded.
- time.sleep(5)
self.page.toggle_open_tree_item('Schemas')
self.page.toggle_open_tree_item('public')
self.page.toggle_open_tree_item('Tables')
@@ -267,7 +265,7 @@ CREATE TABLE public.defaults
cell_xpath = CheckForViewDataTest._get_cell_xpath(
'r'+str(idx), 1
)
- time.sleep(0.4)
+ time.sleep(0.2)
self._update_cell(cell_xpath, config_data[str(idx)])
self.page.find_by_id("btn-save").click() # Save data
@@ -300,4 +298,4 @@ CREATE TABLE public.defaults
if idx != 1 and not is_new_row:
self.assertEquals(cells[idx], config_data[str(idx)][1])
elif is_new_row:
- self.assertEquals(cells[idx], config_data[str(idx)][1])
\ No newline at end of file
+ self.assertEquals(cells[idx], config_data[str(idx)][1])
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 30b1051..7e3a9f8 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
@@ -10,10 +10,7 @@
from selenium.webdriver import ActionChains
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
-from selenium.webdriver.support.ui import WebDriverWait
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.common.by import By
-import time
+
class CheckForXssFeatureTest(BaseFeatureTest):
"""
@@ -53,7 +50,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
def runTest(self):
self.page.wait_for_spinner_to_disappear()
- self._connects_to_server()
+ self.page.add_server(self.server)
self._tables_node_expandable()
self._check_xss_in_browser_tree()
self._check_xss_in_properties_tab()
@@ -65,7 +62,6 @@ class CheckForXssFeatureTest(BaseFeatureTest):
self.page.close_query_tool()
def after(self):
- time.sleep(1)
self.page.remove_server(self.server)
connection = test_utils.get_db_connection(self.server['db'],
self.server['username'],
@@ -75,24 +71,6 @@ class CheckForXssFeatureTest(BaseFeatureTest):
self.server['sslmode'])
test_utils.drop_database(connection, "acceptance_test_db")
- def _connects_to_server(self):
- self.page.find_by_xpath("//*[@class='aciTreeText' and .='Servers']").click()
- time.sleep(2)
- self.page.driver.find_element_by_link_text("Object").click()
- ActionChains(self.page.driver) \
- .move_to_element(self.page.driver.find_element_by_link_text("Create")) \
- .perform()
- self.page.find_by_partial_link_text("Server...").click()
-
- server_config = self.server
- self.page.fill_input_by_field_name("name", server_config['name'])
- self.page.find_by_partial_link_text("Connection").click()
- self.page.fill_input_by_field_name("host", server_config['host'])
- self.page.fill_input_by_field_name("port", server_config['port'])
- self.page.fill_input_by_field_name("username", server_config['username'])
- self.page.fill_input_by_field_name("password", server_config['db_password'])
- self.page.find_by_xpath("//button[contains(.,'Save')]").click()
-
def _tables_node_expandable(self):
self.page.toggle_open_server(self.server['name'])
self.page.toggle_open_tree_item('Databases')
@@ -155,10 +133,10 @@ class CheckForXssFeatureTest(BaseFeatureTest):
self.page.driver.find_element_by_link_text("Tools").click()
self.page.find_by_partial_link_text("Query Tool").click()
self.page.click_tab('Query -')
- self.page.fill_codemirror_area_with("select '<img src=\"x\" onerror=\"console.log(1)\">'")
- time.sleep(1)
+ self.page.fill_codemirror_area_with(
+ "select '<img src=\"x\" onerror=\"console.log(1)\">'"
+ )
self.page.find_by_id("btn-flash").click()
- wait = WebDriverWait(self.page.driver, 5)
result_row = self.page.find_by_xpath(
"//*[contains(@class, 'ui-widget-content') and contains(@style, 'top:0px')]"
@@ -177,9 +155,4 @@ class CheckForXssFeatureTest(BaseFeatureTest):
def _check_escaped_characters(self, source_code, string_to_find, source):
# For XSS we need to search against element's html code
- if source_code.find(string_to_find) == -1:
- # No escaped characters found
- assert False, "{0} might be vulnerable to XSS ".format(source)
- else:
- # escaped characters found
- assert True
+ assert source_code.find(string_to_find) != -1, "{0} might be vulnerable to XSS ".format(source)
diff --git a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
index e847040..f18cde2 100644
--- a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
+++ b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py
@@ -7,10 +7,15 @@
#
##########################################################################
+import time
from selenium.webdriver import ActionChains
+from selenium.common.exceptions import TimeoutException
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
-import time
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.common.by import By
+
class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
"""Tests to check if Debugger is vulnerable to XSS."""
@@ -30,34 +35,15 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
def runTest(self):
self.page.wait_for_spinner_to_disappear()
- self._connects_to_server()
+ self.page.add_server(self.server)
self._function_node_expandable()
self._debug_function()
def after(self):
- time.sleep(0.5)
test_utils.drop_debug_function(self.server, "postgres",
"test_function")
self.page.remove_server(self.server)
- def _connects_to_server(self):
- self.page.find_by_xpath("//*[@class='aciTreeText' and .='Servers']").click()
- time.sleep(2)
- self.page.driver.find_element_by_link_text("Object").click()
- ActionChains(self.page.driver) \
- .move_to_element(self.page.driver.find_element_by_link_text("Create")) \
- .perform()
- self.page.find_by_partial_link_text("Server...").click()
-
- server_config = self.server
- self.page.fill_input_by_field_name("name", server_config['name'])
- self.page.find_by_partial_link_text("Connection").click()
- self.page.fill_input_by_field_name("host", server_config['host'])
- self.page.fill_input_by_field_name("port", server_config['port'])
- self.page.fill_input_by_field_name("username", server_config['username'])
- self.page.fill_input_by_field_name("password", server_config['db_password'])
- self.page.find_by_xpath("//button[contains(.,'Save')]").click()
-
def _function_node_expandable(self):
self.page.toggle_open_server(self.server['name'])
self.page.toggle_open_tree_item('Databases')
@@ -73,32 +59,44 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
.move_to_element(self.page.driver.find_element_by_link_text("Debugging")) \
.perform()
self.page.driver.find_element_by_link_text("Debug").click()
- time.sleep(0.5)
+
# We need to check if debugger plugin is installed or not
try:
- is_error = self.page.find_by_xpath(
- "//div[contains(@class,'ajs-header')]"
- ).text
- except Exception as e:
+ wait = WebDriverWait(self.page.driver, 2)
+ is_error = wait.until(EC.presence_of_element_located(
+ (By.XPATH, "//div[contains(@class,'ajs-header')]"))
+ )
+ except TimeoutException as e:
is_error = None
# If debugger plugin is not found
- if is_error and is_error == "Debugger Error":
+ if is_error and is_error.text == "Debugger Error":
self.page.click_modal('OK')
- self.skipTest("Please make sure that debugger plugin is properly configured")
+ self.skipTest(
+ "Please make sure that debugger plugin is properly configured"
+ )
else:
- time.sleep(2)
- self.page.driver.switch_to.frame(self.page.driver.find_element_by_tag_name('iframe'))
- self.page.click_element(self.page.driver.find_elements_by_xpath("//button")[2])
- time.sleep(2)
+ self.page.driver.switch_to.frame(
+ self.page.driver.find_element_by_tag_name('iframe')
+ )
+
+ wait.until(EC.presence_of_element_located(
+ (By.XPATH, "//span[contains(.,'Hello, pgAdmin4')]"))
+ )
+ self.page.click_element(
+ self.page.driver.find_elements_by_xpath("//button")[2]
+ )
- # Only this tab is vulnerable rest are BackGrid & Code Mirror control
- # which are already tested in Query tool test case
+ wait.until(EC.presence_of_element_located(
+ (By.XPATH, "//td[contains(@class,'test_function') and contains(.,'Hello, pgAdmin4')]"))
+ )
+
+ # Only this tab is vulnerable rest are BackGrid & Code Mirror
+ # control which are already tested in Query tool test case
self.page.click_tab("Messages")
source_code = self.page.find_by_xpath(
"//*[@id='messages']"
).get_attribute('innerHTML')
-
self._check_escaped_characters(
source_code,
'NOTICE: <img src="x" onerror="console.log(1)">',
@@ -107,18 +105,12 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
self._close_debugger()
def _close_debugger(self):
- time.sleep(0.5)
self.page.driver.switch_to_default_content()
- time.sleep(0.5)
self.page.click_element(
self.page.find_by_xpath("//*[@id='dockerContainer']/div/div[3]/div/div[2]/div[1]")
)
def _check_escaped_characters(self, source_code, string_to_find, source):
# For XSS we need to search against element's html code
- if source_code.find(string_to_find) == -1:
- # No escaped characters found
- assert False, "{0} might be vulnerable to XSS ".format(source)
- else:
- # escaped characters found
- assert True
+ # No escaped characters found
+ assert source_code.find(string_to_find) != -1, "{0} might be vulnerable to XSS ".format(source)
diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py
index 21e45a6..50c1cb1 100644
--- a/web/regression/feature_utils/pgadmin_page.py
+++ b/web/regression/feature_utils/pgadmin_page.py
@@ -180,9 +180,6 @@ class PgadminPage:
self.wait_for_input_field_content(field_name, field_content)
def fill_codemirror_area_with(self, field_content):
- # For long text, if we try to execute send_keys and perform back to back, then the actions are
- # not executed properly as the driver can send only 50 to 60 characters. To avoid this, sleep
- # on the basis of content length.
def find_codemirror(driver):
try:
driver.switch_to.default_content()
@@ -203,8 +200,6 @@ class PgadminPage:
action = ActionChains(self.driver)
action.send_keys(field_content)
action.perform()
- sleep_time = math.ceil(len(field_content) / 50)
- time.sleep(sleep_time)
def click_tab(self, tab_name):
tab = self.find_by_xpath("//*[contains(@class,'wcTabTop')]//*[contains(@class,'wcPanelTab') "