mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-12-23 07:34:35 -06:00
Modifies the way to execute feature tests in parallel and it should be configured in Server Mode.
This commit is contained in:
parent
faa49687be
commit
2d58f60a53
@ -88,6 +88,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
||||
BrowserToolBarLocators.view_table_data_button_css),
|
||||
(By.CSS_SELECTOR, BrowserToolBarLocators.view_data_panel_css)),
|
||||
'View/Edit Data tab did not open after clicking View/Edit button.')
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
||||
def test_filtered_rows_tool_button(self):
|
||||
self.assertTrue(self.page.retry_click(
|
||||
@ -96,3 +97,4 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
||||
(By.CSS_SELECTOR, BrowserToolBarLocators.filter_alertify_box_css)),
|
||||
'Filter dialogue did not open on clicking filter button.')
|
||||
self.page.click_modal('Cancel')
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
@ -41,7 +41,10 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
|
||||
self.wait = WebDriverWait(self.page.driver, 10)
|
||||
filename = self.server_information['type'] + \
|
||||
str(self.server_information['server_version'])
|
||||
self.XSS_FILE = '/tmp/<img src=x ' + filename + '=alert("1")>.sql'
|
||||
if self.parallel_ui_tests:
|
||||
self.XSS_FILE = '/<img src=x ' + filename + '=alert("1")>.sql'
|
||||
else:
|
||||
self.XSS_FILE = '/tmp/<img src=x ' + filename + '=alert("1")>.sql'
|
||||
# Remove any previous file
|
||||
if os.path.isfile(self.XSS_FILE):
|
||||
os.remove(self.XSS_FILE)
|
||||
@ -92,21 +95,14 @@ class CheckFileManagerFeatureTest(BaseFeatureTest):
|
||||
self.page.fill_input_by_css_selector(
|
||||
QueryToolLocators.input_file_path_css,
|
||||
"/tmp", key_after_input=Keys.RETURN)
|
||||
time.sleep(2)
|
||||
|
||||
if self.page.driver.capabilities['browserName'] == 'firefox':
|
||||
table = self.page.wait_for_element_to_reload(
|
||||
lambda driver: driver.find_element_by_css_selector(
|
||||
QueryToolLocators.select_file_content_css)
|
||||
)
|
||||
else:
|
||||
self.wait.until(EC.visibility_of_element_located(
|
||||
(By.CSS_SELECTOR, QueryToolLocators.select_file_content_css)))
|
||||
self.wait.until(lambda element:
|
||||
self.page.driver.find_element_by_css_selector(
|
||||
'[name=home]').is_enabled())
|
||||
self.wait.until(EC.visibility_of_element_located(
|
||||
(By.CSS_SELECTOR, QueryToolLocators.select_file_content_css)))
|
||||
|
||||
table = self.page.driver.find_element_by_css_selector(
|
||||
QueryToolLocators.select_file_content_css)
|
||||
|
||||
table = self.page.driver.find_element_by_css_selector(
|
||||
QueryToolLocators.select_file_content_css)
|
||||
retry_count = 0
|
||||
while retry_count < 5:
|
||||
try:
|
||||
|
@ -46,8 +46,8 @@ class TableDdlFeatureTest(BaseFeatureTest):
|
||||
# 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,
|
||||
10), "No data displayed in SQL tab")
|
||||
"contains(.,'CREATE TABLE IF NOT EXISTS public.%s')]"
|
||||
% self.test_table_name, 10), "No data displayed in SQL tab")
|
||||
|
||||
def after(self):
|
||||
self.page.remove_server(self.server)
|
||||
|
@ -148,6 +148,9 @@ class BaseTestGenerator(unittest.TestCase):
|
||||
def setDriver(self, driver):
|
||||
self.driver = driver
|
||||
|
||||
def setParallelUI_tests(self, parallel_ui_tests):
|
||||
self.parallel_ui_tests = parallel_ui_tests
|
||||
|
||||
def setServerInformation(self, server_information):
|
||||
self.server_information = server_information
|
||||
|
||||
|
@ -142,7 +142,8 @@ Python Tests:
|
||||
'pgadmin4/web/pgadmin/utils/test.py' file.
|
||||
|
||||
- To run Feature Tests in parallel using selenoid(grid + docker), selenoid
|
||||
need to be installed. Steps to install selenoid -
|
||||
need to be installed nad should be run only with SERVER_MODE=True.
|
||||
Steps to install selenoid -
|
||||
|
||||
- Install & Start docker
|
||||
$yum -y install docker docker-registry
|
||||
|
@ -27,7 +27,7 @@ class BaseFeatureTest(BaseTestGenerator):
|
||||
def setUp(self):
|
||||
self.server = deepcopy(self.server)
|
||||
self.server['name'] += ' Feature Tests'
|
||||
if app_config.SERVER_MODE:
|
||||
if app_config.SERVER_MODE and not self.parallel_ui_tests:
|
||||
self.skipTest(
|
||||
"Currently, config is set to start pgadmin in server mode. "
|
||||
"This test doesn't know username and password so doesn't work "
|
||||
@ -36,6 +36,8 @@ class BaseFeatureTest(BaseTestGenerator):
|
||||
|
||||
self.page = PgadminPage(self.driver, app_config)
|
||||
try:
|
||||
if self.parallel_ui_tests:
|
||||
self.page.login_to_app(self.server['login_details'])
|
||||
test_utils.reset_layout_db()
|
||||
self.page.driver.switch_to.default_content()
|
||||
self.page.wait_for_app()
|
||||
|
@ -37,6 +37,18 @@ class PgadminPage:
|
||||
self.timeout = 30
|
||||
self.app_start_timeout = 90
|
||||
|
||||
def login_to_app(self, user_detail):
|
||||
if not (self.check_if_element_exist_by_xpath(
|
||||
'//a[@id="navbar-user"]', 1)):
|
||||
user_edt_box_el = self.driver.find_element_by_name('email')
|
||||
user_edt_box_el.send_keys(user_detail['login_username'])
|
||||
password_edt_box_el = self.driver.find_element_by_name('password')
|
||||
password_edt_box_el.send_keys(user_detail['login_password'])
|
||||
submit_btn = self.driver.find_element_by_xpath(
|
||||
'//button[@value="Login"]')
|
||||
submit_btn.click()
|
||||
self.wait_for_spinner_to_disappear()
|
||||
|
||||
def reset_layout(self):
|
||||
attempt = 0
|
||||
while attempt < 4:
|
||||
@ -57,7 +69,15 @@ class PgadminPage:
|
||||
self.wait_for_reloading_indicator_to_disappear()
|
||||
|
||||
def refresh_page(self):
|
||||
self.driver.refresh()
|
||||
try:
|
||||
self.driver.refresh()
|
||||
# wait until alert is present
|
||||
WebDriverWait(self.driver, 1).until(EC.alert_is_present())
|
||||
|
||||
# switch to alert and accept it
|
||||
self.driver.switch_to.alert.accept()
|
||||
except TimeoutException:
|
||||
pass
|
||||
|
||||
def click_modal(self, button_text):
|
||||
time.sleep(0.5)
|
||||
@ -300,6 +320,7 @@ class PgadminPage:
|
||||
delete_menu_item = self.find_by_partial_link_text("Remove Server")
|
||||
self.click_element(delete_menu_item)
|
||||
self.click_modal('Yes')
|
||||
time.sleep(1)
|
||||
|
||||
def select_tree_item(self, tree_item_text):
|
||||
item = self.find_by_xpath(
|
||||
|
@ -17,6 +17,7 @@ import psycopg2
|
||||
import sqlite3
|
||||
import shutil
|
||||
from functools import partial
|
||||
import random
|
||||
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from testtools.testcase import clone_test_with_new_id
|
||||
@ -1400,7 +1401,7 @@ def get_parallel_sequential_module_list(module_list):
|
||||
sequential_tests_file = [
|
||||
'pgadmin.feature_tests.pg_utilities_backup_restore_test',
|
||||
'pgadmin.feature_tests.pg_utilities_maintenance_test',
|
||||
'pgadmin.feature_tests.keyboard_shortcut_test']
|
||||
]
|
||||
|
||||
# list of tests can be executed in parallel
|
||||
parallel_tests = list(module_list)
|
||||
@ -1704,3 +1705,28 @@ def create_user_wise_test_client(user):
|
||||
return wrapper
|
||||
|
||||
return multi_user_decorator
|
||||
|
||||
|
||||
def create_users_for_parallel_tests(tester):
|
||||
"""
|
||||
Function creates user using /user api
|
||||
@param tester: test client
|
||||
@return: uer details dict
|
||||
"""
|
||||
login_username = 'ui_test_user' + str(random.randint(1000, 9999)) +\
|
||||
'@edb.com'
|
||||
user_details = {'login_username': login_username,
|
||||
'login_password': 'adminedb'}
|
||||
response = tester.post(
|
||||
'/user_management/user/',
|
||||
data=json.dumps(dict(username=user_details['login_username'],
|
||||
email=user_details['login_username'],
|
||||
newPassword=user_details['login_password'],
|
||||
confirmPassword=user_details['login_password'],
|
||||
active=True,
|
||||
role="1"
|
||||
)),
|
||||
follow_redirects=True)
|
||||
user_id = json.loads(response.data.decode('utf-8'))['id']
|
||||
user_details['user_id'] = user_id
|
||||
return user_details
|
||||
|
@ -151,7 +151,7 @@ scenarios.apply_scenario = test_utils.apply_scenario
|
||||
|
||||
|
||||
def get_suite(module_list, test_server, test_app_client, server_information,
|
||||
test_db_name, driver_passed):
|
||||
test_db_name, driver_passed, parallel_ui_test):
|
||||
"""
|
||||
This function add the tests to test suite and return modified test suite
|
||||
variable.
|
||||
@ -164,6 +164,12 @@ def get_suite(module_list, test_server, test_app_client, server_information,
|
||||
:type test_app_client: pgadmin app object
|
||||
:return pgadmin_suite: test suite with test cases
|
||||
:rtype: TestSuite
|
||||
:param driver_passed: driver object to run selenium tests
|
||||
:type driver_passed: webdriver object
|
||||
:param parallel_ui_test: whether ui tests to be run in parallel
|
||||
:type parallel_ui_test: boolan
|
||||
:param test_db_name: database name
|
||||
:type test_db_name: string
|
||||
"""
|
||||
modules = []
|
||||
pgadmin_suite = unittest.TestSuite()
|
||||
@ -182,11 +188,11 @@ def get_suite(module_list, test_server, test_app_client, server_information,
|
||||
obj.setTestClient(test_app_client)
|
||||
obj.setTestServer(test_server)
|
||||
obj.setDriver(driver_passed)
|
||||
obj.setParallelUI_tests(parallel_ui_test)
|
||||
obj.setServerInformation(server_information)
|
||||
obj.setTestDatabaseName(test_db_name)
|
||||
scenario = scenarios.generate_scenarios(obj)
|
||||
pgadmin_suite.addTests(scenario)
|
||||
|
||||
return pgadmin_suite
|
||||
|
||||
|
||||
@ -450,12 +456,14 @@ class StreamToLogger(object):
|
||||
pass
|
||||
|
||||
|
||||
def execute_test(test_module_list_passed, server_passed, driver_passed):
|
||||
def execute_test(test_module_list_passed, server_passed, driver_passed,
|
||||
parallel_ui_test=False):
|
||||
"""
|
||||
Function executes actually test
|
||||
:param test_module_list_passed:
|
||||
:param server_passed:
|
||||
:param driver_passed:
|
||||
:param test_module_list_passed: test modules
|
||||
:param server_passed: serve details
|
||||
:param driver_passed: webdriver object
|
||||
:param parallel_ui_test: parallel ui tests
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
@ -493,11 +501,17 @@ def execute_test(test_module_list_passed, server_passed, driver_passed):
|
||||
test_utils.configure_preferences(
|
||||
default_binary_path=server_passed['default_binary_paths'])
|
||||
|
||||
# Create user to run selenoid tests in parallel
|
||||
if parallel_ui_test:
|
||||
server_passed['login_details'] = \
|
||||
test_utils.create_users_for_parallel_tests(test_client)
|
||||
|
||||
# Get unit test suit
|
||||
suite = get_suite(test_module_list_passed,
|
||||
server_passed,
|
||||
test_client,
|
||||
server_information, test_db_name, driver_passed)
|
||||
server_information, test_db_name, driver_passed,
|
||||
parallel_ui_test=parallel_ui_test)
|
||||
|
||||
# Run unit test suit created
|
||||
tests = unittest.TextTestRunner(stream=sys.stderr,
|
||||
@ -570,12 +584,11 @@ def run_parallel_tests(url_client, servers_details, parallel_tests_lists,
|
||||
:param max_thread_count:
|
||||
"""
|
||||
driver_object = None
|
||||
|
||||
# Thread list
|
||||
threads_list = []
|
||||
# Create thread for each server
|
||||
for ser in servers_details:
|
||||
try:
|
||||
try:
|
||||
# Thread list
|
||||
threads_list = []
|
||||
# Create thread for each server
|
||||
for ser in servers_details:
|
||||
while True:
|
||||
# If active thread count <= max_thread_count, add new thread
|
||||
if threading.activeCount() <= max_thread_count:
|
||||
@ -594,33 +607,33 @@ def run_parallel_tests(url_client, servers_details, parallel_tests_lists,
|
||||
# Start thread
|
||||
t = threading.Thread(target=execute_test, name=thread_name,
|
||||
args=(parallel_tests_lists, ser,
|
||||
driver_object))
|
||||
driver_object, True))
|
||||
threads_list.append(t)
|
||||
t.start()
|
||||
time.sleep(3)
|
||||
time.sleep(10)
|
||||
break
|
||||
# else sleep for 10 seconds
|
||||
else:
|
||||
time.sleep(10)
|
||||
|
||||
# Start threads in parallel
|
||||
for t in threads_list:
|
||||
t.join()
|
||||
# Start threads in parallel
|
||||
for t in threads_list:
|
||||
t.join()
|
||||
|
||||
except Exception as exc:
|
||||
# Print exception stack trace
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print('Exception before starting tests for ' + ser['name'],
|
||||
file=sys.stderr)
|
||||
print(str(exc), file=sys.stderr)
|
||||
except Exception as exc:
|
||||
# Print exception stack trace
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print('Exception before starting tests for ' + ser['name'],
|
||||
file=sys.stderr)
|
||||
print(str(exc), file=sys.stderr)
|
||||
|
||||
# Mark failure as true
|
||||
global failure
|
||||
failure = True
|
||||
# Mark failure as true
|
||||
global failure
|
||||
failure = True
|
||||
|
||||
# Clean driver object created
|
||||
if driver_object is not None:
|
||||
driver_object.quit()
|
||||
# Clean driver object created
|
||||
if driver_object is not None:
|
||||
driver_object.quit()
|
||||
|
||||
|
||||
def run_sequential_tests(url_client, servers_details, sequential_tests_lists,
|
||||
@ -654,7 +667,7 @@ def run_sequential_tests(url_client, servers_details, sequential_tests_lists,
|
||||
t = threading.Thread(target=execute_test,
|
||||
name=thread_name,
|
||||
args=(sequential_tests_lists, ser,
|
||||
driver_object))
|
||||
driver_object, True))
|
||||
t.start()
|
||||
t.join()
|
||||
except Exception as exc:
|
||||
@ -779,105 +792,114 @@ if __name__ == '__main__':
|
||||
if args['pkg'] is not None:
|
||||
node_name = args['pkg'].split('.')[-1]
|
||||
|
||||
is_parallel_ui_tests = test_utils.is_parallel_ui_tests(args)
|
||||
# Check if feature tests included & parallel tests switch passed
|
||||
if test_utils.is_feature_test_included(args) and \
|
||||
test_utils.is_parallel_ui_tests(args):
|
||||
try:
|
||||
# Get selenium config dict
|
||||
selenoid_config = test_setup.config_data['selenoid_config']
|
||||
if test_utils.is_feature_test_included(args) and is_parallel_ui_tests:
|
||||
if config.SERVER_MODE:
|
||||
try:
|
||||
# Get selenium config dict
|
||||
selenoid_config = test_setup.config_data['selenoid_config']
|
||||
|
||||
# Set DEFAULT_SERVER value
|
||||
default_server = selenoid_config['pgAdmin_default_server']
|
||||
os.environ["PGADMIN_CONFIG_DEFAULT_SERVER"] = str(default_server)
|
||||
config.DEFAULT_SERVER = str(default_server)
|
||||
# Set DEFAULT_SERVER value
|
||||
default_server = selenoid_config['pgAdmin_default_server']
|
||||
os.environ["PGADMIN_CONFIG_DEFAULT_SERVER"] = str(
|
||||
default_server)
|
||||
config.DEFAULT_SERVER = str(default_server)
|
||||
|
||||
# Get hub url
|
||||
hub_url = selenoid_config['selenoid_url']
|
||||
# Get hub url
|
||||
hub_url = selenoid_config['selenoid_url']
|
||||
|
||||
# Get selenium grid status & list of available browser out passed
|
||||
selenium_grid_status, list_of_browsers \
|
||||
= test_utils.get_selenium_grid_status_and_browser_list(hub_url,
|
||||
args)
|
||||
# Get selenium grid status & list of available browser
|
||||
# out of passed
|
||||
selenium_grid_status, list_of_browsers = test_utils.\
|
||||
get_selenium_grid_status_and_browser_list(hub_url, args)
|
||||
|
||||
# Execute tests if selenium-grid is up
|
||||
if selenium_grid_status and len(list_of_browsers) > 0:
|
||||
app_starter_local = None
|
||||
# run across browsers
|
||||
for browser_info in list_of_browsers:
|
||||
try:
|
||||
# browser info
|
||||
browser_name, browser_version = \
|
||||
test_utils.get_browser_details(browser_info,
|
||||
hub_url)
|
||||
# Execute tests if selenium-grid is up
|
||||
if selenium_grid_status and len(list_of_browsers) > 0:
|
||||
app_starter_local = None
|
||||
# run across browsers
|
||||
for browser_info in list_of_browsers:
|
||||
try:
|
||||
# browser info
|
||||
browser_name, browser_version = \
|
||||
test_utils.get_browser_details(browser_info,
|
||||
hub_url)
|
||||
|
||||
# test lists can be executed in parallel & sequentially
|
||||
parallel_tests, sequential_tests = \
|
||||
test_utils.get_parallel_sequential_module_list(
|
||||
test_module_list)
|
||||
# test lists can be executed in
|
||||
# parallel & sequentially
|
||||
parallel_tests, sequential_tests = \
|
||||
test_utils.get_parallel_sequential_module_list(
|
||||
test_module_list)
|
||||
|
||||
# Print test summary
|
||||
test_utils.print_test_summary(
|
||||
test_module_list, parallel_tests, sequential_tests,
|
||||
browser_name, browser_version)
|
||||
|
||||
# Create app form source code
|
||||
app_starter_local = AppStarter(None, config)
|
||||
client_url = app_starter_local.start_app()
|
||||
|
||||
if config.DEBUG:
|
||||
print('pgAdmin is launched with DEBUG=True, '
|
||||
'hence sleeping for 50 seconds.',
|
||||
file=sys.stderr)
|
||||
time.sleep(50)
|
||||
|
||||
# Running Parallel tests
|
||||
if len(parallel_tests) > 0:
|
||||
parallel_sessions = \
|
||||
int(selenoid_config['max_parallel_sessions'])
|
||||
|
||||
run_parallel_tests(
|
||||
client_url, servers_info, parallel_tests,
|
||||
browser_name, browser_version,
|
||||
parallel_sessions)
|
||||
|
||||
# Sequential Tests
|
||||
if len(sequential_tests) > 0:
|
||||
run_sequential_tests(
|
||||
client_url, servers_info, sequential_tests,
|
||||
# Print test summary
|
||||
test_utils.print_test_summary(
|
||||
test_module_list, parallel_tests,
|
||||
sequential_tests,
|
||||
browser_name, browser_version)
|
||||
|
||||
# Clean up environment
|
||||
if app_starter_local:
|
||||
app_starter_local.stop_app()
|
||||
# Create app form source code
|
||||
app_starter_local = AppStarter(None, config)
|
||||
client_url = app_starter_local.start_app()
|
||||
|
||||
# Pause before printing result in order
|
||||
# not to mix output
|
||||
time.sleep(5)
|
||||
if config.DEBUG:
|
||||
print('pgAdmin is launched with DEBUG=True, '
|
||||
'hence sleeping for 50 seconds.',
|
||||
file=sys.stderr)
|
||||
time.sleep(50)
|
||||
|
||||
# Print note for completion of execution in a browser.
|
||||
print(
|
||||
"\n============= Test execution with {0} is "
|
||||
"completed.=============".format(browser_name),
|
||||
file=sys.stderr)
|
||||
print_test_results()
|
||||
# Running Parallel tests
|
||||
if len(parallel_tests) > 0:
|
||||
parallel_sessions = \
|
||||
int(selenoid_config[
|
||||
'max_parallel_sessions'])
|
||||
|
||||
except SystemExit:
|
||||
if app_starter_local:
|
||||
app_starter_local.stop_app()
|
||||
if handle_cleanup:
|
||||
handle_cleanup()
|
||||
raise
|
||||
else:
|
||||
print(
|
||||
"\n============= Either Selenium Grid is NOT up OR"
|
||||
" browser list is 0 =============", file=sys.stderr)
|
||||
run_parallel_tests(
|
||||
client_url, servers_info, parallel_tests,
|
||||
browser_name, browser_version,
|
||||
parallel_sessions)
|
||||
|
||||
# Sequential Tests
|
||||
if len(sequential_tests) > 0:
|
||||
run_sequential_tests(
|
||||
client_url, servers_info, sequential_tests,
|
||||
browser_name, browser_version)
|
||||
|
||||
# Clean up environment
|
||||
if app_starter_local:
|
||||
app_starter_local.stop_app()
|
||||
|
||||
# Pause before printing result in order
|
||||
# not to mix output
|
||||
time.sleep(5)
|
||||
|
||||
print(
|
||||
"\n============= Test execution with {0} is "
|
||||
"completed.=============".format(browser_name),
|
||||
file=sys.stderr)
|
||||
print_test_results()
|
||||
|
||||
except SystemExit:
|
||||
if app_starter_local:
|
||||
app_starter_local.stop_app()
|
||||
if handle_cleanup:
|
||||
handle_cleanup()
|
||||
raise
|
||||
else:
|
||||
print(
|
||||
"\n============= Either Selenium Grid is NOT up OR"
|
||||
" browser list is 0 =============", file=sys.stderr)
|
||||
failure = True
|
||||
except Exception as exc:
|
||||
# Print exception stack trace
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print(str(exc))
|
||||
failure = True
|
||||
except Exception as exc:
|
||||
# Print exception stack trace
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print(str(exc))
|
||||
del os.environ["PGADMIN_CONFIG_DEFAULT_SERVER"]
|
||||
else:
|
||||
print(
|
||||
"\n============= Please Turn on Server Mode to run selenoid "
|
||||
"tests =============", file=sys.stderr)
|
||||
failure = True
|
||||
del os.environ["PGADMIN_CONFIG_DEFAULT_SERVER"]
|
||||
else:
|
||||
try:
|
||||
for server in servers_info:
|
||||
|
Loading…
Reference in New Issue
Block a user