Feature test improvement and fix intermittent failures part of #3936

pull/26/head
Shubham Agarwal 2019-08-22 14:50:51 +05:30 committed by Akshay Joshi
parent 7090c02014
commit 9f455a514e
21 changed files with 1213 additions and 726 deletions

View File

@ -10,9 +10,8 @@
from __future__ import print_function
import sys
import random
import time
from regression.python_test_utils import test_utils
from regression.feature_utils.locators import BrowserToolBarLocators
from regression.feature_utils.base_feature_test import BaseFeatureTest
from selenium.common.exceptions import TimeoutException, \
StaleElementReferenceException
@ -57,27 +56,25 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
def after(self):
self.page.remove_server(self.server)
test_utils.delete_table(self.server, self.test_db,
self.test_table_name)
def _locate_database_tree_node(self):
def test_query_tool_button(self):
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
self.page.toggle_open_tree_item(self.test_db)
def test_query_tool_button(self):
self._locate_database_tree_node()
retry_count = 0
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='Query Tool']:not(.disabled)")\
BrowserToolBarLocators.open_query_tool_button_css)\
.click()
break
except StaleElementReferenceException:
except (StaleElementReferenceException, TimeoutException):
retry_count += 1
time.sleep(0.5)
self.page.find_by_css_selector(".wcPanelTab .wcTabIcon.fa.fa-bolt")
self.page.find_by_css_selector(
BrowserToolBarLocators.query_tool_panel_css)
def test_view_data_tool_button(self):
self.page.select_tree_item(self.test_db)
@ -90,26 +87,23 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='View Data']:not(.disabled)").click()
BrowserToolBarLocators.view_table_data_button_css).click()
break
except StaleElementReferenceException:
except (StaleElementReferenceException, TimeoutException):
retry_count += 1
time.sleep(0.5)
self.page.find_by_css_selector(".wcPanelTab .wcTabIcon.fa.fa-bolt")
self.page.find_by_css_selector(
BrowserToolBarLocators.view_data_panel_css)
def test_filtered_rows_tool_button(self):
retry_count = 0
while retry_count < 5:
try:
self.page.find_by_css_selector(
".wcFrameButton[title='Filtered Rows']:not(.disabled)")\
BrowserToolBarLocators.filter_data_button_css)\
.click()
break
except StaleElementReferenceException:
except (StaleElementReferenceException, TimeoutException):
retry_count += 1
time.sleep(0.5)
self.page.find_by_css_selector(
".alertify .ajs-header[data-title~='Filter']")
BrowserToolBarLocators.filter_alertify_box_css)
self.page.click_modal('Cancel')

View File

@ -9,11 +9,11 @@
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
from regression.feature_utils.locators import QueryToolLocators
class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
@ -32,10 +32,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
# 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))
self.page.add_server(self.server)
test_utils.create_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'])
@ -46,7 +45,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
self.page.fill_codemirror_area_with(
"SELECT * FROM %s ORDER BY some_column" % self.test_table_name)
self.page.find_by_id("btn-flash").click()
self.page.find_by_css_selector(
QueryToolLocators.btn_execute_query_css).click()
self._copies_rows()
self._copies_columns()
@ -59,21 +59,26 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _copies_rows(self):
pyperclip.copy("old clipboard contents")
self.page.find_by_xpath(
"//*[contains(@class, 'slick-row')]/*[1]").click()
first_row = self.page.find_by_xpath(
QueryToolLocators.output_row_xpath.format(1))
first_row.click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
copy_button = self.page.find_by_css_selector(
QueryToolLocators.copy_button_css)
copy_button.click()
self.assertEqual('"Some-Name"\t"6"\t"some info"',
pyperclip.paste())
def _copies_columns(self):
pyperclip.copy("old clipboard contents")
self.page.find_by_xpath(
"//*[@data-test='output-column-header' and "
"contains(., 'some_column')]"
).click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
column = self.page.find_by_css_selector(
QueryToolLocators.output_column_header_css.format('some_column'))
column.click()
copy_button = self.page.find_by_css_selector(
QueryToolLocators.copy_button_css)
copy_button.click()
self.assertEqual(
"""\"Some-Name"
@ -83,8 +88,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _copies_row_using_keyboard_shortcut(self):
pyperclip.copy("old clipboard contents")
self.page.find_by_xpath(
"//*[contains(@class, 'slick-row')]/*[1]").click()
first_row = self.page.find_by_xpath(
QueryToolLocators.output_row_xpath.format(1))
first_row.click()
ActionChains(self.page.driver).key_down(
Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
@ -94,10 +100,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _copies_column_using_keyboard_shortcut(self):
pyperclip.copy("old clipboard contents")
self.page.find_by_xpath(
"//*[@data-test='output-column-header' and "
"contains(., 'some_column')]"
).click()
column = self.page.find_by_css_selector(
QueryToolLocators.output_column_header_css.format('some_column'))
column.click()
ActionChains(self.page.driver).key_down(
Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
@ -111,12 +116,12 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _copies_rectangular_selection(self):
pyperclip.copy("old clipboard contents")
top_left_cell = self.page.find_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(., 'Some-Other-Name')]"
)
top_left_cell = \
self.page.find_by_xpath(
QueryToolLocators.output_column_data_xpath.
format('Some-Other-Name'))
bottom_right_cell = self.page.find_by_xpath(
"//div[contains(@class, 'slick-cell') and contains(., '14')]")
QueryToolLocators.output_column_data_xpath.format('14'))
ActionChains(
self.page.driver
@ -135,11 +140,11 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
pyperclip.copy("old clipboard contents")
top_left_cell = self.page.find_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(., 'Some-Other-Name')]"
QueryToolLocators.output_column_data_xpath.
format('Some-Other-Name')
)
initial_bottom_right_cell = self.page.find_by_xpath(
"//div[contains(@class, 'slick-cell') and contains(., '14')]")
QueryToolLocators.output_column_data_xpath.format('14'))
ActionChains(
self.page.driver
).click_and_hold(top_left_cell).move_to_element(
@ -160,10 +165,10 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def _shift_resizes_column_selection(self):
pyperclip.copy("old clipboard contents")
self.page.find_by_xpath(
"//*[@data-test='output-column-header' and "
"contains(., 'value')]"
).click()
column = self.page.find_by_css_selector(
QueryToolLocators.output_column_header_css.format('value')
)
column.click()
ActionChains(self.page.driver).key_down(
Keys.SHIFT).send_keys(Keys.ARROW_LEFT).key_up(Keys.SHIFT).perform()
@ -181,11 +186,11 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
pyperclip.copy("old clipboard contents")
bottom_right_cell = self.page.find_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(., 'cool info')]"
QueryToolLocators.output_column_data_xpath.format('cool info')
)
load_button = self.page.find_by_xpath("//button[@id='btn-load-file']")
load_button = self.page.find_by_css_selector(
QueryToolLocators.btn_load_file_css)
ActionChains(self.page.driver).click_and_hold(bottom_right_cell) \
.move_to_element(load_button) \
.release(load_button) \
@ -199,3 +204,5 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
def after(self):
self.page.close_query_tool()
self.page.remove_server(self.server)
test_utils.delete_table(self.server, self.test_db,
self.test_table_name)

View File

@ -9,15 +9,16 @@
from __future__ import print_function
import os
import time
import sys
import time
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.common.exceptions import StaleElementReferenceException, \
TimeoutException
from selenium.webdriver.support import expected_conditions as EC
from regression.feature_utils.base_feature_test import BaseFeatureTest
from .locators import QueryToolLocatorsCss
from regression.feature_utils.locators import QueryToolLocators
class CheckFileManagerFeatureTest(BaseFeatureTest):
@ -65,32 +66,40 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
self.page.open_query_tool()
def _create_new_file(self):
self.page.find_by_css_selector(QueryToolLocatorsCss.btn_save_file)\
self.page.find_by_css_selector(QueryToolLocators.btn_save_file)\
.click()
# Set the XSS value in input
self.page.find_by_css_selector('.change_file_types')
self.page.fill_input_by_css_selector("input#file-input-path",
self.XSS_FILE)
self.page.fill_input_by_css_selector(
QueryToolLocators.input_file_path_css, self.XSS_FILE)
# Save the file
self.page.click_modal('Create')
self.page.wait_for_query_tool_loading_indicator_to_disappear()
def _open_file_manager_and_check_xss_file(self):
self.page.find_by_id("btn-load-file").click()
load_file = self.page.find_by_css_selector(
QueryToolLocators.btn_load_file_css)
load_file.click()
self.page.find_by_css_selector('.change_file_types')
self.page.fill_input_by_css_selector("#file-input-path", "/tmp/",
key_after_input=Keys.RETURN)
self.page.fill_input_by_css_selector(
QueryToolLocators.input_file_path_css,
"/tmp/", key_after_input=Keys.RETURN)
if self.page.driver.capabilities['browserName'] == 'firefox':
table = self.page.wait_for_element_to_reload(
lambda driver:
driver.find_element_by_css_selector("table#contents")
lambda driver: driver.find_element_by_css_selector(
QueryToolLocators.select_file_content_css)
)
else:
table = self.page.driver \
.find_element_by_css_selector("table#contents")
contents = table.get_attribute('innerHTML')
table = self.page.driver.find_element_by_css_selector(
QueryToolLocators.select_file_content_css)
retry_count = 0
while retry_count < 5:
try:
contents = table.get_attribute('innerHTML')
break
except (StaleElementReferenceException, TimeoutException):
retry_count += 1
self.page.click_modal('Cancel')
self.page.wait_for_query_tool_loading_indicator_to_disappear()
@ -107,7 +116,9 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
) != -1, "{0} might be vulnerable to XSS ".format(source)
def _check_file_sorting(self):
self.page.find_by_id("btn-load-file").click()
load_file = self.page.find_by_css_selector(
QueryToolLocators.btn_load_file_css)
load_file.click()
self.page.find_by_css_selector("#contents th[data-column='0']")
# Added time.sleep so that the element to be clicked.
@ -134,7 +145,7 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
if not success:
raise Exception("Unable to sort in ascending order while clicked "
"on 'Name' column")
# Added time.sleep so that the element to be clicked.
time.sleep(0.05)
# Click and Check for sort Descending
@ -143,9 +154,10 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
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.page.find_by_xpath("//th[@data-column='0']"
"/div/span[text()='Name']").click()
self.wait.until(
EC.presence_of_element_located((
By.CSS_SELECTOR,

View File

@ -15,13 +15,14 @@ from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from regression.feature_utils.base_feature_test import BaseFeatureTest
from selenium.webdriver.common.keys import Keys
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.feature_utils.locators import NavMenuLocators
class KeyboardShortcutFeatureTest(BaseFeatureTest):
"""
This feature test will test the keyboard short is working
This feature test will test the keyboard shortcut is working
properly.
"""
@ -85,23 +86,36 @@ class KeyboardShortcutFeatureTest(BaseFeatureTest):
print("OK", file=sys.stderr)
def _update_preferences(self):
self.page.find_by_id("mnu_file").click()
self.page.find_by_id("mnu_preferences").click()
file_menu = self.page.find_by_css_selector(
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()
# Wait till the preference dialogue box is displayed by checking the
# visibility of Show System Object label
self.wait.until(EC.presence_of_element_located(
(By.XPATH, "//*[contains(string(), 'Show system objects?')]"))
(By.XPATH, NavMenuLocators.show_system_objects_pref_label_xpath))
)
self.page.find_by_css_selector(
".ajs-dialog.pg-el-container .ajs-maximize"
).click()
maximize_button = self.page.find_by_css_selector(
NavMenuLocators.maximize_pref_dialogue_css)
maximize_button.click()
browser = self.page.find_by_xpath(
"//*[contains(@class,'aciTreeLi') and contains(.,'Browser')]")
browser_node = self.page.find_by_xpath(
NavMenuLocators.specified_preference_tree_node.format('Browser'))
if self.page.find_by_xpath(
NavMenuLocators.specified_pref_node_exp_status.
format('Browser')).get_attribute('aria-expanded') == 'false':
browser.find_element_by_xpath(
"//*[contains(@class,'aciTreeText') and "
"contains(.,'Keyboard shortcuts')]").click()
ActionChains(self.driver).double_click(browser_node).perform()
keyboard_node = self.page.find_by_xpath(
NavMenuLocators.specified_sub_node_of_pref_tree_node.format(
'Browser', 'Keyboard shortcuts'))
keyboard_node.click()
for s in self.new_shortcuts:
key = self.new_shortcuts[s]['shortcut'][2]

View File

@ -1,32 +0,0 @@
class QueryToolLocatorsCss:
btn_save_file = "#btn-save-file"
btn_save_data = "#btn-save-data"
btn_execute_query = "#btn-flash"
btn_query_dropdown = "#btn-query-dropdown"
btn_auto_rollback = "#btn-auto-rollback"
btn_auto_rollback_check_status = "#btn-auto-rollback > i"
btn_auto_commit = "#btn-auto-commit"
btn_auto_commit_check_status = "#btn-auto-commit > i"
btn_cancel_query = "#btn-cancel-query"
btn_explain = "#btn-explain"
btn_explain_analyze = "#btn-explain-analyze"
btn_explain_options_dropdown = "#btn-explain-options-dropdown"
btn_explain_verbose = "#btn-explain-verbose"
btn_explain_costs = "#btn-explain-costs"
btn_explain_buffers = "#btn-explain-buffers"
btn_explain_timing = "#btn-explain-timing"
btn_clear_dropdown = "#btn-clear-dropdown"
btn_clear = "#btn-clear"
btn_commit = "#btn-commit"
query_editor_panel = "#output-panel"
query_history_selected = "#query_list .selected"
query_history_selected_icon = '#query_list .selected #query_source_icon'
query_history_detail = "#query_detail"
query_history_generated_queries_toggle = '#generated-queries-toggle'
editor_panel = "#output-panel"
query_messages_panel = ".sql-editor-message"
execute_icon = "fa-bolt"
explain_icon = "fa-hand-pointer-o"
explain_analyze_icon = "fa-list-alt"
save_data_icon = "icon-save-data-changes"
commit_icon = "icon-commit"

View File

@ -18,6 +18,8 @@ from selenium.webdriver.common.by import By
from selenium.webdriver import ActionChains
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.feature_utils.locators import NavMenuLocators, \
QueryToolLocators
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
@ -78,35 +80,42 @@ class PGDataypeFeatureTest(BaseFeatureTest):
connection.close()
def _update_preferences(self):
self.page.find_by_id("mnu_file").click()
self.page.find_by_id("mnu_preferences").click()
file_menu = self.page.find_by_css_selector(
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()
wait = WebDriverWait(self.page.driver, 10)
# Wait till the preference dialogue box is displayed by checking the
# visibility of Show System Object label
wait.until(EC.presence_of_element_located(
(By.XPATH, "//*[contains(string(), 'Show system objects?')]"))
(By.XPATH, NavMenuLocators.show_system_objects_pref_label_xpath))
)
self.page.find_by_css_selector(
".ajs-dialog.pg-el-container .ajs-maximize").click()
maximize_button = self.page.find_by_css_selector(
NavMenuLocators.maximize_pref_dialogue_css)
maximize_button.click()
sql_editor = self.page.find_by_xpath(
"//*[contains(@class,'aciTreeLi') and contains(.,'Query Tool')]")
NavMenuLocators.specified_preference_tree_node.
format('Query Tool'))
if self.page.find_by_xpath(
NavMenuLocators.specified_pref_node_exp_status.
format('Query Tool')).\
get_attribute('aria-expanded') == 'false':
ActionChains(self.driver).double_click(sql_editor).perform()
sql_editor.find_element_by_xpath(
"//*[contains(@class,'aciTreeText') and contains(.,'Options')]"
).click()
option_node = self.page.find_by_xpath(
NavMenuLocators.specified_sub_node_of_pref_tree_node.format(
'Query Tool', 'Options'))
option_node.click()
insert_bracket_pairs_control = self.page.find_by_xpath(
"//div[contains(@class,'pgadmin-control-group') and "
"contains(.,'Insert bracket pairs?')]"
)
switch_btn = insert_bracket_pairs_control.\
find_element_by_class_name('toggle')
# check if switch is on then only toggle.
if 'off' not in switch_btn.get_attribute('class'):
switch_btn.click()
self.page.set_switch_box_status(
NavMenuLocators.insert_bracket_pair_switch_btn, 'No')
# save and close the preference dialog.
self.page.click_modal('Save')
@ -121,8 +130,10 @@ class PGDataypeFeatureTest(BaseFeatureTest):
'yellow','green','blue','purple');
"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_id("btn-flash").click()
self._clear_query_tool()
execute_query = self.page.find_by_css_selector(
QueryToolLocators.btn_execute_query_css)
execute_query.click()
self.page.clear_query_tool()
def runTest(self):
self.page.wait_for_spinner_to_disappear()
@ -150,7 +161,9 @@ class PGDataypeFeatureTest(BaseFeatureTest):
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()
execute_query = self.page.find_by_css_selector(
QueryToolLocators.btn_execute_query_css)
execute_query.click()
wait = WebDriverWait(self.page.driver, 5)
@ -168,12 +181,13 @@ class PGDataypeFeatureTest(BaseFeatureTest):
))
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas"))
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
)
# For every sample data-type value, check the expected output.
cnt = 2
cells = canvas.find_elements_by_css_selector('.slick-cell')
cells = canvas.find_elements_by_css_selector(
QueryToolLocators.query_output_cells)
# remove first element as it is row number.
cells.pop(0)
for val, cell, datatype in zip(
@ -202,7 +216,7 @@ class PGDataypeFeatureTest(BaseFeatureTest):
"for datatype {0}\n{1} does not match with {2}".format(
datatype, val, expected_output
)
self._clear_query_tool()
self.page.clear_query_tool()
def construct_select_query(self, batch):
query = 'SELECT '
@ -233,18 +247,6 @@ class PGDataypeFeatureTest(BaseFeatureTest):
datatype, source_code, string_to_find
)
def _clear_query_tool(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
)
ActionChains(self.driver)\
.move_to_element(self.page.find_by_xpath("//*[@id='btn-clear']"))\
.perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear']")
)
self.page.click_modal('Yes')
def _is_datatype_available_in_current_database(self, datatype):
if datatype == '':
return True

View File

@ -11,9 +11,11 @@ import os
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import ElementClickInterceptedException
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.python_test_utils import test_utils
from regression.python_test_utils import test_gui_helper
from regression.feature_utils.locators import NavMenuLocators
class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
@ -61,22 +63,47 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.page.toggle_open_tree_item(self.database_name)
# Backup
self.driver.find_element_by_link_text("Tools").click()
retry = 3
while retry > 0:
try:
self.driver.find_element_by_link_text(
NavMenuLocators.tools_menu_link_text).click()
break
except ElementClickInterceptedException:
retry -= 1
self.page.find_by_partial_link_text("Backup...").click()
backup_object = self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, NavMenuLocators.backup_obj_css)))
backup_object.click()
self.wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, ".file [name='file']")))
self.wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, ".file [name='file']"))).click()
# Enter the file name of the backup to be taken
self.wait.until(EC.visibility_of_element_located(
(By.NAME, NavMenuLocators.backup_filename_txt_box_name)))
element = self.wait.until(EC.element_to_be_clickable(
(By.NAME, NavMenuLocators.backup_filename_txt_box_name)))
element.click()
self.page.fill_input_by_field_name(
"file", "test_backup", loose_focus=True)
NavMenuLocators.backup_filename_txt_box_name,
"test_backup", loose_focus=True)
self.page.find_by_xpath("//button[contains(@class,'fa-save') "
"and contains(.,'Backup')]").click()
# Click on the take Backup button
take_bckup = self.page.find_by_xpath(
NavMenuLocators.backup_btn_xpath)
click = True
while click:
try:
take_bckup.click()
if self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_name(
NavMenuLocators.backup_filename_txt_box_name)):
click = False
except Exception as e:
pass
self.page.find_by_css_selector('.ajs-bg-bgprocess')
# Wait for the backup status alertfier
self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR,
NavMenuLocators.bcg_process_status_alertifier_css)))
status = test_utils.get_watcher_dialogue_status(self)
@ -86,7 +113,10 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.assertEquals(status, "Successfully completed.")
self.page.find_by_css_selector(
".pg-bg-more-details").click()
NavMenuLocators.status_alertifier_more_btn_css).click()
self.wait.until(EC.visibility_of_element_located(
(By.XPATH, NavMenuLocators.process_watcher_alertfier)))
backup_file = None
# Check for XSS in Backup details
@ -94,7 +124,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self._check_detailed_window_for_xss('Backup')
else:
command = self.page.find_by_css_selector(
".bg-process-details .bg-detailed-desc").text
NavMenuLocators.process_watcher_detailed_command_canvas_css).\
text
self.assertIn(self.server['name'], str(command))
self.assertIn("from database 'pg_utility_test_db'", str(command))
@ -109,26 +140,41 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
backup_file = command[int(command.find('--file')) +
8:int(command.find('--host')) - 2]
self.page.find_by_xpath("//div[contains(@class,'wcFloatingFocus')"
"]//div[contains(@class,'fa-close')]").click()
close_btn = self.page.find_by_xpath(
NavMenuLocators.process_watcher_close_button_xpath)
close_btn.click()
# Restore
self.driver.find_element_by_link_text("Tools").click()
self.page.find_by_partial_link_text("Restore...").click()
tools_menu = self.driver.find_element_by_link_text(
NavMenuLocators.tools_menu_link_text)
tools_menu.click()
restore_obj = self.page.find_by_css_selector(
NavMenuLocators.restore_obj_css)
restore_obj.click()
self.wait.until(EC.visibility_of_element_located(
(By.NAME, NavMenuLocators.restore_file_name_txt_box_name)))
self.wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, ".file [name='file']")))
self.wait.until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, ".file [name='file']"))).click()
(By.NAME, NavMenuLocators.restore_file_name_txt_box_name))).click()
self.page.fill_input_by_field_name(
"file", "test_backup", loose_focus=True)
NavMenuLocators.restore_file_name_txt_box_name,
"test_backup", loose_focus=True)
self.page.find_by_xpath("//button[contains(@class,'fa-upload')"
" and contains(.,'Restore')]").click()
restore_btn = self.page.find_by_xpath(
NavMenuLocators.restore_button_xpath)
restore_btn.click()
self.page.find_by_css_selector('.ajs-bg-bgprocess')
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_css_selector(
NavMenuLocators.restore_file_name_txt_box_name))
# Wait for the backup status alertfier
self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR,
NavMenuLocators.bcg_process_status_alertifier_css)))
status = test_utils.get_watcher_dialogue_status(self)
@ -138,14 +184,18 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.assertEquals(status, "Successfully completed.")
self.page.find_by_css_selector(
".pg-bg-more-details").click()
NavMenuLocators.status_alertifier_more_btn_css).click()
self.wait.until(EC.visibility_of_element_located(
(By.XPATH, NavMenuLocators.process_watcher_alertfier)))
# Check for XSS in Restore details
if self.is_xss_check:
self._check_detailed_window_for_xss('Restore')
else:
command = self.page.find_by_css_selector(
".bg-process-details .bg-detailed-desc").text
NavMenuLocators.process_watcher_detailed_command_canvas_css).\
text
self.assertIn(self.server['name'], str(command))
if os.name is not 'nt':
@ -153,8 +203,9 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.assertIn("pg_restore", str(command))
self.page.find_by_xpath("//div[contains(@class,'wcFloatingFocus')]"
"//div[contains(@class,'fa-close')]").click()
close_watcher = self.page.find_by_xpath(
NavMenuLocators.process_watcher_close_button_xpath)
close_watcher.click()
if backup_file is not None:
if os.path.isfile(backup_file):
@ -175,7 +226,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
def _check_detailed_window_for_xss(self, tool_name):
source_code = self.page.find_by_css_selector(
".bg-process-details .bg-detailed-desc"
NavMenuLocators.process_watcher_detailed_command_canvas_css
).get_attribute('innerHTML')
self._check_escaped_characters(
source_code,

View File

@ -6,13 +6,15 @@
# This software is released under the PostgreSQL Licence
#
##########################################################################
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
from selenium.common.exceptions import ElementClickInterceptedException
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.python_test_utils import test_utils
from regression.python_test_utils import test_gui_helper
from regression.feature_utils.locators import NavMenuLocators
import random
class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
@ -55,6 +57,8 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
self.server['port'],
self.server['sslmode']
)
self.table_name = self.table_name + str(random.randint(1000, 3000))
test_utils.drop_database(connection, self.database_name)
test_utils.create_database(self.server, self.database_name)
test_utils.create_table(self.server, self.database_name,
@ -66,8 +70,16 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
def runTest(self):
self._open_maintenance_dialogue()
self.page.click_modal('OK')
self.page.find_by_css_selector('.ajs-bg-bgprocess')
self._verify_command()
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element_by_xpath(
NavMenuLocators.maintenance_operation))
# Wait for the backup status alertfier
self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR,
NavMenuLocators.bcg_process_status_alertifier_css)))
self.verify_command()
def _open_maintenance_dialogue(self):
self.page.toggle_open_server(self.server['name'])
@ -78,30 +90,49 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
self.page.toggle_open_tree_item('public')
self.page.toggle_open_tables_node()
self.page.select_tree_item(self.table_name)
retry = 3
while retry > 0:
try:
tools_menu = self.driver.find_element_by_link_text(
NavMenuLocators.tools_menu_link_text)
tools_menu.click()
break
except ElementClickInterceptedException:
retry -= 1
maintenance_obj = self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, NavMenuLocators.maintenance_obj_css)))
maintenance_obj.click()
self.driver.find_element_by_link_text("Tools").click()
self.page.find_by_partial_link_text("Maintenance...").click()
time.sleep(0.5)
self.page.check_if_element_exist_by_xpath(
NavMenuLocators.maintenance_operation, 10)
def _verify_command(self):
def verify_command(self):
status = test_utils.get_watcher_dialogue_status(self)
if status != "Successfully completed.":
test_gui_helper.close_bgprocess_popup(self)
self.assertEquals(status, "Successfully completed.")
self.page.find_by_css_selector(".pg-bg-more-details").click()
self.page.find_by_css_selector(
NavMenuLocators.status_alertifier_more_btn_css).click()
self.wait.until(EC.visibility_of_element_located(
(By.XPATH, NavMenuLocators.process_watcher_alertfier)))
command = self.page.find_by_css_selector(
".bg-process-details .bg-detailed-desc").text
NavMenuLocators.
process_watcher_detailed_command_canvas_css).text
if self.test_level == 'database':
self.assertEquals(command, "VACUUM "
"(VERBOSE)\nRunning Query:"
self.assertEquals(command, "VACUUM (VERBOSE)\nRunning Query:"
"\nVACUUM VERBOSE;")
elif self.is_xss_check and self.test_level == 'table':
# Check for XSS in the dialog
source_code = self.page.find_by_css_selector(
".bg-process-details .bg-detailed-desc"
NavMenuLocators.
process_watcher_detailed_command_canvas_css
).get_attribute('innerHTML')
self._check_escaped_characters(
self.check_escaped_characters(
source_code,
'&lt;h1&gt;test_me&lt;/h1&gt;',
'Maintenance detailed window'
@ -112,12 +143,14 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
"\nVACUUM VERBOSE"
" public." + self.table_name + ";")
self.page.find_by_css_selector(
"div.wcFloatingFocus div.fa-close").click()
self.page.find_by_xpath(
NavMenuLocators.process_watcher_close_button_xpath).click()
def after(self):
test_gui_helper.close_bgprocess_popup(self)
self.page.remove_server(self.server)
test_utils.delete_table(self.server, self.test_db,
self.table_name)
connection = test_utils.get_db_connection(
self.server['db'],
self.server['username'],
@ -128,7 +161,7 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
)
test_utils.drop_database(connection, self.database_name)
def _check_escaped_characters(self, source_code, string_to_find, source):
def check_escaped_characters(self, source_code, string_to_find, source):
# For XSS we need to search against element's html code
assert source_code.find(string_to_find) != - \
1, "{0} might be vulnerable to XSS ".format(source)

View File

@ -15,6 +15,7 @@ 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
from regression.feature_utils.locators import QueryToolLocators
class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
@ -55,7 +56,10 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
test_utils.create_table(self.server, self.test_db,
self.second_table_name)
self._locate_database_tree_node()
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
self.page.toggle_open_tree_item(self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
@ -64,64 +68,64 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
print("\nAuto complete ALTER keyword... ", file=sys.stderr, end="")
self._auto_complete("A", "ALTER")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete BEGIN keyword... ", file=sys.stderr, end="")
self._auto_complete("BE", "BEGIN")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete CASCADED keyword... ", file=sys.stderr, end="")
self._auto_complete("CAS", "CASCADED")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete SELECT keyword... ", file=sys.stderr, end="")
self._auto_complete("SE", "SELECT")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete pg_backend_pid() function ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT pg_", "pg_backend_pid()")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete current_query() function ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT current_", "current_query()")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete function with argument ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT pg_st", "pg_stat_file(filename)")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete schema other than default start with test_ ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT * FROM te", self.first_schema_name)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete schema other than default starts with comp_ ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT * FROM co", self.second_schema_name)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete first table in public schema ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT * FROM public.", self.first_table_name)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete second table in public schema ... ",
file=sys.stderr, end="")
self._auto_complete("SELECT * FROM public.", self.second_table_name)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete JOIN second table with after schema name ... ",
file=sys.stderr, end="")
@ -129,7 +133,7 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
" JOIN public."
self._auto_complete(query, self.second_table_name)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete JOIN ON some columns ... ",
file=sys.stderr, end="")
@ -140,54 +144,51 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest):
".some_column"
self._auto_complete(query, expected_string)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("Auto complete JOIN ON some columns using tabel alias ... ",
print("Auto complete JOIN ON some columns using table alias ... ",
file=sys.stderr, end="")
query = "SELECT * FROM public." + self.first_table_name + \
" t1 JOIN public." + self.second_table_name + " t2 ON t2."
self._auto_complete(query, "some_column = t1.some_column")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
def after(self):
self.page.remove_server(self.server)
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(self.test_db)
def _clear_query_tool(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
)
ActionChains(self.driver) \
.move_to_element(self.page.find_by_xpath("//*[@id='btn-clear']")) \
.perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear']")
)
self.page.click_modal('Yes')
test_utils.delete_table(self.server, self.test_db,
self.first_table_name)
test_utils.delete_table(self.server, self.test_db,
self.second_table_name)
def _auto_complete(self, word, expected_string):
self.page.fill_codemirror_area_with(word)
ActionChains(self.page.driver).key_down(
Keys.CONTROL).send_keys(Keys.SPACE).key_up(Keys.CONTROL).perform()
# if IntelliSense is present then verify this
if self.page.check_if_element_exist_by_xpath(
"//ul[@class='CodeMirror-hints default']", 2):
hint_displayed = False
retry = 3
while retry > 0:
ActionChains(self.page.driver).key_down(
Keys.CONTROL).send_keys(Keys.SPACE).key_up(
Keys.CONTROL).perform()
if self.page.check_if_element_exist_by_xpath(
QueryToolLocators.code_mirror_hint_box_xpath, 20):
hint_displayed = True
break
else:
retry -= 1
if hint_displayed:
# if IntelliSense is present then verify this
self.page.find_by_xpath(
"//ul[contains(@class, 'CodeMirror-hints') and "
"contains(., '" + expected_string + "')]")
QueryToolLocators.code_mirror_hint_item_xpath.format(
expected_string))
else:
# if no IntelliSense is present it means there is only one option
# so check if required string is present in codeMirror
code_mirror = self.page.find_by_xpath(
"//pre[@class=' CodeMirror-line ']/span")
code_mirror_text = code_mirror.text
if expected_string not in code_mirror_text:
raise Exception("Required String %s is not "
"present" % expected_string)
code_mirror = self.driver.find_elements_by_xpath(
QueryToolLocators.code_mirror_data_xpath)
for data in code_mirror:
code_mirror_text = data.text
print("Single entry..........")
if expected_string not in code_mirror_text:
print("single entry exception.........")
raise Exception("Required String %s is not "
"present" % expected_string)

View File

@ -14,10 +14,10 @@ import random
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from .locators import QueryToolLocatorsCss
from regression.feature_utils.locators import QueryToolLocators
class QueryToolJourneyTest(BaseFeatureTest):
@ -31,9 +31,12 @@ class QueryToolJourneyTest(BaseFeatureTest):
test_table_name = ""
test_editable_table_name = ""
invalid_table_name = ""
def before(self):
self.test_table_name = "test_table" + str(random.randint(1000, 3000))
self.invalid_table_name = \
"table_that_doesnt_exist_" + str(random.randint(1000, 3000))
test_utils.create_table(
self.server, self.test_db, self.test_table_name)
@ -52,10 +55,11 @@ class QueryToolJourneyTest(BaseFeatureTest):
driver_version = test_utils.get_driver_version()
self.driver_version = float('.'.join(driver_version.split('.')[:2]))
self.wait = WebDriverWait(self.page.driver, 10)
def runTest(self):
self._navigate_to_query_tool()
self._execute_query(
self.page.execute_query(
"SELECT * FROM %s ORDER BY value " % self.test_table_name)
print("Copy rows...", file=sys.stderr, end="")
@ -78,7 +82,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
self._test_query_sources_and_generated_queries()
print(" OK.", file=sys.stderr)
print("Updatable resultsets...", file=sys.stderr, end="")
print("Updatable result sets...", file=sys.stderr, end="")
self._test_updatable_resultset()
print(" OK.", file=sys.stderr)
@ -87,9 +91,14 @@ class QueryToolJourneyTest(BaseFeatureTest):
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()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
select_row = self.page.find_by_xpath(
QueryToolLocators.output_row_xpath.format('1'))
select_row.click()
copy_row = self.page.find_by_css_selector(
QueryToolLocators.copy_button_css)
copy_row.click()
self.assertEqual('"Some-Name"\t"6"\t"some info"',
pyperclip.paste())
@ -100,86 +109,85 @@ class QueryToolJourneyTest(BaseFeatureTest):
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(
"//*[@data-test='output-column-header' and "
"contains(., 'some_column')]"
).click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
column_header = self.page.find_by_css_selector(
QueryToolLocators.output_column_header_css.format('some_column'))
column_header.click()
copy_btn = self.page.find_by_css_selector(
QueryToolLocators.copy_button_css)
copy_btn.click()
self.assertTrue('"Some-Name"' in pyperclip.paste())
self.assertTrue('"Some-Other-Name"' in pyperclip.paste())
self.assertTrue('"Yet-Another-Name"' in pyperclip.paste())
def _test_history_tab(self):
self.__clear_query_tool()
self.page.clear_query_tool()
editor_input = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_editor_panel)
QueryToolLocators.query_editor_panel)
self.page.click_element(editor_input)
self._execute_query("SELECT * FROM table_that_doesnt_exist")
self.page.execute_query("SELECT * FROM %s" % self.invalid_table_name)
self.page.click_tab("Query History")
selected_history_entry = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_selected)
self.assertIn("SELECT * FROM table_that_doesnt_exist",
QueryToolLocators.query_history_selected)
self.assertIn("SELECT * FROM %s" % self.invalid_table_name,
selected_history_entry.text)
failed_history_detail_pane = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_detail)
QueryToolLocators.query_history_detail)
self.assertIn(
"Error Message relation \"table_that_doesnt_exist\" "
"does not exist", failed_history_detail_pane.text
"Error Message relation \"%s\" does not exist"
% self.invalid_table_name,
failed_history_detail_pane.text
)
self.page.wait_for_element(lambda driver: driver
.find_element_by_css_selector(
"#query_list> .query-group>ul>li"))
self.page.wait_for_elements(
lambda driver: driver.find_elements_by_css_selector(
QueryToolLocators.query_history_entries))
# get the query history rows and click the previous query row which
# was executed and verify it
history_rows = self.driver.find_elements_by_css_selector(
"#query_list> .query-group>ul>li")
QueryToolLocators.query_history_entries)
history_rows[1].click()
selected_history_entry = self.page.find_by_css_selector(
"#query_list .selected")
QueryToolLocators.query_history_selected)
self.assertIn(("SELECT * FROM %s ORDER BY value" %
self.test_table_name),
selected_history_entry.text)
# check second(invalid) query also exist in the history tab with error
newly_selected_history_entry = self.page.find_by_xpath(
"//*[@id='query_list']/div/ul/li[1]")
newly_selected_history_entry = history_rows[0]
self.page.click_element(newly_selected_history_entry)
selected_invalid_history_entry = self.page.find_by_css_selector(
"#query_list .selected .entry.error .query")
invalid_history_entry = self.page.find_by_css_selector(
QueryToolLocators.invalid_query_history_entry_css)
self.assertIn("SELECT * FROM table_that_doesnt_exist",
selected_invalid_history_entry.text)
self.assertIn("SELECT * FROM %s" % self.invalid_table_name,
invalid_history_entry.text)
self.page.click_tab("Query Editor")
self.__clear_query_tool()
self.page.clear_query_tool()
self.page.click_element(editor_input)
# Check if 15 more query executed then the history should contain 17
# entries.
self.page.fill_codemirror_area_with("SELECT * FROM hats")
for _ in range(15):
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab("Query History")
query_we_need_to_scroll_to = self.page.find_by_xpath(
"//*[@id='query_list']/div/ul/li[17]")
query_list = self.page.wait_for_elements(
lambda driver: driver.find_elements_by_css_selector(
QueryToolLocators.query_history_entries))
self.page.click_element(query_we_need_to_scroll_to)
for _ in range(17):
ActionChains(self.page.driver) \
.send_keys(Keys.ARROW_DOWN) \
.perform()
self._assert_clickable(query_we_need_to_scroll_to)
self.assertTrue(17, len(query_list))
def _test_query_sources_and_generated_queries(self):
self.__clear_query_history()
@ -193,12 +201,12 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.click_tab("Query History")
history_entries_icons = [
QueryToolLocatorsCss.commit_icon,
QueryToolLocatorsCss.save_data_icon,
QueryToolLocatorsCss.save_data_icon,
QueryToolLocatorsCss.execute_icon,
QueryToolLocatorsCss.explain_analyze_icon,
QueryToolLocatorsCss.explain_icon
QueryToolLocators.commit_icon,
QueryToolLocators.save_data_icon,
QueryToolLocators.save_data_icon,
QueryToolLocators.execute_icon,
QueryToolLocators.explain_analyze_icon,
QueryToolLocators.explain_icon
]
history_entries_queries = [
@ -217,33 +225,31 @@ class QueryToolJourneyTest(BaseFeatureTest):
def _test_toggle_generated_queries(self):
xpath = '//li[contains(@class, "pgadmin-query-history-entry")]'
self.assertTrue(self.page.check_if_element_exist_by_xpath(xpath))
toggle_el = self.page.find_by_xpath(
'//input[@id ="generated-queries-toggle"]/..'
)
toggle_el.click()
self.page.set_switch_box_status(
QueryToolLocators.show_query_internally_btn, 'No')
self.assertFalse(self.page.check_if_element_exist_by_xpath(xpath))
toggle_el.click()
self.page.set_switch_box_status(
QueryToolLocators.show_query_internally_btn, 'Yes')
self.assertTrue(self.page.check_if_element_exist_by_xpath(xpath))
def _test_updatable_resultset(self):
if self.driver_version < 2.8:
return
self.page.click_tab("Query Editor")
# Select all data (contains the primary key -> should be editable)
self.__clear_query_tool()
self.page.clear_query_tool()
query = "SELECT pk_column, normal_column FROM %s" \
% self.test_editable_table_name
self._check_query_results_editable(query, True)
# Select data without primary keys -> should not be editable
self.__clear_query_tool()
self.page.clear_query_tool()
query = "SELECT normal_column FROM %s" % self.test_editable_table_name
self._check_query_results_editable(query, False)
def _execute_sources_test_queries(self):
self.__clear_query_tool()
self.page.clear_query_tool()
self._explain_query(
"SELECT * FROM %s;"
@ -253,17 +259,17 @@ class QueryToolJourneyTest(BaseFeatureTest):
"SELECT * FROM %s;"
% self.test_editable_table_name
)
self._execute_query(
self.page.execute_query(
"SELECT * FROM %s;"
% self.test_editable_table_name
)
# Turn off autocommit
query_options = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_options.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit).click()
QueryToolLocators.btn_auto_commit).click()
query_options.click() # Click again to close dropdown
self._update_numeric_cell(2, 10)
@ -272,24 +278,25 @@ class QueryToolJourneyTest(BaseFeatureTest):
# Turn on autocommit
query_options = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_options.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit).click()
QueryToolLocators.btn_auto_commit).click()
query_options.click() # Click again to close dropdown
def _check_history_queries_and_icons(self, history_queries, history_icons):
# Select first query history entry
self.page.find_by_xpath("//*[@id='query_list']/div/ul/li[1]").click()
self.page.find_by_css_selector(
QueryToolLocators.query_history_specific_entry.format(1)).click()
for icon, query in zip(history_icons, history_queries):
# Check query
query_history_selected_item = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_selected
QueryToolLocators.query_history_selected
)
self.assertIn(query, query_history_selected_item.text)
# Check source icon
query_history_selected_icon = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_selected_icon)
QueryToolLocators.query_history_selected_icon)
icon_classes = query_history_selected_icon.get_attribute('class')
icon_classes = icon_classes.split(" ")
self.assertTrue(icon in icon_classes)
@ -302,47 +309,37 @@ class QueryToolJourneyTest(BaseFeatureTest):
"""
Updates a numeric cell in the first row of the resultset
"""
xpath = '//div[contains(@class, "slick-row") and ' \
'contains(@style, "top:0px")]'
xpath += '/div[contains(@class, "slick-cell") and ' \
'contains(@class, "r' + str(cell_index) + '")]'
cell_el = self.page.find_by_xpath(xpath)
self.page.check_if_element_exist_by_xpath(
"//div[contains(@style, 'top:0px')]//div[contains(@class, "
"'l{0} r{1}')]".format(cell_index, cell_index))
cell_el = self.page.find_by_xpath(
"//div[contains(@style, 'top:0px')]//div[contains(@class, "
"'l{0} r{1}')]".format(cell_index, cell_index))
ActionChains(self.driver).double_click(cell_el).perform()
ActionChains(self.driver).send_keys(value). \
send_keys(Keys.ENTER).perform()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_save_data).click()
QueryToolLocators.btn_save_data).click()
def _insert_data_into_test_editable_table(self):
self.page.click_tab("Query Editor")
self.__clear_query_tool()
self._execute_query(
self.page.clear_query_tool()
self.page.execute_query(
"INSERT INTO %s VALUES (1, 1), (2, 2);"
% self.test_editable_table_name
)
def __clear_query_tool(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
)
ActionChains(self.driver)\
.move_to_element(self.page.find_by_xpath("//*[@id='btn-clear']"))\
.perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear']")
)
self.page.click_modal('Yes')
def __clear_query_history(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
self.page.find_by_css_selector(
QueryToolLocators.btn_clear_dropdown)
)
ActionChains(self.driver)\
.move_to_element(
self.page.find_by_xpath(
"//*[@id='btn-clear-history']")).perform()
self.page.find_by_css_selector(
QueryToolLocators.btn_clear_history)).perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-history']")
self.page.find_by_css_selector(QueryToolLocators.btn_clear_history)
)
self.page.click_modal('Yes')
@ -353,44 +350,39 @@ class QueryToolJourneyTest(BaseFeatureTest):
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
def _execute_query(self, query):
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
def _explain_query(self, query):
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain).click()
QueryToolLocators.btn_explain).click()
def _explain_analyze_query(self, query):
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_analyze).click()
QueryToolLocators.btn_explain_analyze).click()
def _commit_transaction(self):
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_commit).click()
QueryToolLocators.btn_commit).click()
def _assert_clickable(self, element):
self.page.click_element(element)
def _check_query_results_editable(self, query, should_be_editable):
self._execute_query(query)
self.page.wait_for_spinner_to_disappear()
self.page.execute_query(query)
# Check if the first cell in the first row is editable
is_editable = self._check_cell_editable(1)
self.assertEqual(is_editable, should_be_editable)
def _check_cell_editable(self, cell_index):
"""
Checks if a cell in the first row of the resultset is editable
"""
xpath = '//div[contains(@class, "slick-row") and ' \
'contains(@style, "top:0px")]'
xpath += '/div[contains(@class, "slick-cell") and ' \
'contains(@class, "r' + str(cell_index) + '")]'
cell_el = self.page.find_by_xpath(xpath)
"""Checks if a cell in the first row of the resultset is editable"""
self.page.check_if_element_exist_by_xpath(
"//div[contains(@style, 'top:0px')]//div[contains(@class, "
"'l{0} r{1}')]".format(cell_index, cell_index))
cell_el = self.page.find_by_xpath(
"//div[contains(@style, 'top:0px')]//div[contains(@class, "
"'l{0} r{1}')]".format(cell_index, cell_index))
# Get existing value
cell_value = int(cell_el.text)
new_value = cell_value + 1
@ -401,6 +393,12 @@ class QueryToolJourneyTest(BaseFeatureTest):
# Check if the value was updated
return int(cell_el.text) == new_value
def _check_can_add_row(self):
return self.page.check_if_element_exist_by_xpath(
QueryToolLocators.new_row_xpath)
def after(self):
self.page.close_query_tool()
self.page.remove_server(self.server)
test_utils.delete_table(
self.server, self.test_db, self.test_table_name)

View File

@ -10,15 +10,16 @@
from __future__ import print_function
import sys
from selenium.common.exceptions import StaleElementReferenceException
from selenium.webdriver import ActionChains
from selenium.common.exceptions import StaleElementReferenceException, \
ElementClickInterceptedException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
import config
from .locators import QueryToolLocatorsCss
from regression.feature_utils.locators import \
QueryToolLocators
class QueryToolFeatureTest(BaseFeatureTest):
@ -33,17 +34,20 @@ class QueryToolFeatureTest(BaseFeatureTest):
def before(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
self._locate_database_tree_node()
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
self.page.toggle_open_tree_item(self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
self._reset_options()
self.wait = WebDriverWait(self.page.driver, 10)
def runTest(self):
# on demand result set on scrolling.
print("\nOn demand query result... ",
file=sys.stderr, end="")
self._on_demand_result()
self._clear_query_tool()
self.page.clear_query_tool()
# explain query with verbose and cost
print("Explain query with verbose and cost... ",
@ -51,7 +55,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
if self._supported_server_version():
self._query_tool_explain_with_verbose_and_cost()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
else:
print("Skipped.", file=sys.stderr)
@ -61,7 +65,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
if self._supported_server_version():
self._query_tool_explain_analyze_with_buffers_and_timing()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
else:
print("Skipped.", file=sys.stderr)
@ -69,30 +73,30 @@ class QueryToolFeatureTest(BaseFeatureTest):
print("Auto commit disabled... ", file=sys.stderr, end="")
self._query_tool_auto_commit_disabled()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
# auto commit enabled.
print("Auto commit enabled... ", file=sys.stderr, end="")
self._query_tool_auto_commit_enabled()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
# auto rollback enabled.
print("Auto rollback enabled...", file=sys.stderr, end="")
self._query_tool_auto_rollback_enabled()
print(" OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
# cancel query.
print("Cancel query... ", file=sys.stderr, end="")
self._query_tool_cancel_query()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
# Notify Statements.
print("Capture Notify Statements... ", file=sys.stderr, end="")
self._query_tool_notify_statements()
self._clear_query_tool()
self.page.clear_query_tool()
# explain query with JIT stats
print("Explain query with JIT stats... ",
@ -100,7 +104,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
if self._supported_jit_on_server():
self._query_tool_explain_check_jit_stats()
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
else:
print("Skipped.", file=sys.stderr)
@ -112,33 +116,33 @@ class QueryToolFeatureTest(BaseFeatureTest):
self.page.fill_codemirror_area_with('')
explain_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_options_dropdown)
QueryToolLocators.btn_explain_options_dropdown)
explain_op.click()
# disable Explain options and auto rollback only if they are enabled.
for op in (QueryToolLocatorsCss.btn_explain_verbose,
QueryToolLocatorsCss.btn_explain_costs,
QueryToolLocatorsCss.btn_explain_buffers,
QueryToolLocatorsCss.btn_explain_timing):
for op in (QueryToolLocators.btn_explain_verbose,
QueryToolLocators.btn_explain_costs,
QueryToolLocators.btn_explain_buffers,
QueryToolLocators.btn_explain_timing):
btn = self.page.find_by_css_selector(op)
check = btn.find_element_by_tag_name('i')
if 'visibility-hidden' not in check.get_attribute('class'):
btn.click()
query_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_op.click()
# disable auto rollback only if they are enabled
btn = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_rollback)
QueryToolLocators.btn_auto_rollback)
check = btn.find_element_by_tag_name('i')
if 'visibility-hidden' not in check.get_attribute('class'):
btn.click()
# enable autocommit only if it's disabled
btn = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit)
QueryToolLocators.btn_auto_commit)
check = btn.find_element_by_tag_name('i')
if 'visibility-hidden' in check.get_attribute('class'):
btn.click()
@ -146,23 +150,6 @@ class QueryToolFeatureTest(BaseFeatureTest):
# close menu
query_op.click()
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(self.test_db)
def _clear_query_tool(self):
self.page.click_element(self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_clear_dropdown)
)
ActionChains(self.driver) \
.move_to_element(self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_clear)).perform()
self.page.click_element(
self.page.find_by_css_selector(QueryToolLocatorsCss.btn_clear)
)
self.page.click_modal('Yes')
def _on_demand_result(self):
ON_DEMAND_CHUNKS = 2
row_id_to_find = config.ON_DEMAND_RECORD_COUNT * ON_DEMAND_CHUNKS
@ -175,126 +162,133 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format(
print("\nOn demand result set on scrolling... ",
file=sys.stderr, end="")
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
# wait for header of the table to be visible
wait.until(EC.visibility_of_element_located(
(By.XPATH, '//div[@class="slick-header-columns"]')))
self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
wait.until(EC.presence_of_element_located(
(By.XPATH,
'//span[@data-row="0" and text()="1"]'))
)
self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR,
QueryToolLocators.query_output_cells)))
# 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());"
)
canvas = self.page.find_by_css_selector(
QueryToolLocators.query_output_canvas_css)
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
self._check_ondemand_result(row_id_to_find, canvas)
self._check_ondemand_result(row_id_to_find)
print("OK.", file=sys.stderr)
print("On demand result set on grid select all... ",
file=sys.stderr, end="")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
# wait for header of the table to be visible
wait.until(EC.visibility_of_element_located(
(By.XPATH, '//div[@class="slick-header-columns"]')))
canvas = self.page.find_by_css_selector(
QueryToolLocators.query_output_canvas_css)
# wait for first row to contain value
wait.until(EC.presence_of_element_located(
(By.XPATH,
'//span[@data-row="0" and text()="1"]'))
# wait for the rows in the table to be displayed
self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR,
QueryToolLocators.query_output_cells))
)
wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, ".slick-header-column"))).click()
# Select all rows in a table
multiple_check = True
count = 0
while multiple_check:
try:
select_all = self.wait.until(EC.element_to_be_clickable(
(By.XPATH, QueryToolLocators.select_all_column)))
select_all.click()
multiple_check = False
except (StaleElementReferenceException,
ElementClickInterceptedException):
count += 1
pass
print(count)
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
self._check_ondemand_result(row_id_to_find, canvas)
self._check_ondemand_result(row_id_to_find)
print("OK.", file=sys.stderr)
print("On demand result set on column select all... ",
file=sys.stderr, end="")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
# wait for header of the table to be visible
wait.until(EC.visibility_of_element_located(
(By.XPATH, '//div[@class="slick-header-columns"]')))
self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
wait.until(EC.presence_of_element_located(
(By.XPATH,
'//span[@data-row="0" and text()="1"]'))
# wait for the rows in the table to be displayed
self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR,
QueryToolLocators.query_output_cells))
)
# 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()
column_1 = \
self.page.find_by_css_selector(
QueryToolLocators.output_column_header_css.format('id1'))
column_1.click()
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
self._check_ondemand_result(row_id_to_find, canvas)
self._check_ondemand_result(row_id_to_find)
print("OK.", file=sys.stderr)
def _check_ondemand_result(self, row_id_to_find, canvas):
def _check_ondemand_result(self, row_id_to_find):
# 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_ele = self.page.find_by_css_selector()
scroll = 10
while scroll:
canvas_ele = self.page.find_by_css_selector('.grid-canvas')
scrolling_height = canvas_ele.size['height']
self.driver.execute_script(
"pgAdmin.SqlEditor.jquery('.slick-viewport')"
".scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas')"
".height());"
)
import time
time.sleep(0.5)
if canvas_ele.size['height'] == scrolling_height:
break
else:
scroll -= 1
canvas.find_element_by_xpath(
'//span[text()="{}"]'.format(row_id_to_find)
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.output_column_data_xpath.format(row_id_to_find)
))
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)
explain_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_options_dropdown)
QueryToolLocators.btn_explain_options_dropdown)
explain_op.click()
# disable Explain options and auto rollback only if they are enabled.
for op in (QueryToolLocatorsCss.btn_explain_verbose,
QueryToolLocatorsCss.btn_explain_costs):
for op in (QueryToolLocators.btn_explain_verbose,
QueryToolLocators.btn_explain_costs):
self.page.find_by_css_selector(op).click()
explain_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain).click()
QueryToolLocators.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"))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
)
# Search for 'Output' word in result (verbose option)
@ -307,40 +301,38 @@ SELECT generate_series(1, 1000) as id order by id desc"""
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)
self.page.fill_codemirror_area_with(query)
explain_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_options_dropdown)
QueryToolLocators.btn_explain_options_dropdown)
explain_op.click()
# disable Explain options and auto rollback only if they are enabled.
for op in (QueryToolLocatorsCss.btn_explain_buffers,
QueryToolLocatorsCss.btn_explain_timing):
for op in (QueryToolLocators.btn_explain_buffers,
QueryToolLocators.btn_explain_timing):
self.page.find_by_css_selector(op).click()
explain_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_analyze).click()
QueryToolLocators.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 (buffers option)
canvas.find_element_by_xpath(
"//*[contains(string(), 'Shared Read Blocks')]"
self.wait.until(EC.presence_of_element_located(
(By.XPATH, QueryToolLocators.output_cell_xpath.format(1, 1)))
)
result = self.page.find_by_xpath(
QueryToolLocators.output_cell_xpath.format(1, 1))
# Search for 'Shared Read Blocks' word in result (buffers option)
self.assertIn('Shared Read Blocks', result.text)
# Search for 'Actual Total Time' word in result (timing option)
canvas.find_element_by_xpath(
"//*[contains(string(), 'Actual Total Time')]"
)
self.assertIn('Actual Total Time', result.text)
def _query_tool_auto_commit_disabled(self):
table_name = 'query_tool_auto_commit_disabled_table'
@ -349,32 +341,31 @@ SELECT generate_series(1, 1000) as id order by id desc"""
-- 3. ROLLBACK transaction.
-- 4. Check if table is *NOT* created.
CREATE TABLE public.{}();""".format(table_name)
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with(query)
# open auto commit option and disable it
query_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit).click()
QueryToolLocators.btn_auto_commit).click()
# close option
query_op.click()
# execute query
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "CREATE TABLE")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
"CREATE TABLE message does not displayed")
# do the ROLLBACK and check if the table is present or not
self._clear_query_tool()
self.page.clear_query_tool()
query = """-- 1. (Done) Disable auto commit.
-- 2. (Done) Create table in public schema.
-- 3. ROLLBACK transaction.
@ -382,16 +373,15 @@ CREATE TABLE public.{}();""".format(table_name)
ROLLBACK;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "ROLLBACK")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('ROLLBACK')),
"ROLLBACK message does not displayed")
self._clear_query_tool()
self.page.clear_query_tool()
query = """-- 1. (Done) Disable auto commit.
-- 2. (Done) Create table in public schema.
-- 3. (Done) ROLLBACK transaction.
@ -400,16 +390,15 @@ SELECT relname FROM pg_class
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).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")))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(text(), '{}')]".format(table_name))
QueryToolLocators.output_column_data_xpath.format(table_name))
assert len(el) == 0, "Table '{}' created with auto commit disabled " \
"and without any explicit commit.".format(
@ -423,7 +412,7 @@ SELECT relname FROM pg_class
ROLLBACK;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
@ -437,23 +426,21 @@ END;"""
self.page.fill_codemirror_area_with(query)
wait = WebDriverWait(self.page.driver, 10)
query_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit).click()
QueryToolLocators.btn_auto_commit).click()
query_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self._clear_query_tool()
self.page.clear_query_tool()
table_name = 'query_tool_auto_commit_enabled_table'
query = """-- 1. (Done) END any open transaction.
@ -463,37 +450,29 @@ END;"""
-- 5. Check if table is created event after ROLLBACK.
CREATE TABLE public.{}();""".format(table_name)
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "CREATE TABLE")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
"CREATE TABLE message does not displayed")
self._clear_query_tool()
self.page.clear_query_tool()
query = """-- 1. (Done) END any open transaction if any.
-- 2. (Done) Enable auto commit.
-- 3. (Done) Create table in public schema.
-- 4. ROLLBACK transaction
-- 5. Check if table is created event after ROLLBACK.
ROLLBACK;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "ROLLBACK")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('ROLLBACK')),
"ROLLBACK message does not displayed")
self._clear_query_tool()
self.page.clear_query_tool()
query = """-- 1. (Done) END any open transaction if any.
-- 2. (Done) Enable auto commit.
-- 3. (Done) Create table in public schema.
@ -503,17 +482,16 @@ SELECT relname FROM pg_class
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.click_tab('Data Output')
self.page.wait_for_query_tool_loading_indicator_to_disappear()
canvas = wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, "#datagrid .slick-viewport .grid-canvas")))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(text(), '{}')]".format(table_name))
QueryToolLocators.output_column_data_xpath.format(table_name))
assert len(el) != 0, "Table '{}' is not created with auto " \
"commit enabled.".format(table_name)
@ -527,12 +505,11 @@ SELECT relname FROM pg_class
-- 5. END transaction.
-- 6. Check if table is *NOT* created after ending transaction.
END;"""
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with(query)
query_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_op.click()
# uncheckt auto commit and check auto-rollback
@ -542,10 +519,10 @@ END;"""
query_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self._clear_query_tool()
self.page.clear_query_tool()
query = """-- 1. (Done) END any open transaction.
-- 2. Enable auto rollback and disable auto commit.
@ -554,21 +531,14 @@ END;"""
-- 5. END transaction.
-- 6. Check if table is *NOT* created after ending transaction.
CREATE TABLE public.{}();""".format(table_name)
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "CREATE TABLE")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
"CREATE TABLE message does not displayed")
self.page.clear_query_tool()
self._clear_query_tool()
query = """-- 1. (Done) END any open transaction.
-- 2. (Done) Enable auto rollback and disable auto commit.
-- 3. (Done) Create table in public schema.
@ -576,18 +546,14 @@ CREATE TABLE public.{}();""".format(table_name)
-- 5. END transaction.
-- 6. Check if table is *NOT* created after ending transaction.
SELECT 1/0;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "division by zero")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('division by zero')),
"division by zero message does not displayed")
self.page.clear_query_tool()
self._clear_query_tool()
query = """-- 1. (Done) END any open transaction.
-- 2. (Done) Enable auto rollback and disable auto commit.
-- 3. (Done) Create table in public schema.
@ -595,19 +561,15 @@ SELECT 1/0;"""
-- 5. END transaction.
-- 6. Check if table is *NOT* created after ending transaction.
END;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'contains(string(), "Query returned successfully")]'
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.
format('Query returned successfully')),
"Query returned successfully message does not displayed")
self.page.clear_query_tool()
self._clear_query_tool()
query = """-- 1. (Done) END any open transaction.
-- 2. (Done) Enable auto rollback and disable auto commit.
-- 3. (Done) Create table in public schema.
@ -616,18 +578,14 @@ END;"""
-- 6. Check if table is *NOT* created after ending transaction.
SELECT relname FROM pg_class
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.execute_query(query)
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")))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
el = canvas.find_elements_by_xpath(
"//div[contains(@class, 'slick-cell') and "
"contains(text(), '{}')]".format(table_name))
QueryToolLocators.output_column_data_xpath.format(table_name))
assert len(el) == 0, "Table '{}' created even after ROLLBACK due to " \
"sql error.".format(table_name)
@ -648,7 +606,7 @@ SELECT 1, pg_sleep(300)"""
commit_button.click()
query_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_query_dropdown)
QueryToolLocators.btn_query_dropdown)
query_op.click()
# enable auto-commit and disable auto-rollback
@ -658,18 +616,18 @@ SELECT 1, pg_sleep(300)"""
query_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
QueryToolLocators.btn_execute_query_css).click()
self.page.find_by_xpath("//*[@id='fetching_data']")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_cancel_query).click()
QueryToolLocators.btn_cancel_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Messages')
self.page.find_by_xpath(
self.assertTrue(self.page.check_if_element_exist_by_xpath(
'//div[contains(@class, "sql-editor-message") and '
'(contains(string(), "canceling statement due to user request") '
'or contains(string(), "Execution Cancelled!"))]'
)
))
def _supported_server_version(self):
connection = test_utils.get_db_connection(
@ -683,48 +641,33 @@ SELECT 1, pg_sleep(300)"""
return connection.server_version > 90100
def _query_tool_notify_statements(self):
wait = WebDriverWait(self.page.driver, 60)
print("\n\tListen on an event... ", file=sys.stderr, end="")
self.page.fill_codemirror_area_with("LISTEN foo;")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.execute_query("LISTEN foo;")
self.page.click_tab('Messages')
wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, ".sql-editor-message"), "LISTEN")
)
self.assertTrue(self.page.check_if_element_exist_by_xpath(
QueryToolLocators.sql_editor_message.format('LISTEN')),
"LISTEN message does not displayed")
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("\tNotify event without data... ", file=sys.stderr, end="")
self.page.fill_codemirror_area_with("NOTIFY foo;")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.execute_query("NOTIFY foo;")
self.page.click_tab('Notifications')
wait.until(EC.text_to_be_present_in_element(
self.wait.until(EC.text_to_be_present_in_element(
(By.CSS_SELECTOR, "td.channel"), "foo")
)
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
print("\tNotify event with data... ", file=sys.stderr, end="")
if self._supported_server_version():
self.page.fill_codemirror_area_with("SELECT pg_notify('foo', "
"'Hello')")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.execute_query("SELECT pg_notify('foo', 'Hello')")
self.page.click_tab('Notifications')
wait.until(WaitForAnyElementWithText(
self.wait.until(WaitForAnyElementWithText(
(By.CSS_SELECTOR, 'td.payload'), "Hello"))
print("OK.", file=sys.stderr)
self._clear_query_tool()
self.page.clear_query_tool()
else:
print("Skipped.", file=sys.stderr)
@ -756,69 +699,63 @@ SELECT 1, pg_sleep(300)"""
is_edb = 'EnterpriseDB' in version_string[0]
connection.close()
return connection.server_version >= 110000 and jit_enabled
def _query_tool_explain_check_jit_stats(self):
wait = WebDriverWait(self.page.driver, 10)
self.page.fill_codemirror_area_with("SET jit_above_cost=10;")
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self._clear_query_tool()
self.page.execute_query("SET jit_above_cost=10;")
self.page.clear_query_tool()
self.page.fill_codemirror_area_with("SELECT count(*) FROM pg_class;")
explain_op = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_options_dropdown)
QueryToolLocators.btn_explain_options_dropdown)
explain_op.click()
# disable Explain options and only enable COST option
for op in (QueryToolLocatorsCss.btn_explain_verbose,
QueryToolLocatorsCss.btn_explain_costs,
QueryToolLocatorsCss.btn_explain_buffers,
QueryToolLocatorsCss.btn_explain_timing):
for op in (QueryToolLocators.btn_explain_verbose,
QueryToolLocators.btn_explain_costs,
QueryToolLocators.btn_explain_buffers,
QueryToolLocators.btn_explain_timing):
btn = self.page.find_by_css_selector(op)
check = btn.find_element_by_tag_name('i')
if 'visibility-hidden' not in check.get_attribute('class'):
btn.click()
# click cost button
cost_btn = self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_costs)
QueryToolLocators.btn_explain_costs)
cost_btn.click()
# close explain options
explain_op.click()
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_explain_analyze).click()
QueryToolLocators.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"))
canvas = self.wait.until(EC.presence_of_element_located(
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
)
# Search for 'Output' word in result (verbose option)
canvas.find_element_by_xpath("//*[contains(string(), 'JIT')]")
self._clear_query_tool()
self.page.clear_query_tool()
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"""
if option == 'auto_commit':
check_status = self.driver.find_element_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit_check_status)
QueryToolLocators.btn_auto_commit_check_status)
if 'visibility-hidden' in check_status.get_attribute('class'):
self.page.find_by_css_selector(QueryToolLocatorsCss.
self.page.find_by_css_selector(QueryToolLocators.
btn_auto_commit).click()
if option == 'auto_rollback':
check_status = self.driver.find_element_by_css_selector(
QueryToolLocatorsCss.btn_auto_rollback_check_status)
QueryToolLocators.btn_auto_rollback_check_status)
if 'visibility-hidden' in check_status.get_attribute('class'):
self.page.find_by_css_selector(QueryToolLocatorsCss.
self.page.find_by_css_selector(QueryToolLocators.
btn_auto_rollback).click()
def uncheck_execute_option(self, option):
@ -826,15 +763,15 @@ SELECT 1, pg_sleep(300)"""
user input. If button is already unchecked, no action will be taken"""
if option == 'auto_commit':
check_status = self.driver.find_element_by_css_selector(
QueryToolLocatorsCss.btn_auto_commit_check_status)
QueryToolLocators.btn_auto_commit_check_status)
if 'visibility-hidden' not in check_status.get_attribute('class'):
self.page.find_by_css_selector(QueryToolLocatorsCss.
self.page.find_by_css_selector(QueryToolLocators.
btn_auto_commit).click()
if option == 'auto_rollback':
check_status = self.driver.find_element_by_css_selector(
QueryToolLocatorsCss.btn_auto_rollback_check_status)
QueryToolLocators.btn_auto_rollback_check_status)
if 'visibility-hidden' not in check_status.get_attribute('class'):
self.page.find_by_css_selector(QueryToolLocatorsCss.
self.page.find_by_css_selector(QueryToolLocators.
btn_auto_rollback).click()

View File

@ -40,9 +40,13 @@ class TableDdlFeatureTest(BaseFeatureTest):
self.page.select_tree_item(self.test_table_name)
self.page.click_tab("SQL")
self.page.find_by_xpath(
# Wait till data is displayed in SQL Tab
self.assertTrue(self.page.check_if_element_exist_by_xpath(
"//*[contains(@class,'CodeMirror-lines') and "
"contains(.,'CREATE TABLE public.%s')]" % self.test_table_name)
"contains(.,'CREATE TABLE public.%s')]" % self.test_table_name,
10), "No data displayed in SQL tab")
def after(self):
self.page.remove_server(self.server)
test_utils.delete_table(
self.server, self.test_db, self.test_table_name)

View File

@ -18,7 +18,8 @@ from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from .locators import QueryToolLocatorsCss
from regression.feature_utils.locators import QueryToolLocators, \
NavMenuLocators
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
@ -26,8 +27,6 @@ config_data = config_data_json = {}
# try:
with open(CURRENT_PATH + '/test_data.json') as data_file:
config_data_json = json.load(data_file)
# except Exception as e:
# print(str(e))
class CheckForViewDataTest(BaseFeatureTest):
@ -121,7 +120,13 @@ CREATE TABLE public.nonintpkey
def runTest(self):
self.page.wait_for_spinner_to_disappear()
self.page.add_server(self.server)
self._tables_node_expandable()
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
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._load_config_data('table_insert_update_cases')
# iterate on both tables
@ -134,6 +139,10 @@ CREATE TABLE public.nonintpkey
def after(self):
self.page.remove_server(self.server)
for cnt in (1, 2):
test_utils.delete_table(
self.server, self.test_db, 'defaults_{0}'.format(str(cnt)))
test_utils.delete_table(self.server, self.test_db, 'nonintpkey')
@staticmethod
def _get_cell_xpath(cell, row):
@ -227,14 +236,14 @@ CREATE TABLE public.nonintpkey
send_keys(Keys.ENTER).perform()
elif cell_type in ['text', 'json', 'text[]', 'boolean[]']:
text_area_ele = self.page.find_by_css_selector(
".pg-text-editor > textarea")
QueryToolLocators.row_editor_text_area_css)
text_area_ele.clear()
text_area_ele.click()
text_area_ele.send_keys(value)
# Click on editor's Save button
self.page.find_by_css_selector(
'.btn.btn-primary.long_text_editor').click()
QueryToolLocators.text_editor_ok_btn_css).click()
else:
# Boolean editor test for to True click
if data[1] == 'true':
@ -250,24 +259,19 @@ CREATE TABLE public.nonintpkey
# Sets false
ActionChains(self.driver).click(checkbox_el).perform()
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(self.test_db)
self.page.toggle_open_tree_item('Schemas')
self.page.toggle_open_tree_item('public')
self.page.toggle_open_tree_item('Tables')
def _view_data_grid(self, table_name):
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("View/Edit Data")
self.page.driver.find_element_by_link_text(
NavMenuLocators.view_data_link_text)
).perform()
self.page.find_by_partial_link_text("All Rows").click()
time.sleep(1)
# wait until datagrid frame is loaded.
self.page.wait_for_query_tool_loading_indicator_to_appear()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab(table_name)
@ -284,8 +288,10 @@ CREATE TABLE public.nonintpkey
row0_cell0_xpath = CheckForViewDataTest._get_cell_xpath("r0", 1)
self.page.find_by_xpath(row0_cell0_xpath).click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
self.page.find_by_xpath("//*[@id='btn-paste-row']").click()
self.page.find_by_css_selector(
QueryToolLocators.copy_button_css).click()
self.page.find_by_css_selector(
QueryToolLocators.paste_button_css).click()
# Update primary key of copied cell
self._add_update_save_row(config_data['copy'], row=2)
@ -305,7 +311,7 @@ CREATE TABLE public.nonintpkey
time.sleep(0.2)
self._update_cell(cell_xpath, data[str(idx)])
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_save_data).click()
QueryToolLocators.btn_save_data).click()
# There should be some delay after save button is clicked, as it
# takes some time to complete save ajax call otherwise discard unsaved
# changes dialog will appear if we try to execute query before previous
@ -320,11 +326,12 @@ CREATE TABLE public.nonintpkey
def _verify_messsages(self, text):
messages_ele = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_messages_panel)
QueryToolLocators.query_messages_panel)
self.assertEquals(text, messages_ele.text)
def _verify_row_data(self, is_new_row, config_check_data):
self.page.find_by_id("btn-flash").click()
self.page.find_by_css_selector(
QueryToolLocators.btn_execute_query_css).click()
# First row if row height = 0, second row if its 25
row_height = 0 if is_new_row else 25

View File

@ -8,10 +8,13 @@
##########################################################################
from __future__ import print_function
import sys
import random
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from selenium.webdriver import ActionChains
import sys
from selenium.common.exceptions import StaleElementReferenceException
from regression.feature_utils.locators import QueryToolLocators
class CheckForXssFeatureTest(BaseFeatureTest):
@ -32,7 +35,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
scenarios = [
("Test XSS check for panels and query tool", dict())
]
test_table_name = "<h1>X"
test_table_name = "<h1>X" + str(random.randint(1000, 3000))
# test_table_name = "<h1>X"
test_type_name = '"<script>alert(1)</script>"'
def before(self):
@ -85,6 +89,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
def after(self):
self.page.remove_server(self.server)
test_utils.delete_table(
self.server, self.test_db, self.test_table_name)
def _tables_node_expandable(self):
self.page.toggle_open_server(self.server['name'])
@ -198,7 +204,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
self.page.fill_codemirror_area_with(
"select '<script>alert(1)</script>"
)
self.page.find_by_id("btn-flash").click()
self.page.find_by_css_selector(
QueryToolLocators.btn_execute_query_css).click()
self.page.click_tab('Query History')
@ -227,13 +234,17 @@ class CheckForXssFeatureTest(BaseFeatureTest):
'&lt;script&gt;alert(1)&lt;/script&gt;',
"Query tool (History Details-Message)"
)
# Check for history details error message
history_ele = self.page.find_by_css_selector(
".query-detail .history-error-text"
)
source_code = history_ele.get_attribute('innerHTML')
retry = 2
while retry > 0:
try:
# Check for history details error message
history_ele = self.page.find_by_css_selector(
".query-detail .history-error-text"
)
source_code = history_ele.get_attribute('innerHTML')
break
except StaleElementReferenceException:
retry -= 1
self._check_escaped_characters(
source_code,
@ -272,7 +283,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
'select * from "{0}"'.format(self.test_table_name)
)
self.page.find_by_id("btn-explain").click()
self.page.find_by_css_selector(
QueryToolLocators.btn_explain).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab('Explain')

View File

@ -88,7 +88,18 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
# If debugger plugin is not found
if is_error and is_error.text == "Debugger Error":
self.page.click_modal('OK')
click = True
while click:
try:
self.page.click_modal('OK')
wait.until(EC.invisibility_of_element(
(By.XPATH, "//div[contains(@class, 'alertify') and "
"not(contains(@class, 'ajs-hidden'))]//div["
"contains(@class,'ajs-header')]")
))
click = False
except TimeoutException:
pass
self.skipTest(
"Please make sure that debugger plugin is properly configured"
)

View File

@ -10,6 +10,10 @@ import random
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from regression.feature_utils.locators import NavMenuLocators
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
@ -36,6 +40,7 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
self.role)
test_utils.create_role(self.server, "postgres",
"<h1>test</h1>")
self.wait = WebDriverWait(self.page.driver, 20)
def runTest(self):
self.page.wait_for_spinner_to_disappear()
@ -56,9 +61,11 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
self.page.select_tree_item(role)
def _check_role_membership_control(self):
self.page.driver.find_element_by_link_text("Object").click()
self.page.driver.find_element_by_link_text("Properties...").click()
# self.page.find_by_partial_link_text("Membership").click()
self.page.driver.find_element_by_link_text(
NavMenuLocators.object_menu_link_text).click()
property_object = self.wait.until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, NavMenuLocators.properties_obj_css)))
property_object.click()
self.click_membership_tab()
# Fetch the source code for our custom control
source_code = self.page.find_by_xpath(

View File

@ -0,0 +1,221 @@
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
class BrowserToolBarLocators():
"""This will contains element locators for browser tool bar"""
open_query_tool_button_css = \
".wcFrameButton[title='Query Tool']:not(.disabled)"
query_tool_panel_css = ".wcPanelTab .wcTabIcon.fa.fa-bolt"
view_table_data_button_css = \
".wcFrameButton[title='View Data']:not(.disabled)"
view_data_panel_css = ".wcPanelTab .wcTabIcon.fa.fa-table"
filter_data_button_css = \
".wcFrameButton[title='Filtered Rows']:not(.disabled)"
filter_alertify_box_css = ".alertify .ajs-header[data-title~='Filter']"
class NavMenuLocators:
"This will contains element locators of navigation menu bar"
file_menu_css = "#mnu_file"
preference_menu_item_css = "#mnu_preferences"
tools_menu_link_text = "Tools"
view_data_link_text = "View/Edit Data"
object_menu_link_text = "Object"
properties_obj_css = "#show_obj_properties.dropdown-item:not(.disabled)"
backup_obj_css = "#backup_object.dropdown-item:not(.disabled)"
restore_obj_css = "#restore_object.dropdown-item:not(.disabled)"
maintenance_obj_css = "#maintenance.dropdown-item:not(.disabled)"
show_system_objects_pref_label_xpath = \
"//label[contains(text(), 'Show system objects?')]"
maximize_pref_dialogue_css = ".ajs-dialog.pg-el-container .ajs-maximize"
specified_pref_node_exp_status = \
"//div[div[span[span[(@class='aciTreeText')and " \
"(text()='{0} ' or text()='{0}')]]]]"
specified_preference_tree_node = \
"//div//span[(@class='aciTreeText')and " \
"(text()='{0} ' or text()='{0}')]"
specified_sub_node_of_pref_tree_node = \
"//span[text()='{0}']//following::span[text()='{1}']"
insert_bracket_pair_switch_btn = \
"//div[label[normalize-space(text())='Insert bracket pairs?']]" \
"//div[contains(@class,'toggle btn')]"
backup_filename_txt_box_name = "file"
restore_file_name_txt_box_name = "file"
backup_btn_xpath = \
"//button[contains(@class,'fa-save')and contains(.,'Backup')]"
bcg_process_status_alertifier_css = \
".ajs-message.ajs-bg-bgprocess.ajs-visible"
status_alertifier_more_btn_css = ".pg-bg-more-details"
process_watcher_alertfier = \
"//div[contains(@class,'wcFrameTitleBar')]" \
"//div[contains(text(),'Process Watcher')]"
process_watcher_detailed_command_canvas_css = \
".bg-process-details .bg-detailed-desc"
process_watcher_close_button_xpath = \
"//div[contains(@class,'wcFloatingFocus')]//" \
"div[contains(@class,'fa-close')]"
restore_file_name_xpath = "//div[contains(text(),'Restore')]" \
"//following::input[@name='file']"
restore_button_xpath = \
"//button[contains(@class,'fa-upload') and contains(.,'Restore')]"
maintenance_operation = "//label[text()='Maintenance operation']"
select_tab_xpath = \
"//*[contains(@class,'wcTabTop')]//*[contains(@class,'wcPanelTab') " \
"and contains(.,'{}')]"
class QueryToolLocators:
btn_save_file = "#btn-save-file"
btn_save_data = "#btn-save-data"
btn_query_dropdown = "#btn-query-dropdown"
btn_auto_rollback = "#btn-auto-rollback"
btn_auto_rollback_check_status = "#btn-auto-rollback > i"
btn_auto_commit = "#btn-auto-commit"
btn_auto_commit_check_status = "#btn-auto-commit > i"
btn_cancel_query = "#btn-cancel-query"
btn_explain = "#btn-explain"
btn_explain_analyze = "#btn-explain-analyze"
btn_explain_options_dropdown = "#btn-explain-options-dropdown"
btn_explain_verbose = "#btn-explain-verbose"
btn_explain_costs = "#btn-explain-costs"
btn_explain_buffers = "#btn-explain-buffers"
btn_explain_timing = "#btn-explain-timing"
btn_clear_dropdown = "#btn-clear-dropdown"
btn_clear_history = "#btn-clear-history"
btn_clear = "#btn-clear"
query_editor_panel = "#output-panel"
query_history_selected = "#query_list .selected"
query_history_entries = "#query_list>.query-group>ul>li"
query_history_specific_entry = \
"#query_list>.query-group>ul>li:nth-child({})"
query_history_detail = "#query_detail"
invalid_query_history_entry_css = "#query_list .entry.error .query"
editor_panel = "#output-panel"
query_messages_panel = ".sql-editor-message"
output_row_xpath = "//div[contains(@class, 'slick-row')][{}]/*[1]"
output_column_header_css = "[data-column-id='{}']"
output_column_data_xpath = "//div[contains(@class, 'slick-cell')]" \
"[contains(., '{}')]"
output_cell_xpath = "//div[contains(@class, 'slick-cell') and " \
"contains(@class, 'l{0} r{1}')]"
select_all_column = \
"//div[contains(@id,'row-header-column')]"
new_row_xpath = "//div[contains(@class, 'new-row')]"
copy_button_css = "#btn-copy-row"
paste_button_css = "#btn-paste-row"
row_editor_text_area_css = ".pg-text-editor > textarea"
text_editor_ok_btn_css = ".btn.btn-primary.long_text_editor"
btn_load_file_css = "#btn-load-file"
btn_execute_query_css = "#btn-flash"
input_file_path_css = "input#file-input-path"
select_file_content_css = "table#contents"
query_output_canvas_css = "#datagrid .slick-viewport .grid-canvas"
query_output_cells = ".slick-cell"
sql_editor_message = "//div[contains(@class, 'sql-editor-message') and " \
"contains(string(), '{}')]"
code_mirror_hint_box_xpath = "//ul[@class='CodeMirror-hints default']"
code_mirror_hint_item_xpath = \
"//ul[contains(@class, 'CodeMirror-hints') and contains(., '{}')]"
code_mirror_data_xpath = "//pre[@class=' CodeMirror-line ']/span"
save_data_icon = "icon-save-data-changes"
commit_icon = "icon-commit"
execute_icon = "fa-bolt"
explain_icon = "fa-hand-pointer-o"
explain_analyze_icon = "fa-list-alt"
query_history_selected_icon = '#query_list .selected #query_source_icon'
btn_commit = "#btn-commit"
show_query_internally_btn = \
"//div[label[normalize-space(" \
"text())='Show queries generated internally by pgAdmin?']]" \
"//div[contains(@class,'toggle btn')]"

View File

@ -8,6 +8,7 @@
##########################################################################
import time
import sys
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, \
@ -18,6 +19,9 @@ from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from regression.feature_utils.locators import QueryToolLocators, \
NavMenuLocators
from regression.feature_utils.tree_area_locators import TreeAreaLocators
class PgadminPage:
@ -84,8 +88,10 @@ class PgadminPage:
self.find_by_css_selector("button[type='save'].btn.btn-primary").\
click()
self.find_by_xpath(
"//*[@id='tree']//*[.='" + server_config['name'] + "']")
WebDriverWait(self.driver, 10).until(
EC.visibility_of_element_located(
(By.XPATH,
"//*[@id='tree']//*[.='" + server_config['name'] + "']")))
def open_query_tool(self):
self.driver.find_element_by_link_text("Tools").click()
@ -151,6 +157,24 @@ class PgadminPage:
'contains(.,"Don\'t save")]'))
self.driver.switch_to.default_content()
def clear_query_tool(self):
self.click_element(
self.find_by_css_selector(QueryToolLocators.btn_clear_dropdown)
)
ActionChains(self.driver).move_to_element(
self.find_by_css_selector(QueryToolLocators.btn_clear)).perform()
self.click_element(
self.find_by_css_selector(QueryToolLocators.btn_clear)
)
self.click_modal('Yes')
def execute_query(self, query):
self.fill_codemirror_area_with(query)
execute_button = self.find_by_css_selector(
QueryToolLocators.btn_execute_query_css)
execute_button.click()
self.wait_for_query_tool_loading_indicator_to_disappear()
def close_data_grid(self):
self.driver.switch_to_default_content()
xpath = "//*[@id='dockerContainer']/div/div[3]/div/div[2]/div[1]"
@ -188,14 +212,40 @@ class PgadminPage:
if attempts == 0:
raise Exception(e)
def get_expansion_status_of_node(self, xpath_node):
"""get the expansion status for a node through xpath"""
node_is_expanded = False
element = self.find_by_xpath(xpath_node)
if element.get_attribute("aria-expanded") == 'true':
node_is_expanded = True
return node_is_expanded
def toggle_open_servers_group(self):
"""This will open Servers group to display underlying nodes"""
is_expanded = False
self.wait_for_spinner_to_disappear()
server_group = self.find_by_xpath(
"//div[@id='tree']//span[@class='aciTreeItem']"
"/span[(@class='aciTreeText') and starts-with(text(),'Servers ') "
"or starts-with(text(), 'Servers')]")
ActionChains(self.driver).double_click(server_group).perform()
if self.check_if_element_exist_by_xpath(
TreeAreaLocators.server_group_node):
if self.get_expansion_status_of_node(
TreeAreaLocators.server_group_node_exp_status):
is_expanded = True
else:
webdriver.ActionChains(self.driver).double_click(
self.find_by_xpath(
TreeAreaLocators.
server_group_node)).perform()
if self.check_if_element_exist_by_xpath(
TreeAreaLocators.server_group_sub_nodes):
is_expanded = True
else:
print(
"(toggle_open_servers_group)The Server Group "
"node is clicked to expand but it is not expanded",
file=sys.stderr)
else:
print("The Server Group node is not visible",
file=sys.stderr)
return is_expanded
def toggle_open_tree_item(self, tree_item_text):
# 'sleep' here helps in cases where underlying nodes are auto opened.
@ -203,8 +253,7 @@ class PgadminPage:
# even if the underlying node to be clicked was Opened.
time.sleep(.6)
item_with_text = self.find_by_xpath(
"//div[@id='tree']//span[@class='aciTreeItem']/span["
"(@class='aciTreeText') and text()='" + tree_item_text + "']")
TreeAreaLocators.specified_tree_node.format(tree_item_text))
self.driver.execute_script("arguments[0].scrollIntoView()",
item_with_text)
@ -215,6 +264,17 @@ class PgadminPage:
item = item_with_text.find_element_by_xpath(
".//parent::*[@class='aciTreeItem']")
ActionChains(self.driver).double_click(item).perform()
retry = 3
while retry > 0:
try:
WebDriverWait(self.driver, 5).until((lambda item_with_text: (
item_with_text.find_element_by_xpath(
".//ancestor::*[@class='aciTreeLine']").
get_attribute("aria-expanded") == 'true')))
break
except TimeoutException:
retry -= 1
pass
def toggle_open_tables_node(self):
"""The function will be used for opening Tables node only"""
@ -454,15 +514,14 @@ class PgadminPage:
def click_tab(self, tab_name):
WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable(
(By.XPATH, "//*[contains(@class,'wcTabTop')]//"
"*[contains(@class,'wcPanelTab') "
"and contains(.,'" + tab_name + "')]")))
tab = self.find_by_xpath("//*[contains(@class,'wcTabTop')]//"
"*[contains(@class,'wcPanelTab') "
"and contains(.,'" + tab_name + "')]")
self.click_element(tab)
(By.XPATH, NavMenuLocators.select_tab_xpath.format(tab_name))))
click_tab = True
while click_tab:
tab = self.find_by_xpath(
NavMenuLocators.select_tab_xpath.format(tab_name))
self.click_element(tab)
if 'wcPanelTabActive' in tab.get_attribute('class'):
break
def wait_for_input_by_element(self, element, content):
def input_field_has_content(driver):
@ -539,7 +598,7 @@ class PgadminPage:
except NoSuchElementException:
return True
self._wait_for("spinner to disappear", spinner_has_disappeared)
self._wait_for("spinner to disappear", spinner_has_disappeared, 20)
def wait_for_query_tool_loading_indicator_to_disappear(self):
def spinner_has_disappeared(driver):
@ -553,7 +612,12 @@ class PgadminPage:
time.sleep(0.5)
return True
self._wait_for("spinner to disappear", spinner_has_disappeared)
self._wait_for("spinner to disappear", spinner_has_disappeared, 20)
def wait_for_query_tool_loading_indicator_to_appear(self):
self.check_if_element_exist_by_xpath(
"//div[@id='editor-panel']//"
"div[@class='pg-sp-container sql-editor-busy-fetching']")
def wait_for_app(self):
def page_shows_app(driver):
@ -574,10 +638,98 @@ class PgadminPage:
return element_selector(self.driver)
def _wait_for(self, waiting_for_message, condition_met_function,
timeout=3):
timeout=5):
if timeout is None:
timeout = self.timeout
return WebDriverWait(self.driver, timeout, 0.01).until(
condition_met_function,
"Timed out waiting for " + waiting_for_message
)
def wait_for_elements(self, find_method_with_args):
"""Using xpath, it will wait for elements"""
def element_if_it_exists(driver):
try:
element = find_method_with_args(driver)
if len(element) > 0 and element[0].is_displayed() and element[
0].is_enabled():
return element
except NoSuchElementException:
return False
return self._wait_for("element to exist", element_if_it_exists)
def find_by_xpath_list(self, xpath):
"""This will find out list of elements through a single xpath"""
return self.wait_for_elements(
lambda driver: driver.find_elements_by_xpath(xpath))
def get_index_of_element(self, element_list, target_string):
"""it will return index of an element from provided element list"""
index_of_required_server = -1
if len(element_list) > 0:
for index, element in enumerate(element_list):
if element.text.startswith(target_string) and (
target_string in element.text):
index_of_required_server = index
break
else:
print("There seems no record in the provided element list")
return index_of_required_server
def set_switch_box_status(self, switch_box, required_status):
"""it will change switch box status to required one. Two elements
of the switch boxes are to be provided i) button which is needed to
toggle ii) Yes for True or No for False"""
status_changed_successfully = False
switch_box_element = self.find_by_xpath(switch_box)
if required_status == 'Yes':
if 'off' in switch_box_element.get_attribute("class"):
switch_box_element.click()
time.sleep(1)
if 'success' in switch_box_element.get_attribute("class"):
status_changed_successfully = True
else:
print(
"(set_switch_box_status)Clicked the "
"element to change its status but "
"it did not changed",
file=sys.stderr)
elif 'success' in switch_box_element.get_attribute("class"):
status_changed_successfully = True
else:
if 'success' in switch_box_element.get_attribute("class"):
switch_box_element.click()
if 'off' in switch_box_element.get_attribute("class"):
status_changed_successfully = True
else:
print(
"(set_switch_box_status)Clicked the element to "
"change its status but it did not changed",
file=sys.stderr)
elif 'off' in switch_box_element.get_attribute("class"):
status_changed_successfully = True
return status_changed_successfully
def retry_click_operation(self, element_to_click,
element_to_verify_after_click):
"""This will attempt to click add button multiple time,
some different exception encountered while clicking, so handled
through this"""
click_status = False
attempt = 0
while click_status is not True and attempt < 5:
try:
if element_to_verify_after_click.is_displayed():
click_status = True
element_to_click.click()
if element_to_verify_after_click.is_displayed():
click_status = True
except Exception:
print("The click operation is not performed for "
"attempt %s, will try 5 attempts" % attempt)
attempt = +1
return click_status

View File

@ -0,0 +1,31 @@
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
class TreeAreaLocators():
"""This will contains element locators for tree area, will also contain
parametrized xpath where applicable"""
server_group_node = \
"//div[@id='tree']//span[@class='aciTreeItem']" \
"/span[(@class='aciTreeText') and starts-with(text(),'Servers ') or " \
"starts-with(text(), 'Servers')]"
server_group_node_exp_status = "//div[div[span[span[" \
"(@class='aciTreeText') and " \
"(text()='Servers ' or " \
"text()='Servers')]]]]"
server_group_sub_nodes = \
"//div[div[span[span[contains(text(),'Servers')]]]]/" \
"following-sibling::ul/li/div/div/div/span[2]/" \
"span[@class='aciTreeText']"
specified_tree_node = \
"//div[@id='tree']//span[@class='aciTreeItem']/" \
"span[(@class='aciTreeText') and text()='{}']"

View File

@ -12,42 +12,32 @@ def close_bgprocess_popup(tester):
"""
Allows us to close the background process popup window
"""
screen_shot_taken = False
# In cases where backup div is not closed (sometime due to some error)
try:
if tester.driver.find_element_by_css_selector(
".ajs-message.ajs-bg-bgprocess.ajs-visible"):
tester._screenshot()
screen_shot_taken = True
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
tester.page.wait_for_element_to_disappear(
lambda x: tester.driver.find_element_by_xpath(
".ajs-message.ajs-bg-bgprocess.ajs-visible"))
except Exception:
pass
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
# In cases where restore div is not closed (sometime due to some error)
try:
if tester.driver.find_element_by_xpath(
tester.page.wait_for_element_to_disappear(
lambda x: tester.driver.find_element_by_xpath(
"//div[@class='card-header bg-primary d-flex']/div"
"[contains(text(), 'Restoring backup')]"):
tester._screenshot()
screen_shot_taken = True
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
"[contains(text(), 'Restoring backup')]"))
except Exception:
pass
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
# In cases where maintenance window is not closed (sometime due to some
# error)
try:
if tester.driver.find_element_by_xpath(
tester.page.wait_for_element_to_disappear(
lambda x: tester.driver.find_element_by_xpath(
"//div[@class='card-header bg-primary d-flex']/div"
"[contains(text(), 'Maintenance')]"):
tester._screenshot()
screen_shot_taken = True
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()
"[contains(text(), 'Maintenance')]"))
except Exception:
pass
if not screen_shot_taken:
tester._screenshot()
tester.driver.find_element_by_css_selector(
".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click()

View File

@ -194,6 +194,35 @@ def create_table(server, db_name, table_name, extra_columns=[]):
traceback.print_exc(file=sys.stderr)
def delete_table(server, db_name, table_name):
"""
This function delete the table in given database
:param server: server details
:type server: dict
:param db_name: database name
:type db_name: str
:param table_name: table name
:type table_name: str
:return: None
"""
try:
connection = get_db_connection(
db_name,
server['username'],
server['db_password'],
server['host'],
server['port'],
server['sslmode']
)
pg_cursor = connection.cursor()
pg_cursor.execute(
'''DROP TABLE IF EXISTS "%s"''' % table_name)
connection.commit()
except Exception:
traceback.print_exc(file=sys.stderr)
def create_table_with_query(server, db_name, query):
"""
This function create the table in given database name
@ -774,22 +803,28 @@ def configure_preferences(default_binary_path=None):
def reset_layout_db(user_id=None):
conn = sqlite3.connect(config.TEST_SQLITE_PATH)
cur = conn.cursor()
retry = 3
while retry > 0:
try:
conn = sqlite3.connect(config.TEST_SQLITE_PATH)
cur = conn.cursor()
if user_id is None:
cur.execute(
'DELETE FROM SETTING WHERE SETTING in '
'("Browser/Layout", "SQLEditor/Layout", "Debugger/Layout")'
)
else:
cur.execute(
'DELETE FROM SETTING WHERE SETTING in '
'("Browser/Layout", "SQLEditor/Layout", "Debugger/Layout")'
' AND USER_ID=?', user_id
)
conn.commit()
conn.close()
if user_id is None:
cur.execute(
'DELETE FROM SETTING WHERE SETTING in '
'("Browser/Layout", "SQLEditor/Layout", "Debugger/Layout")'
)
else:
cur.execute(
'DELETE FROM SETTING WHERE SETTING in '
'("Browser/Layout", "SQLEditor/Layout", "Debugger/Layout")'
' AND USER_ID=?', user_id
)
conn.commit()
conn.close()
break
except Exception:
retry -= 1
def remove_db_file():