Modifies the way to execute feature tests in parallel and it should be configured in Server Mode.

This commit is contained in:
Yogesh Mahajan 2021-05-27 11:01:25 +05:30 committed by Akshay Joshi
parent faa49687be
commit 2d58f60a53
9 changed files with 209 additions and 136 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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(

View File

@ -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

View File

@ -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: