mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Feature test improvement and fix intermittent failures part of #3936
This commit is contained in:
committed by
Akshay Joshi
parent
7090c02014
commit
9f455a514e
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
'<h1>test_me</h1>',
|
||||
'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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
'<script>alert(1)</script>',
|
||||
"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')
|
||||
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user