diff --git a/app/selenium_ui/confluence/modules.py b/app/selenium_ui/confluence/modules.py index d19524df5..6c2003860 100644 --- a/app/selenium_ui/confluence/modules.py +++ b/app/selenium_ui/confluence/modules.py @@ -1,5 +1,5 @@ import random -from selenium_ui.conftest import print_timing, measure_browser_navi_metrics, measure_dom_requests +from selenium_ui.conftest import print_timing, measure_timing, measure_dom_requests, measure_with_browser_metrics from selenium_ui.confluence.pages.pages import Login, AllUpdates, PopupManager, Page, Dashboard, TopNavPanel, Editor, \ Logout @@ -57,45 +57,45 @@ def login(webdriver, datasets): login_page = Login(webdriver) webdriver.debug_info = generate_debug_session_info(webdriver, datasets) - @print_timing("selenium_login") - def measure(): - def sub_measure(): + def measure(): + login_page.go_to() + if login_page.is_logged_in(): + login_page.delete_all_cookies() login_page.go_to() - if login_page.is_logged_in(): - login_page.delete_all_cookies() - login_page.go_to() - login_page.wait_for_page_loaded() - node_id = login_page.get_node_id() - node_ip = rest_client.get_node_ip(node_id) - webdriver.node_ip = node_ip - print(f"node_id:{node_id}, node_ip: {webdriver.node_ip}") - measure_dom_requests(webdriver, interaction="selenium_login:open_login_page") - - sub_measure() + login_page.wait_for_page_loaded() + node_id = login_page.get_node_id() + node_ip = rest_client.get_node_ip(node_id) + webdriver.node_ip = node_ip + print(f"node_id:{node_id}, node_ip: {webdriver.node_ip}") + measure_dom_requests(webdriver, interaction="selenium_login:open_login_page") login_page.set_credentials(username=datasets['current_session']['username'], password=datasets['current_session']['password']) - def sub_measure(): - login_page.click_login_button() - all_updates_page = AllUpdates(webdriver) - all_updates_page.wait_for_page_loaded() - if login_page.is_first_login(): - login_page.first_user_setup() - all_updates_page.wait_for_page_loaded() - measure_dom_requests(webdriver, interaction="selenium_login:login_and_view_dashboard") - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, expected_metrics=browser_metrics['selenium_login']) + login_page.click_login_button() + all_updates_page = AllUpdates(webdriver) + all_updates_page.wait_for_page_loaded() + if login_page.is_first_login(): + login_page.first_user_setup() + all_updates_page.wait_for_page_loaded() + measure_dom_requests(webdriver, interaction="selenium_login:login_and_view_dashboard") - sub_measure() + + def post_metric_measure(): current_session_response = login_page.rest_api_get(url=f'{CONFLUENCE_SETTINGS.server_url}' f'/rest/api/user/current') if 'username' in current_session_response: actual_username = current_session_response['username'] assert actual_username == datasets['current_session']['username'] - measure() + measure_with_browser_metrics( + "selenium_login", + webdriver, + datasets, + measure, + post_metric_measure + ) PopupManager(webdriver).dismiss_default_popup() @@ -107,15 +107,17 @@ def view_page(webdriver, datasets): datasets['current_session']['view_page_cache'] = random_page page = Page(webdriver, page_id=page_id) - @print_timing("selenium_view_page") def measure(): page.go_to() page.wait_for_page_loaded() measure_dom_requests(webdriver, interaction=f"selenium_view_page", description=page_description) - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, expected_metrics=browser_metrics['selenium_view_page']) - measure() + measure_with_browser_metrics( + "selenium_view_page", + webdriver, + datasets, + measure + ) def view_page_from_cache(webdriver, datasets): @@ -126,17 +128,17 @@ def view_page_from_cache(webdriver, datasets): page = Page(webdriver, page_id=page_id) - @print_timing("selenium_view_page_from_cache") def measure(): page.go_to() page.wait_for_page_loaded() measure_dom_requests(webdriver, interaction=f"selenium_view_page_from_cache", description=page_description) - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, - expected_metrics=browser_metrics['selenium_view_page_from_cache']) - - measure() + measure_with_browser_metrics( + "selenium_view_page_from_cache", + webdriver, + datasets, + measure + ) def view_blog(webdriver, datasets): random_blog = random.choice(datasets[BLOGS]) @@ -145,64 +147,65 @@ def view_blog(webdriver, datasets): blog = Page(webdriver, page_id=blog_id) datasets['current_session']['view_blog'] = random_blog - @print_timing("selenium_view_blog") def measure(): blog.go_to() blog.wait_for_page_loaded() measure_dom_requests(webdriver, interaction=f"selenium_view_blog", description=blog_description) - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, expected_metrics=browser_metrics['selenium_view_blog']) - measure() + measure_with_browser_metrics( + "selenium_view_blog", + webdriver, + datasets, + measure + ) def view_dashboard(webdriver, datasets): dashboard_page = Dashboard(webdriver) - @print_timing("selenium_view_dashboard") def measure(): dashboard_page.go_to() dashboard_page.wait_for_page_loaded() measure_dom_requests(webdriver, interaction="selenium_view_dashboard") - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, - expected_metrics=browser_metrics['selenium_view_dashboard']) - - measure() + measure_with_browser_metrics( + "selenium_view_dashboard", + webdriver, + datasets, + measure + ) def create_confluence_page(webdriver, datasets): nav_panel = TopNavPanel(webdriver) create_page = Editor(webdriver) - @print_timing("selenium_create_page") def measure(): - def sub_measure(): - PopupManager(webdriver).dismiss_default_popup() - nav_panel.click_create() - PopupManager(webdriver).dismiss_default_popup() - create_page.wait_for_create_page_open() - measure_dom_requests(webdriver, interaction="selenium_create_page:open_create_page_editor") - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, - expected_metrics=browser_metrics['selenium_create_page']) + PopupManager(webdriver).dismiss_default_popup() + nav_panel.click_create() + PopupManager(webdriver).dismiss_default_popup() + create_page.wait_for_create_page_open() + measure_dom_requests(webdriver, interaction="selenium_create_page:open_create_page_editor") - sub_measure() + def post_metric_measure(): PopupManager(webdriver).dismiss_default_popup() create_page.write_title() create_page.write_content() - def sub_measure(): - create_page.click_submit() - page = Page(webdriver) - page.wait_for_page_loaded() - measure_dom_requests(webdriver, interaction="selenium_create_page:save_created_page") + create_page.click_submit() + page = Page(webdriver) + page.wait_for_page_loaded() + measure_dom_requests(webdriver, interaction="selenium_create_page:save_created_page") - sub_measure() - measure() + measure_with_browser_metrics( + "selenium_create_page", + webdriver, + datasets, + measure, + post_metric_measure + ) def edit_confluence_page_by_url(webdriver, datasets): @@ -212,29 +215,26 @@ def edit_confluence_page_by_url(webdriver, datasets): datasets['current_session']['edit_page'] = random_page edit_page = Editor(webdriver, page_id=page_id) - @print_timing("selenium_edit_page_by_url") def measure(): - def sub_measure(): - edit_page.go_to() - edit_page.wait_for_page_loaded() - measure_dom_requests(webdriver, interaction=f"selenium_edit_page_by_url:open_create_page_editor", - description=page_description) - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, - expected_metrics=browser_metrics['selenium_edit_page_by_url']) - - sub_measure() + edit_page.go_to() + edit_page.wait_for_page_loaded() + measure_dom_requests(webdriver, interaction=f"selenium_edit_page_by_url:open_create_page_editor", + description=page_description) + def post_metric_measure(): edit_page.write_content() - def sub_measure(): - edit_page.save_edited_page() - measure_dom_requests(webdriver, interaction=f"selenium_edit_page_by_url:save_edited_page", - description=page_description) - - sub_measure() + edit_page.save_edited_page() + measure_dom_requests(webdriver, interaction=f"selenium_edit_page_by_url:save_edited_page", + description=page_description) - measure() + measure_with_browser_metrics( + "selenium_edit_page_by_url", + webdriver, + datasets, + measure, + post_metric_measure + ) def edit_confluence_page_quick_edit(webdriver, datasets): @@ -246,32 +246,29 @@ def edit_confluence_page_quick_edit(webdriver, datasets): @print_timing("selenium_quick_edit_page_click") def measure(): - def sub_measure(): - page.go_to() - page.wait_for_resources_loaded() - page.wait_for_page_loaded() - PopupManager(webdriver).dismiss_default_popup() - page.click_edit() - edit_page.wait_for_page_loaded() - measure_dom_requests(webdriver, interaction=f"selenium_quick_edit_page_click:open_create_page_editor", - description=page_description) - if CONFLUENCE_SETTINGS.extended_metrics: - measure_browser_navi_metrics(webdriver, datasets, - expected_metrics=browser_metrics['selenium_quick_edit_page_click']) - - sub_measure() + page.go_to() + page.wait_for_resources_loaded() + page.wait_for_page_loaded() + PopupManager(webdriver).dismiss_default_popup() + page.click_edit() + edit_page.wait_for_page_loaded() + measure_dom_requests(webdriver, interaction=f"selenium_quick_edit_page_click:open_create_page_editor", + description=page_description) + def post_metric_measure(): edit_page.write_content() - def sub_measure(): - edit_page.save_edited_page() - measure_dom_requests(webdriver, interaction=f"selenium_quick_edit_page_click:save_edited_page", - description=page_description) - - sub_measure() - - measure() + edit_page.save_edited_page() + measure_dom_requests(webdriver, interaction=f"selenium_quick_edit_page_click:save_edited_page", + description=page_description) + measure_with_browser_metrics( + "selenium_quick_edit_page_click", + webdriver, + datasets, + measure, + post_metric_measure + ) def create_inline_comment(webdriver, datasets): page = random.choice(datasets[PAGES]) diff --git a/app/selenium_ui/conftest.py b/app/selenium_ui/conftest.py index a52243165..4f4f12737 100644 --- a/app/selenium_ui/conftest.py +++ b/app/selenium_ui/conftest.py @@ -18,6 +18,7 @@ from util.common_util import webdriver_pretty_debug from util.conf import CONFLUENCE_SETTINGS, JIRA_SETTINGS, BITBUCKET_SETTINGS, JSM_SETTINGS, BAMBOO_SETTINGS +from util.confluence.browser_metrics import browser_metrics from util.exceptions import WebDriverExceptionPostpone from util.project_paths import JIRA_DATASET_ISSUES, JIRA_DATASET_JQLS, JIRA_DATASET_KANBAN_BOARDS, \ JIRA_DATASET_PROJECTS, JIRA_DATASET_SCRUM_BOARDS, JIRA_DATASET_USERS, JIRA_DATASET_CUSTOM_ISSUES, BITBUCKET_USERS, \ @@ -139,6 +140,55 @@ def is_docker(): ) +def measure_timing(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + start = time() + func(*args, **kwargs) + end = time() + return end - start + return wrapper + + +def measure_with_browser_metrics(interaction_name, webdriver, datasets, measure_func, post_metric_measure_func=None): + """ + Helper function that combines timing for measure_func + post_metric_measure_func + ready_for_user_timing. + """ + # Step 1: Measure core operations + @measure_timing + def measure1(): + measure_func() + + timing = measure1() + + # Step 2: Measure browser metrics AFTER core operations (not included in core timing) + ready_for_user_timing = None + if CONFLUENCE_SETTINGS.extended_metrics: + ready_for_user_timing = measure_browser_navi_metrics( + webdriver, datasets, expected_metrics=browser_metrics[interaction_name] + ) + + # Step 3: Measure post_metric_measure_func (included in total timing) + if post_metric_measure_func is not None: + @measure_timing + def measure_post(): + post_metric_measure_func() + + post_timing = measure_post() + timing = timing + post_timing + + # Step 4: Calculate combined timing (core + post + ready_for_user) + if ready_for_user_timing is not None: + timing = timing + (int(ready_for_user_timing) / 1000) + + # Step 5: Record combined timing using print_timing with explicit_timing + @print_timing(interaction_name, explicit_timing=timing) + def record_result(): + pass + + record_result() + + def print_timing(interaction=None, explicit_timing=None): assert interaction is not None, "Interaction name is not passed to print_timing decorator" @@ -182,8 +232,9 @@ def wrapper(*args, **kwargs): with open(selenium_results_file, "a+") as jtl_file: timestamp = round(time() * 1000) if explicit_timing: + timing = str(int(explicit_timing * 1000)) jtl_file.write( - f"{timestamp},{explicit_timing*1000},{interaction},,{error_msg}," + f"{timestamp},{timing},{interaction},,{error_msg}," f",{success},0,0,0,0,,0\n") else: jtl_file.write( @@ -295,11 +346,22 @@ def get_requests_by_url(requests, url_path): return filtered_requests +def click_page_body(webdriver): + try: + body_element = webdriver.find_element("tag name", "body") + body_element.click() + print("Successfully clicked on page body") + except Exception as e: + print(f"Failed to click on page body: {e}") + + def get_wait_browser_metrics(webdriver, expected_metrics): attempts = 15 sleep_time = 0.5 data = {} + click_page_body(webdriver) #this resolves browser metric + for i in range(attempts): requests = get_performance_logs(webdriver) requests_bulk = get_requests_by_url(requests, 'bulk') @@ -398,8 +460,11 @@ def measure_browser_navi_metrics(webdriver, dataset, expected_metrics): lockfile = f'{selenium_results_file}.lock' error_msg = 'Success' success = True + ready_for_user_timing = None + if not metrics: - return + return ready_for_user_timing + with filelock.SoftFileLock(lockfile): with open(selenium_results_file, "a+") as jtl_file: for metric in metrics: @@ -411,6 +476,8 @@ def measure_browser_navi_metrics(webdriver, dataset, expected_metrics): f"{timestamp},{ready_for_user_timing},{interaction},,{error_msg},,{success},0,0,0,0,{node_ip},0\n") print( f"{timestamp},{ready_for_user_timing},{interaction},{error_msg},{success},{node_ip}") + + return ready_for_user_timing @pytest.fixture(scope="module")