From 889f3c85c89829017a73a1b6bb50e3554d0416d9 Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Mon, 29 Jul 2024 07:12:08 +0200 Subject: [PATCH 1/6] style: One more space --- .../ci-scripts/utility_scripts/playwright-update-tokens.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py index afd146414..20243e180 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py @@ -101,7 +101,7 @@ def main(): users = json.load(fd) users_new = [] - users_allowlist = [] # keep empty to allow all + users_allowlist = [] # keep empty to allow all for user in users: if users_allowlist is not [] and user["username"] not in users_allowlist: From 19fc716500bdb762880f11f00477b31e73adbc4c Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Mon, 29 Jul 2024 07:14:33 +0200 Subject: [PATCH 2/6] feat: Script to create Stage users, should not be necessary as jhutar have them precreated, so just for record --- .../playwright-create-users.py | 100 ++++++------------ 1 file changed, 31 insertions(+), 69 deletions(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py index a5600c9ba..28bbc215c 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py @@ -25,16 +25,13 @@ import email.parser import email.policy import json +import os +import os.path import subprocess import time import uuid import multiprocessing import queue -import os.path -import sys - -sys.path.append(os.path.dirname(os.path.realpath(__file__))) -import playwright_lib PLAYWRIGHT_HEADLESS = False PLAYWRIGHT_VIDEO_DIR = "videos/" @@ -54,40 +51,18 @@ def get_verification_link(user_email): raise Exception(f"Out of tries to get verification email for {user_email}") try: - fetchmail = subprocess.run( - ["fetchmail"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT - ) - if fetchmail.returncode not in ( - 0, - 1, - ): # 0 = emails downloaded, 1 = no new emails - raise Exception( - f"Running 'fetchmail' failed with {fetchmail.returncode}: {fetchmail.stdout}" - ) - - notmuch_search = subprocess.run( - [ - "notmuch", - "search", - "--output=files", - "--format=json", - "--sort=newest-first", - f"to:'{user_email}' AND subject:'Verify email for Red Hat account' AND date:'1hour..now'", - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) + fetchmail = subprocess.run(["fetchmail"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if fetchmail.returncode not in (0, 1): # 0 = emails downloaded, 1 = no new emails + raise Exception(f"Running 'fetchmail' failed with {fetchmail.returncode}: {fetchmail.stdout}") + + notmuch_search = subprocess.run(["notmuch", "search", "--output=files", "--format=json", "--sort=newest-first", f"to:'{user_email}' AND subject:'Verify email for Red Hat account' AND date:'1hour..now'"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if notmuch_search.returncode != 0: - raise Exception( - f"Running 'notmuch search ...' failed with {notmuch_search.returncode}: {notmuch_search.stderr}" - ) + raise Exception(f"Running 'notmuch search ...' failed with {notmuch_search.returncode}: {notmuch_search.stderr}") message_files_json = notmuch_search.stdout message_files = json.loads(message_files_json) if len(message_files) != 1: - raise Exception( - f"Command 'notmuch search ...' returned unexpected number of files: {message_files}" - ) + raise Exception(f"Command 'notmuch search ...' returned unexpected number of files: {message_files}") if not os.path.isfile(message_files[0]): raise Exception("File {message_files[0]} is missing") @@ -103,15 +78,11 @@ def get_verification_link(user_email): simplest = msg.get_body(preferencelist=("plain")) for line in simplest.get_content().splitlines(): line = line.strip() - if line.startswith( - "https://sso.redhat.com/auth/realms/redhat-external/login-actions/action-token?key=" - ): + if line.startswith("https://sso.redhat.com/auth/realms/redhat-external/login-actions/action-token?key="): return line -def click_and_wait_hard( - page, clickable, verifier, timeout_ms_start=1000, timeout_ms_max=30000 -): +def click_and_wait_hard(page, clickable, verifier, timeout_ms_start=1000, timeout_ms_max=30000): """ Try to click at given thingy (probably link) and wait for another thingy to appear, try it multiple times untill it works @@ -124,29 +95,22 @@ def click_and_wait_hard( page.wait_for_selector(verifier, timeout=timeout) except playwright.sync_api.TimeoutError as e: if timeout >= timeout_ms_max: - raise # giving up + raise # giving up timeout *= 2 else: - break # success - - -def generate_password(): - """ - Keep generating password until it contains both digit and letter. - Given special char ("-") is granted, this will meet password requirements. - """ - while True: - password = str(uuid.uuid4()) - contains_digit = any(char.isdigit() for char in password) - contains_alpha = any(char.isalpha() for char in password) - if contains_digit and contains_alpha: - return password + break # success def workload(user): username = user["username"] email = f"jhutar+{username}@redhat.com" - password = generate_password() + + # Keep generating password until it contains both digit and letter. + # Given special char ("-") is granted, this will meet password requirements. + while True: + password = str(uuid.uuid4()) + if any(char.isdigit() for char in password) and any(char.isalpha() for char in password): + break with playwright.sync_api.sync_playwright() as p: browser = p.chromium.launch( @@ -157,14 +121,16 @@ def workload(user): ) page = context.new_page() - playwright_lib.goto_login_and_accept_cookies(page) + page.goto("https://console.dev.redhat.com") + page.wait_for_url("https://sso.redhat.com/**") + + # Accept cookies + cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') + cookies_button = cookies_iframe.get_by_role("button", name="Agree and proceed with standard settings") + cookies_button.click() # Go to registration form - click_and_wait_hard( - page, - '//a[@id="rh-login-registration-link"]', - '//h1[text()="Register for a Red Hat account"]', - ) + click_and_wait_hard(page, '//a[@id="rh-login-registration-link"]', '//h1[text()="Register for a Red Hat account"]') # Fill the form user_input = page.locator('//input[@id="username"]') @@ -177,9 +143,7 @@ def workload(user): last_input.fill("Testing") email_input = page.locator('//input[@id="email"]') email_input.fill(email) - terms_checkbox = page.locator( - '//input[contains(@id, "user.attributes.tcacc-SSO/ssoSignIn/")]' - ) + terms_checkbox = page.locator('//input[contains(@id, "user.attributes.tcacc-SSO/ssoSignIn/")]') terms_checkbox.click() submit_button = page.locator('//input[@id="regform-submit"]') submit_button.click() @@ -188,9 +152,7 @@ def workload(user): # Verify account verification_link = get_verification_link(email) page.goto(verification_link) - page.wait_for_selector( - f'//h1[text()="Confirm validity of e-mail address {email}."]' - ) + page.wait_for_selector(f'//h1[text()="Confirm validity of e-mail address {email}."]') finish_button = page.locator('//a[text()="Finish"]') finish_button.click() page.wait_for_selector('//h1[text()="Your email address has been verified"]') @@ -244,7 +206,7 @@ def main(): print(users_new) with open("users-new.json", "w") as fd: print(f"Dumping {len(users_new)} users") - json.dump(users_new, fd) + users = json.dump(users_new, fd) if __name__ == "__main__": From 48ed475eb70238576e45116db34c201144cfbb27 Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Mon, 29 Jul 2024 08:03:17 +0200 Subject: [PATCH 3/6] feat: Script to join user to waitlist --- .../playwright-join-waitlist.py | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py index dad8c11a9..a0bf8847d 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py @@ -19,19 +19,15 @@ # getting "Access Denied" errors. I guess it was some rate limiting. import playwright.sync_api +import os +import time import json import multiprocessing import queue -import os.path -import sys - -sys.path.append(os.path.dirname(os.path.realpath(__file__))) -import playwright_lib PLAYWRIGHT_HEADLESS = False PLAYWRIGHT_VIDEO_DIR = "videos/" - def workload(user): username = user["username"].replace("-", "_") password = user["password"] @@ -45,24 +41,39 @@ def workload(user): ) page = context.new_page() - playwright_lib.goto_login_and_accept_cookies(page) - - playwright_lib.form_login(page, username, password) - - # Go to Konflux + page.goto("https://console.dev.redhat.com") + page.wait_for_url("https://sso.redhat.com/**") + + # Accept cookies + cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') + cookies_button = cookies_iframe.get_by_role("button", name="Agree and proceed with standard settings") + cookies_button.click() + + # Wait for login form and use it + page.wait_for_selector('//h1[text()="Log in to your Red Hat account"]') + input_user = page.locator('//input[@id="username-verification"]') + time.sleep(1) + input_user.fill(username) + button_next = page.locator('//button[@id="login-show-step2"]') + button_next.click() + button_next.wait_for(state="hidden") + input_pass = page.locator('//input[@id="password"]') + input_pass.wait_for(state="visible") + input_pass.fill(password) + page.locator('//button[@id="rh-password-verification-submit-button"]').click() + + # Wait for console and go to Konflux page + page.wait_for_url("https://console.dev.redhat.com/**") + page.wait_for_selector('//h2[text()="Welcome to your Hybrid Cloud Console."]') page.goto("https://console.dev.redhat.com/preview/application-pipeline") # Accept terms and conditions if this appears try: - page.wait_for_selector( - '//h1[text()="We need a little more information"]', timeout=15 - ) + page.wait_for_selector('//h1[text()="We need a little more information"]', timeout=15) except playwright.sync_api.TimeoutError as e: pass else: - terms_checkbox = page.locator( - '//input[contains(@id, "user.attributes.tcacc-SSO/developersPortalSubscriptionCreation/")]' - ) + terms_checkbox = page.locator('//input[contains(@id, "user.attributes.tcacc-SSO/developersPortalSubscriptionCreation/")]') terms_checkbox.click() submit_button = page.locator('//button[@id="regform-submit"]') submit_button.click() @@ -71,9 +82,7 @@ def workload(user): page.wait_for_selector('//h1[contains(text(), "Get started with")]') join_button = page.locator('//button[text()="Join the waitlist"]') join_button.click() - page.wait_for_selector( - '//h4[contains(text(), "We have received your request")]' - ) + page.wait_for_selector('//h4[contains(text(), "We have received your request")]') def process_it(output_queue, user): @@ -88,7 +97,7 @@ def main(): with open("users.json", "r") as fd: users = json.load(fd) - users_allowlist = [] # keep empty to allow all + users_allowlist = [] # keep empty to allow all for user in users: if users_allowlist is [] or user["username"] in users_allowlist: From 0f32595dfbc52f7703a9b2133e41959ebba43d2b Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Mon, 29 Jul 2024 08:04:21 +0200 Subject: [PATCH 4/6] style: Black formater and flake8 fixes --- .../playwright-create-users.py | 72 ++++++++++++++----- .../playwright-join-waitlist.py | 20 ++++-- .../playwright-update-tokens.py | 9 ++- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py index 28bbc215c..acd2c8123 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py @@ -51,18 +51,40 @@ def get_verification_link(user_email): raise Exception(f"Out of tries to get verification email for {user_email}") try: - fetchmail = subprocess.run(["fetchmail"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - if fetchmail.returncode not in (0, 1): # 0 = emails downloaded, 1 = no new emails - raise Exception(f"Running 'fetchmail' failed with {fetchmail.returncode}: {fetchmail.stdout}") - - notmuch_search = subprocess.run(["notmuch", "search", "--output=files", "--format=json", "--sort=newest-first", f"to:'{user_email}' AND subject:'Verify email for Red Hat account' AND date:'1hour..now'"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + fetchmail = subprocess.run( + ["fetchmail"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) + if fetchmail.returncode not in ( + 0, + 1, + ): # 0 = emails downloaded, 1 = no new emails + raise Exception( + f"Running 'fetchmail' failed with {fetchmail.returncode}: {fetchmail.stdout}" + ) + + notmuch_search = subprocess.run( + [ + "notmuch", + "search", + "--output=files", + "--format=json", + "--sort=newest-first", + f"to:'{user_email}' AND subject:'Verify email for Red Hat account' AND date:'1hour..now'", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) if notmuch_search.returncode != 0: - raise Exception(f"Running 'notmuch search ...' failed with {notmuch_search.returncode}: {notmuch_search.stderr}") + raise Exception( + f"Running 'notmuch search ...' failed with {notmuch_search.returncode}: {notmuch_search.stderr}" + ) message_files_json = notmuch_search.stdout message_files = json.loads(message_files_json) if len(message_files) != 1: - raise Exception(f"Command 'notmuch search ...' returned unexpected number of files: {message_files}") + raise Exception( + f"Command 'notmuch search ...' returned unexpected number of files: {message_files}" + ) if not os.path.isfile(message_files[0]): raise Exception("File {message_files[0]} is missing") @@ -78,11 +100,15 @@ def get_verification_link(user_email): simplest = msg.get_body(preferencelist=("plain")) for line in simplest.get_content().splitlines(): line = line.strip() - if line.startswith("https://sso.redhat.com/auth/realms/redhat-external/login-actions/action-token?key="): + if line.startswith( + "https://sso.redhat.com/auth/realms/redhat-external/login-actions/action-token?key=" + ): return line -def click_and_wait_hard(page, clickable, verifier, timeout_ms_start=1000, timeout_ms_max=30000): +def click_and_wait_hard( + page, clickable, verifier, timeout_ms_start=1000, timeout_ms_max=30000 +): """ Try to click at given thingy (probably link) and wait for another thingy to appear, try it multiple times untill it works @@ -95,10 +121,10 @@ def click_and_wait_hard(page, clickable, verifier, timeout_ms_start=1000, timeou page.wait_for_selector(verifier, timeout=timeout) except playwright.sync_api.TimeoutError as e: if timeout >= timeout_ms_max: - raise # giving up + raise # giving up timeout *= 2 else: - break # success + break # success def workload(user): @@ -109,7 +135,9 @@ def workload(user): # Given special char ("-") is granted, this will meet password requirements. while True: password = str(uuid.uuid4()) - if any(char.isdigit() for char in password) and any(char.isalpha() for char in password): + if any(char.isdigit() for char in password) and any( + char.isalpha() for char in password + ): break with playwright.sync_api.sync_playwright() as p: @@ -126,11 +154,17 @@ def workload(user): # Accept cookies cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') - cookies_button = cookies_iframe.get_by_role("button", name="Agree and proceed with standard settings") + cookies_button = cookies_iframe.get_by_role( + "button", name="Agree and proceed with standard settings" + ) cookies_button.click() # Go to registration form - click_and_wait_hard(page, '//a[@id="rh-login-registration-link"]', '//h1[text()="Register for a Red Hat account"]') + click_and_wait_hard( + page, + '//a[@id="rh-login-registration-link"]', + '//h1[text()="Register for a Red Hat account"]', + ) # Fill the form user_input = page.locator('//input[@id="username"]') @@ -143,7 +177,9 @@ def workload(user): last_input.fill("Testing") email_input = page.locator('//input[@id="email"]') email_input.fill(email) - terms_checkbox = page.locator('//input[contains(@id, "user.attributes.tcacc-SSO/ssoSignIn/")]') + terms_checkbox = page.locator( + '//input[contains(@id, "user.attributes.tcacc-SSO/ssoSignIn/")]' + ) terms_checkbox.click() submit_button = page.locator('//input[@id="regform-submit"]') submit_button.click() @@ -152,7 +188,9 @@ def workload(user): # Verify account verification_link = get_verification_link(email) page.goto(verification_link) - page.wait_for_selector(f'//h1[text()="Confirm validity of e-mail address {email}."]') + page.wait_for_selector( + f'//h1[text()="Confirm validity of e-mail address {email}."]' + ) finish_button = page.locator('//a[text()="Finish"]') finish_button.click() page.wait_for_selector('//h1[text()="Your email address has been verified"]') @@ -206,7 +244,7 @@ def main(): print(users_new) with open("users-new.json", "w") as fd: print(f"Dumping {len(users_new)} users") - users = json.dump(users_new, fd) + json.dump(users_new, fd) if __name__ == "__main__": diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py index a0bf8847d..8e2e583e6 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py @@ -19,7 +19,6 @@ # getting "Access Denied" errors. I guess it was some rate limiting. import playwright.sync_api -import os import time import json import multiprocessing @@ -28,6 +27,7 @@ PLAYWRIGHT_HEADLESS = False PLAYWRIGHT_VIDEO_DIR = "videos/" + def workload(user): username = user["username"].replace("-", "_") password = user["password"] @@ -46,7 +46,9 @@ def workload(user): # Accept cookies cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') - cookies_button = cookies_iframe.get_by_role("button", name="Agree and proceed with standard settings") + cookies_button = cookies_iframe.get_by_role( + "button", name="Agree and proceed with standard settings" + ) cookies_button.click() # Wait for login form and use it @@ -69,11 +71,15 @@ def workload(user): # Accept terms and conditions if this appears try: - page.wait_for_selector('//h1[text()="We need a little more information"]', timeout=15) + page.wait_for_selector( + '//h1[text()="We need a little more information"]', timeout=15 + ) except playwright.sync_api.TimeoutError as e: pass else: - terms_checkbox = page.locator('//input[contains(@id, "user.attributes.tcacc-SSO/developersPortalSubscriptionCreation/")]') + terms_checkbox = page.locator( + '//input[contains(@id, "user.attributes.tcacc-SSO/developersPortalSubscriptionCreation/")]' + ) terms_checkbox.click() submit_button = page.locator('//button[@id="regform-submit"]') submit_button.click() @@ -82,7 +88,9 @@ def workload(user): page.wait_for_selector('//h1[contains(text(), "Get started with")]') join_button = page.locator('//button[text()="Join the waitlist"]') join_button.click() - page.wait_for_selector('//h4[contains(text(), "We have received your request")]') + page.wait_for_selector( + '//h4[contains(text(), "We have received your request")]' + ) def process_it(output_queue, user): @@ -97,7 +105,7 @@ def main(): with open("users.json", "r") as fd: users = json.load(fd) - users_allowlist = [] # keep empty to allow all + users_allowlist = [] # keep empty to allow all for user in users: if users_allowlist is [] or user["username"] in users_allowlist: diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py index 20243e180..9614c7560 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py @@ -52,7 +52,12 @@ def workload(user): playwright_lib.goto_login_and_accept_cookies(page) - playwright_lib.form_login(page, username, password) + # Accept cookies + cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') + cookies_button = cookies_iframe.get_by_role( + "button", name="Agree and proceed with standard settings" + ) + cookies_button.click() # Go to OpenShift Token page page.goto("https://console.dev.redhat.com/openshift/token") @@ -101,7 +106,7 @@ def main(): users = json.load(fd) users_new = [] - users_allowlist = [] # keep empty to allow all + users_allowlist = [] # keep empty to allow all for user in users: if users_allowlist is not [] and user["username"] not in users_allowlist: From 5998933dd0560f7f23707ee4af47f361aec06af1 Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Mon, 29 Jul 2024 11:40:51 +0200 Subject: [PATCH 5/6] refactor: Create two shared functions --- .../playwright-create-users.py | 40 +++++++++---------- .../playwright-join-waitlist.py | 35 +++++----------- .../playwright-update-tokens.py | 7 +--- 3 files changed, 30 insertions(+), 52 deletions(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py index acd2c8123..a5600c9ba 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-create-users.py @@ -25,13 +25,16 @@ import email.parser import email.policy import json -import os -import os.path import subprocess import time import uuid import multiprocessing import queue +import os.path +import sys + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +import playwright_lib PLAYWRIGHT_HEADLESS = False PLAYWRIGHT_VIDEO_DIR = "videos/" @@ -127,18 +130,23 @@ def click_and_wait_hard( break # success +def generate_password(): + """ + Keep generating password until it contains both digit and letter. + Given special char ("-") is granted, this will meet password requirements. + """ + while True: + password = str(uuid.uuid4()) + contains_digit = any(char.isdigit() for char in password) + contains_alpha = any(char.isalpha() for char in password) + if contains_digit and contains_alpha: + return password + + def workload(user): username = user["username"] email = f"jhutar+{username}@redhat.com" - - # Keep generating password until it contains both digit and letter. - # Given special char ("-") is granted, this will meet password requirements. - while True: - password = str(uuid.uuid4()) - if any(char.isdigit() for char in password) and any( - char.isalpha() for char in password - ): - break + password = generate_password() with playwright.sync_api.sync_playwright() as p: browser = p.chromium.launch( @@ -149,15 +157,7 @@ def workload(user): ) page = context.new_page() - page.goto("https://console.dev.redhat.com") - page.wait_for_url("https://sso.redhat.com/**") - - # Accept cookies - cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') - cookies_button = cookies_iframe.get_by_role( - "button", name="Agree and proceed with standard settings" - ) - cookies_button.click() + playwright_lib.goto_login_and_accept_cookies(page) # Go to registration form click_and_wait_hard( diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py index 8e2e583e6..dad8c11a9 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-join-waitlist.py @@ -19,10 +19,14 @@ # getting "Access Denied" errors. I guess it was some rate limiting. import playwright.sync_api -import time import json import multiprocessing import queue +import os.path +import sys + +sys.path.append(os.path.dirname(os.path.realpath(__file__))) +import playwright_lib PLAYWRIGHT_HEADLESS = False PLAYWRIGHT_VIDEO_DIR = "videos/" @@ -41,32 +45,11 @@ def workload(user): ) page = context.new_page() - page.goto("https://console.dev.redhat.com") - page.wait_for_url("https://sso.redhat.com/**") + playwright_lib.goto_login_and_accept_cookies(page) - # Accept cookies - cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') - cookies_button = cookies_iframe.get_by_role( - "button", name="Agree and proceed with standard settings" - ) - cookies_button.click() - - # Wait for login form and use it - page.wait_for_selector('//h1[text()="Log in to your Red Hat account"]') - input_user = page.locator('//input[@id="username-verification"]') - time.sleep(1) - input_user.fill(username) - button_next = page.locator('//button[@id="login-show-step2"]') - button_next.click() - button_next.wait_for(state="hidden") - input_pass = page.locator('//input[@id="password"]') - input_pass.wait_for(state="visible") - input_pass.fill(password) - page.locator('//button[@id="rh-password-verification-submit-button"]').click() - - # Wait for console and go to Konflux page - page.wait_for_url("https://console.dev.redhat.com/**") - page.wait_for_selector('//h2[text()="Welcome to your Hybrid Cloud Console."]') + playwright_lib.form_login(page, username, password) + + # Go to Konflux page.goto("https://console.dev.redhat.com/preview/application-pipeline") # Accept terms and conditions if this appears diff --git a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py index 9614c7560..afd146414 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py +++ b/tests/load-tests/ci-scripts/utility_scripts/playwright-update-tokens.py @@ -52,12 +52,7 @@ def workload(user): playwright_lib.goto_login_and_accept_cookies(page) - # Accept cookies - cookies_iframe = page.frame_locator('iframe[name="trustarc_cm"]') - cookies_button = cookies_iframe.get_by_role( - "button", name="Agree and proceed with standard settings" - ) - cookies_button.click() + playwright_lib.form_login(page, username, password) # Go to OpenShift Token page page.goto("https://console.dev.redhat.com/openshift/token") From ff392e2ea1f0534f772e426d64511b418fd8d43f Mon Sep 17 00:00:00 2001 From: Jan Hutar Date: Tue, 30 Jul 2024 16:22:20 +0200 Subject: [PATCH 6/6] feat: Make the script to also dump conditions fequecy to CSV files --- .../utility_scripts/show-pipelineruns.py | 74 ++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/tests/load-tests/ci-scripts/utility_scripts/show-pipelineruns.py b/tests/load-tests/ci-scripts/utility_scripts/show-pipelineruns.py index 105c25bd7..a15d8c61b 100755 --- a/tests/load-tests/ci-scripts/utility_scripts/show-pipelineruns.py +++ b/tests/load-tests/ci-scripts/utility_scripts/show-pipelineruns.py @@ -14,6 +14,7 @@ import yaml import time import re +import csv import matplotlib.pyplot import matplotlib.colors @@ -65,7 +66,6 @@ def __init__(self, data_dir): self.data_pipelineruns = {} self.data_taskruns = [] self.data_pods = [] - self.data_taskruns = [] self.data_dir = data_dir self.pr_lanes = [] @@ -79,12 +79,15 @@ def __init__(self, data_dir): self.pod_skips = 0 # how many Pods we skipped self.pr_duration = datetime.timedelta(0) # total time of all PipelineRuns self.tr_duration = datetime.timedelta(0) # total time of all TaskRuns + self.pod_duration = datetime.timedelta(0) # total time of all Pods running + self.pod_pending_duration = datetime.timedelta(0) # total time of all Pods pending self.pr_idle_duration = datetime.timedelta( 0 ) # total time in PipelineRuns when no TaskRun was running self.pr_conditions = collections.defaultdict(lambda: 0) self.tr_conditions = collections.defaultdict(lambda: 0) self.tr_statuses = collections.defaultdict(lambda: 0) + self.pod_conditions = collections.defaultdict(lambda: 0) self._populate(self.data_dir) self._merge_taskruns() @@ -147,6 +150,10 @@ def _merge_pods(self): "node_name" ] + self.data_pipelineruns[pod["pipelinerun"]]["taskRuns"][pod["task"]]["pod_start_time"] = pod["start_time"] + self.data_pipelineruns[pod["pipelinerun"]]["taskRuns"][pod["task"]]["pod_creation_timestamp"] = pod["creation_timestamp"] + self.data_pipelineruns[pod["pipelinerun"]]["taskRuns"][pod["task"]]["pod_finished_time"] = pod["finished_time"] + self.data_pods = [] def _populate(self, data_dir): @@ -347,19 +354,66 @@ def _populate_pod(self, pod): self.pod_skips += 1 return + try: + pod_creation_timestamp = pod["metadata"]["creationTimestamp"] + except KeyError as e: + logging.info(f"Pod {pod_name} missing creationTimestamp, skipping: {e}") + self.pod_skips += 1 + return + + try: + pod_start_time = pod["status"]["startTime"] + except KeyError as e: + logging.info(f"Pod {pod_name} missing startTime, skipping: {e}") + self.pod_skips += 1 + return + + try: + pod_finished_time = None + for container in pod["status"]["containerStatuses"]: + if pod_finished_time is None: + pod_finished_time = container["state"]["terminated"]["finishedAt"] + elif pod_finished_time < container["state"]["terminated"]["finishedAt"]: + pod_finished_time = container["state"]["terminated"]["finishedAt"] + except KeyError as e: + logging.info(f"Pod {pod_name} missing finishedAt timestamp for container, skipping: {e}") + self.pod_skips += 1 + return + + try: + pod_conditions = pod["status"]["conditions"] + except KeyError as e: + logging.info(f"Pod {pod_name} missing conditions, skipping: {e}") + self.pod_skips += 1 + return + self.data_pods.append( { "name": pod_name, "pipelinerun": pod_pipelinerun, "task": pod_task, "node_name": pod_node_name, + "creation_timestamp": pod_creation_timestamp, + "start_time": pod_start_time, + "finished_time": pod_finished_time, } ) + for condition in pod_conditions: + c_type = condition["type"] + c_status = condition["status"] + c_reason = condition["reason"] if "reason" in condition else None + self.pod_conditions[f"{c_type} / {c_status} / {c_reason}"] += 1 + def _dump_json(self, data, path): with open(path, "w") as fp: json.dump(data, fp, cls=DateTimeEncoder, sort_keys=True, indent=4) + def _dump_csv(self, data, path): + with open(path, "w") as fp: + writer = csv.writer(fp) + writer.writerows(data) + def _load_json(self, path): with open(path, "r") as fp: return json.load(fp, cls=DateTimeDecoder) @@ -474,6 +528,7 @@ def add_time_interval(existing, new): for i in self.data_pipelineruns.values() ] ) + tr_without_pod_times = 0 for pr_name, pr_times in self.data_pipelineruns.items(): pr_duration = pr_times[end] - pr_times[start] @@ -484,6 +539,11 @@ def add_time_interval(existing, new): for tr_name, tr_times in pr_times["taskRuns"].items(): self.tr_duration += tr_times[end] - tr_times[start] add_time_interval(trs, tr_times) + if "pod_finished_time" in tr_times and "pod_start_time" in tr_times and "pod_creation_timestamp" in tr_times: + self.pod_duration += tr_times["pod_finished_time"] - tr_times["pod_start_time"] + self.pod_pending_duration += tr_times["pod_start_time"] - tr_times["pod_creation_timestamp"] + else: + tr_without_pod_times += 1 # Combine new intervals so they do not overlap trs_no_overlap = [] @@ -504,7 +564,7 @@ def add_time_interval(existing, new): f"There was {self.pr_count} PipelineRuns and {self.tr_count} TaskRuns and {self.pod_count} Pods." ) print( - f"In total PipelineRuns took {self.pr_duration} and TaskRuns took {self.tr_duration}, PipelineRuns were idle for {self.pr_idle_duration}" + f"In total PipelineRuns took {self.pr_duration} and TaskRuns took {self.tr_duration}, Pods were pending for {self.pod_pending_duration} and running for {self.pod_duration} (having {tr_without_pod_times} TRs without pod times), PipelineRuns were idle for {self.pr_idle_duration}" ) pr_duration_avg = ( (self.pr_duration / self.pr_count).total_seconds() @@ -613,6 +673,7 @@ def _show_pr_tr_conditions(self): headers=["Condition message", "Count"], ) ) + self._dump_csv([["Condition message", "Count"]] + list(self.pr_conditions.items()), os.path.join(self.data_dir, "show-pipelineruns-pipelinerun-conditions.csv")) print("\nTaskRuns conditions frequency") print( tabulate.tabulate( @@ -620,6 +681,7 @@ def _show_pr_tr_conditions(self): headers=["Condition message", "Count"], ) ) + self._dump_csv([["Condition message", "Count"]] + list(self.tr_conditions.items()), os.path.join(self.data_dir, "show-pipelineruns-taskrun-conditions.csv")) print("\nTaskRuns status messages frequency") print( tabulate.tabulate( @@ -627,6 +689,14 @@ def _show_pr_tr_conditions(self): headers=["Status message", "Count"], ) ) + print("\nPods conditions frequency") + print( + tabulate.tabulate( + self.pod_conditions.items(), + headers=["Condition description", "Count"], + ) + ) + self._dump_csv([["Condition description", "Count"]] + list(self.pod_conditions.items()), os.path.join(self.data_dir, "show-pipelineruns-pod-conditions.csv")) def _plot_graph(self): """