diff --git a/tests/AutoscalingTests/common.py b/tests/AutoscalingTests/common.py index b178d0c102..47985d34d2 100644 --- a/tests/AutoscalingTests/common.py +++ b/tests/AutoscalingTests/common.py @@ -1,17 +1,18 @@ -import unittest -import random -import time -import subprocess -import signal import concurrent.futures import csv import os +import random +import signal +import subprocess +import time +import unittest + +from csv2md.table import Table from selenium import webdriver -from selenium.webdriver.firefox.options import Options as FirefoxOptions -from selenium.webdriver.edge.options import Options as EdgeOptions from selenium.webdriver.chrome.options import Options as ChromeOptions +from selenium.webdriver.edge.options import Options as EdgeOptions +from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.remote.client_config import ClientConfig -from csv2md.table import Table BROWSER = { "chrome": ChromeOptions(), @@ -27,16 +28,32 @@ timeout=3600, ) -FIELD_NAMES = ["Iteration", "New request sessions", "Sessions created time", "Sessions failed to create", "New pods scaled up", "Total running sessions", "Total running pods", "Max sessions per pod", "Gaps", "Sessions closed"] +FIELD_NAMES = [ + "Iteration", + "New request sessions", + "Sessions created time", + "Sessions failed to create", + "New pods scaled up", + "Total running sessions", + "Total running pods", + "Max sessions per pod", + "Gaps", + "Sessions closed", +] + def get_pod_count(): result = subprocess.run(["kubectl", "get", "pods", "-A", "--no-headers"], capture_output=True, text=True) return len([line for line in result.stdout.splitlines() if "selenium-node-" in line and "Running" in line]) + def create_session(browser_name): options = BROWSER[browser_name] options.set_capability("platformName", "Linux") - return webdriver.Remote(command_executor=CLIENT_CONFIG.remote_server_addr, options=options, client_config=CLIENT_CONFIG) + return webdriver.Remote( + command_executor=CLIENT_CONFIG.remote_server_addr, options=options, client_config=CLIENT_CONFIG + ) + def wait_for_count_matches(sessions, timeout=10, interval=5): elapsed = 0 @@ -48,20 +65,26 @@ def wait_for_count_matches(sessions, timeout=10, interval=5): time.sleep(interval) elapsed += interval if pod_count != len(sessions): - print(f"WARN: Mismatch between pod count and session count after {timeout} seconds. Gaps: {pod_count - len(sessions)}") + print( + f"WARN: Mismatch between pod count and session count after {timeout} seconds. Gaps: {pod_count - len(sessions)}" + ) else: print(f"PASS: Pod count matches session count after {elapsed} seconds.") + def close_all_sessions(sessions): for session in sessions: session.quit() sessions.clear() return sessions + def create_sessions_in_parallel(new_request_sessions): failed_jobs = 0 with concurrent.futures.ThreadPoolExecutor() as executor: - futures = [executor.submit(create_session, random.choice(list(BROWSER.keys()))) for _ in range(new_request_sessions)] + futures = [ + executor.submit(create_session, random.choice(list(BROWSER.keys()))) for _ in range(new_request_sessions) + ] sessions = [] for future in concurrent.futures.as_completed(futures): try: @@ -72,6 +95,7 @@ def create_sessions_in_parallel(new_request_sessions): print(f"Total failed jobs: {failed_jobs}") return sessions + def randomly_quit_sessions(sessions, sublist_size): if sessions: sessions_to_quit = random.sample(sessions, min(sublist_size, len(sessions))) @@ -82,15 +106,18 @@ def randomly_quit_sessions(sessions, sublist_size): return len(sessions_to_quit) return 0 + def get_result_file_name(): return f"tests/autoscaling_results" + def export_results_to_csv(output_file, field_names, results): with open(output_file, mode="w") as csvfile: writer = csv.DictWriter(csvfile, fieldnames=field_names) writer.writeheader() writer.writerows(results) + def export_results_csv_to_md(csv_file, md_file): with open(csv_file) as f: table = Table.parse_csv(f) diff --git a/tests/AutoscalingTests/test_scale_chaos.py b/tests/AutoscalingTests/test_scale_chaos.py index c28d488839..0ce89051e8 100644 --- a/tests/AutoscalingTests/test_scale_chaos.py +++ b/tests/AutoscalingTests/test_scale_chaos.py @@ -1,9 +1,11 @@ -import unittest +import csv import random -import time import signal -import csv +import time +import unittest + from csv2md.table import Table + from .common import * SESSIONS = [] @@ -11,13 +13,16 @@ TEST_NODE_MAX_SESSIONS = int(os.getenv("TEST_NODE_MAX_SESSIONS", 1)) TEST_AUTOSCALING_ITERATIONS = int(os.getenv("TEST_AUTOSCALING_ITERATIONS", 20)) + def signal_handler(signum, frame): print("Signal received, quitting all sessions...") close_all_sessions(SESSIONS) + signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGINT, signal_handler) + class SeleniumAutoscalingTests(unittest.TestCase): def test_run_tests(self): try: @@ -38,18 +43,20 @@ def test_run_tests(self): print(f"INFO: Total sessions: {total_sessions}") print(f"INFO: Total pods: {total_pods}") closed_session = randomly_quit_sessions(SESSIONS, random.randint(3, 12)) - RESULTS.append({ - FIELD_NAMES[0]: iteration + 1, - FIELD_NAMES[1]: new_request_sessions, - FIELD_NAMES[2]: f"{elapsed_time:.2f} s", - FIELD_NAMES[3]: failed_sessions, - FIELD_NAMES[4]: new_scaled_pods, - FIELD_NAMES[5]: total_sessions, - FIELD_NAMES[6]: total_pods, - FIELD_NAMES[7]: TEST_NODE_MAX_SESSIONS, - FIELD_NAMES[8]: (total_pods * TEST_NODE_MAX_SESSIONS) - total_sessions, - FIELD_NAMES[9]: closed_session, - }) + RESULTS.append( + { + FIELD_NAMES[0]: iteration + 1, + FIELD_NAMES[1]: new_request_sessions, + FIELD_NAMES[2]: f"{elapsed_time:.2f} s", + FIELD_NAMES[3]: failed_sessions, + FIELD_NAMES[4]: new_scaled_pods, + FIELD_NAMES[5]: total_sessions, + FIELD_NAMES[6]: total_pods, + FIELD_NAMES[7]: TEST_NODE_MAX_SESSIONS, + FIELD_NAMES[8]: (total_pods * TEST_NODE_MAX_SESSIONS) - total_sessions, + FIELD_NAMES[9]: closed_session, + } + ) time.sleep(15) finally: print(f"FINISH: Closing {len(SESSIONS)} sessions.") @@ -58,5 +65,6 @@ def test_run_tests(self): export_results_to_csv(f"{output_file}.csv", FIELD_NAMES, RESULTS) export_results_csv_to_md(f"{output_file}.csv", f"{output_file}.md") + if __name__ == "__main__": unittest.main() diff --git a/tests/AutoscalingTests/test_scale_up.py b/tests/AutoscalingTests/test_scale_up.py index ddad4a344d..d0dcfea896 100644 --- a/tests/AutoscalingTests/test_scale_up.py +++ b/tests/AutoscalingTests/test_scale_up.py @@ -1,9 +1,11 @@ -import unittest +import csv import random -import time import signal -import csv +import time +import unittest + from csv2md.table import Table + from .common import * SESSIONS = [] @@ -11,13 +13,16 @@ TEST_NODE_MAX_SESSIONS = int(os.getenv("TEST_NODE_MAX_SESSIONS", 1)) TEST_AUTOSCALING_ITERATIONS = int(os.getenv("TEST_AUTOSCALING_ITERATIONS", 20)) + def signal_handler(signum, frame): print("Signal received, quitting all sessions...") close_all_sessions(SESSIONS) + signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGINT, signal_handler) + class SeleniumAutoscalingTests(unittest.TestCase): def test_run_tests(self): try: @@ -41,18 +46,20 @@ def test_run_tests(self): closed_session = randomly_quit_sessions(SESSIONS, 20) else: closed_session = 0 - RESULTS.append({ - FIELD_NAMES[0]: iteration + 1, - FIELD_NAMES[1]: new_request_sessions, - FIELD_NAMES[2]: f"{elapsed_time:.2f} s", - FIELD_NAMES[3]: failed_sessions, - FIELD_NAMES[4]: new_scaled_pods, - FIELD_NAMES[5]: total_sessions, - FIELD_NAMES[6]: total_pods, - FIELD_NAMES[7]: TEST_NODE_MAX_SESSIONS, - FIELD_NAMES[8]: (total_pods * TEST_NODE_MAX_SESSIONS) - total_sessions, - FIELD_NAMES[9]: closed_session, - }) + RESULTS.append( + { + FIELD_NAMES[0]: iteration + 1, + FIELD_NAMES[1]: new_request_sessions, + FIELD_NAMES[2]: f"{elapsed_time:.2f} s", + FIELD_NAMES[3]: failed_sessions, + FIELD_NAMES[4]: new_scaled_pods, + FIELD_NAMES[5]: total_sessions, + FIELD_NAMES[6]: total_pods, + FIELD_NAMES[7]: TEST_NODE_MAX_SESSIONS, + FIELD_NAMES[8]: (total_pods * TEST_NODE_MAX_SESSIONS) - total_sessions, + FIELD_NAMES[9]: closed_session, + } + ) time.sleep(15) finally: print(f"FINISH: Closing {len(SESSIONS)} sessions.") @@ -61,5 +68,6 @@ def test_run_tests(self): export_results_to_csv(f"{output_file}.csv", FIELD_NAMES, RESULTS) export_results_csv_to_md(f"{output_file}.csv", f"{output_file}.md") + if __name__ == "__main__": unittest.main() diff --git a/tests/SeleniumTests/__init__.py b/tests/SeleniumTests/__init__.py index 2802d1fee9..4e117b3519 100644 --- a/tests/SeleniumTests/__init__.py +++ b/tests/SeleniumTests/__init__.py @@ -1,17 +1,18 @@ -import unittest import concurrent.futures import os -import traceback -import time import random +import time +import traceback +import unittest + from selenium import webdriver +from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.edge.options import Options as EdgeOptions -from selenium.webdriver.chrome.options import Options as ChromeOptions +from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.remote.client_config import ClientConfig +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait SELENIUM_GRID_PROTOCOL = os.environ.get('SELENIUM_GRID_PROTOCOL', 'http') SELENIUM_GRID_HOST = os.environ.get('SELENIUM_GRID_HOST', 'localhost') @@ -40,8 +41,8 @@ LIST_PLATFORMS = ['Linux', None, 'Windows 11'] if not TEST_MULTIPLE_VERSIONS_EXPLICIT: - LIST_CHROMIUM_VERSIONS.append(None) - LIST_FIREFOX_VERSIONS.append(None) + LIST_CHROMIUM_VERSIONS.append(None) + LIST_FIREFOX_VERSIONS.append(None) if TEST_MULTIPLE_PLATFORMS_RELAY: # Replace index with None to macOS @@ -60,6 +61,7 @@ if TEST_NODE_RELAY == 'Android': time.sleep(90) + class SeleniumGenericTests(unittest.TestCase): def test_title(self): @@ -73,12 +75,8 @@ def test_with_frames(self): driver = self.driver driver.get('http://the-internet.herokuapp.com/nested_frames') wait = WebDriverWait(driver, WEB_DRIVER_WAIT_TIMEOUT) - frame_top = wait.until( - EC.frame_to_be_available_and_switch_to_it('frame-top') - ) - frame_middle = wait.until( - EC.frame_to_be_available_and_switch_to_it('frame-middle') - ) + frame_top = wait.until(EC.frame_to_be_available_and_switch_to_it('frame-top')) + frame_middle = wait.until(EC.frame_to_be_available_and_switch_to_it('frame-middle')) self.assertTrue(driver.find_element(By.ID, 'content').text == "MIDDLE", "content should be MIDDLE") # https://github.com/tourdedave/elemental-selenium-tips/blob/master/05-select-from-a-dropdown/python/dropdown.py @@ -108,17 +106,11 @@ def test_play_video(self): driver = self.driver driver.get('https://googleads.github.io/googleads-ima-html5/vsi/') wait = WebDriverWait(driver, WEB_DRIVER_WAIT_TIMEOUT) - play_button = wait.until( - EC.element_to_be_clickable((By.ID, 'play-button')) - ) + play_button = wait.until(EC.element_to_be_clickable((By.ID, 'play-button'))) play_button.click() video = driver.find_element(By.TAG_NAME, 'video') - wait.until( - lambda d: d.find_element(By.TAG_NAME, 'video').get_property('currentTime') - ) - wait.until( - lambda d: d.find_element(By.TAG_NAME, 'video').get_property('paused') == False - ) + wait.until(lambda d: d.find_element(By.TAG_NAME, 'video').get_property('currentTime')) + wait.until(lambda d: d.find_element(By.TAG_NAME, 'video').get_property('paused') == False) paused = video.get_property('paused') self.assertFalse(paused) @@ -127,17 +119,13 @@ def test_download_file(self): driver.get('https://the-internet.herokuapp.com/download') file_name = 'some-file.txt' wait = WebDriverWait(driver, 30) - file_link = wait.until( - EC.element_to_be_clickable((By.LINK_TEXT, file_name)) - ) + file_link = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, file_name))) driver.execute_script("arguments[0].scrollIntoView();", file_link) file_link.click() if not SELENIUM_ENABLE_MANAGED_DOWNLOADS: time.sleep(4) return - wait.until( - lambda d: str(d.get_downloadable_files()[0]).endswith(file_name) - ) + wait.until(lambda d: str(d.get_downloadable_files()[0]).endswith(file_name)) self.assertTrue(str(driver.get_downloadable_files()[0]).endswith(file_name)) def tearDown(self): @@ -191,25 +179,29 @@ def setUp(self): if platform_name: options.set_capability('platformName', platform_name) if TEST_MULTIPLE_PLATFORMS_RELAY: - options.set_capability('sauce:options', { - 'username': os.environ.get('SAUCE_USERNAME'), - 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), - 'name': f"{self._testMethodName} ({self.__class__.__name__})", - 'seleniumVersion': '4.29.0', - }) + options.set_capability( + 'sauce:options', + { + 'username': os.environ.get('SAUCE_USERNAME'), + 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), + 'name': f"{self._testMethodName} ({self.__class__.__name__})", + 'seleniumVersion': '4.29.0', + }, + ) start_time = time.time() self.driver = webdriver.Remote( - options=options, - command_executor=SELENIUM_GRID_URL, - client_config=CLIENT_CONFIG + options=options, command_executor=SELENIUM_GRID_URL, client_config=CLIENT_CONFIG ) end_time = time.time() - print(f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)") + print( + f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)" + ) except Exception as e: print(f"::error::Exception: {str(e)}") print(traceback.format_exc()) raise e + class EdgeTests(SeleniumGenericTests): def setUp(self): try: @@ -236,25 +228,29 @@ def setUp(self): if platform_name: options.set_capability('platformName', platform_name) if TEST_MULTIPLE_PLATFORMS_RELAY: - options.set_capability('sauce:options', { - 'username': os.environ.get('SAUCE_USERNAME'), - 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), - 'name': f"{self._testMethodName} ({self.__class__.__name__})", - 'seleniumVersion': '4.29.0', - }) + options.set_capability( + 'sauce:options', + { + 'username': os.environ.get('SAUCE_USERNAME'), + 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), + 'name': f"{self._testMethodName} ({self.__class__.__name__})", + 'seleniumVersion': '4.29.0', + }, + ) start_time = time.time() self.driver = webdriver.Remote( - options=options, - command_executor=SELENIUM_GRID_URL, - client_config=CLIENT_CONFIG + options=options, command_executor=SELENIUM_GRID_URL, client_config=CLIENT_CONFIG ) end_time = time.time() - print(f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)") + print( + f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)" + ) except Exception as e: print(f"::error::Exception: {str(e)}") print(traceback.format_exc()) raise e + class FirefoxTests(SeleniumGenericTests): def setUp(self): try: @@ -286,20 +282,23 @@ def setUp(self): if platform_name: options.set_capability('platformName', platform_name) if TEST_MULTIPLE_PLATFORMS_RELAY: - options.set_capability('sauce:options', { - 'username': os.environ.get('SAUCE_USERNAME'), - 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), - 'name': f"{self._testMethodName} ({self.__class__.__name__})", - 'seleniumVersion': '4.29.0', - }) + options.set_capability( + 'sauce:options', + { + 'username': os.environ.get('SAUCE_USERNAME'), + 'accessKey': os.environ.get('SAUCE_ACCESS_KEY'), + 'name': f"{self._testMethodName} ({self.__class__.__name__})", + 'seleniumVersion': '4.29.0', + }, + ) start_time = time.time() self.driver = webdriver.Remote( - options=options, - command_executor=SELENIUM_GRID_URL, - client_config=CLIENT_CONFIG + options=options, command_executor=SELENIUM_GRID_URL, client_config=CLIENT_CONFIG ) end_time = time.time() - print(f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)") + print( + f"Begin: {self._testMethodName} ({self.__class__.__name__}) WebDriver initialization completed in {end_time - start_time} (s)" + ) except Exception as e: print(f"::error::Exception: {str(e)}") print(traceback.format_exc()) @@ -312,19 +311,20 @@ def test_title_and_maximize_window(self): def test_accept_languages(self): if TEST_FIREFOX_INSTALL_LANG_PACKAGE: - addon_id = webdriver.Firefox.install_addon(self.driver, "./target/firefox_lang_packs/langpack-vi@firefox.mozilla.org.xpi") + addon_id = webdriver.Firefox.install_addon( + self.driver, "./target/firefox_lang_packs/langpack-vi@firefox.mozilla.org.xpi" + ) self.driver.get('https://gtranslate.io/detect-browser-language') wait = WebDriverWait(self.driver, WEB_DRIVER_WAIT_TIMEOUT) - lang_code = wait.until( - EC.presence_of_element_located((By.XPATH, '(//*[@class="notranslate"])[1]')) - ) + lang_code = wait.until(EC.presence_of_element_located((By.XPATH, '(//*[@class="notranslate"])[1]'))) self.driver.execute_script("arguments[0].scrollIntoView();", lang_code) self.assertTrue(lang_code.text == 'vi-VN', "Language code should be vi-VN") time.sleep(1) self.driver.get('https://google.com') time.sleep(2) -class Autoscaling(): + +class Autoscaling: def run(self, test_classes): with concurrent.futures.ThreadPoolExecutor() as executor: futures = [] @@ -367,6 +367,7 @@ def run(self, test_classes): raise Exception(f"Rerun test failed: {str(test)} failed with exception: {str(e)}") print(f"::warning:: Number of failed tests: {len(failed_tests)}. All tests passed in rerun!") + class DeploymentAutoscalingTests(unittest.TestCase): def test_parallel_autoscaling(self): runner = Autoscaling() @@ -376,6 +377,7 @@ def test_parallel_autoscaling(self): else: runner.run(platform.add_test_based_platform(TEST_PARALLEL_COUNT)) + class JobAutoscalingTests(unittest.TestCase): def test_parallel_autoscaling(self): runner = Autoscaling() @@ -385,6 +387,7 @@ def test_parallel_autoscaling(self): else: runner.run(platform.add_test_based_platform(TEST_PARALLEL_COUNT)) + class TestPlatform: def add_test_based_platform(self, repeat): tests = [] diff --git a/tests/SmokeTests/__init__.py b/tests/SmokeTests/__init__.py index e7a11b1276..118cad9a81 100644 --- a/tests/SmokeTests/__init__.py +++ b/tests/SmokeTests/__init__.py @@ -1,8 +1,9 @@ -import os -import unittest -import time import json +import os import ssl +import time +import unittest + import requests from requests.auth import HTTPBasicAuth @@ -18,7 +19,8 @@ HUB_CHECKS_INTERVAL = os.environ.get('HUB_CHECKS_INTERVAL', 10) if CHART_CERT_PATH: - os.environ['REQUESTS_CA_BUNDLE'] = CHART_CERT_PATH + os.environ['REQUESTS_CA_BUNDLE'] = CHART_CERT_PATH + class SmokeTests(unittest.TestCase): def smoke_test_container(self, port): @@ -35,14 +37,18 @@ def smoke_test_container(self, port): try: grid_url_status = f'{SELENIUM_GRID_PROTOCOL}://{SELENIUM_GRID_HOST}:{port}/status' if SELENIUM_GRID_USERNAME and SELENIUM_GRID_PASSWORD: - response = requests.get(grid_url_status, auth=HTTPBasicAuth(SELENIUM_GRID_USERNAME, SELENIUM_GRID_PASSWORD)) + response = requests.get( + grid_url_status, auth=HTTPBasicAuth(SELENIUM_GRID_USERNAME, SELENIUM_GRID_PASSWORD) + ) else: response = requests.get(grid_url_status) status_json = response.json() if not auto_scaling or (auto_scaling and auto_scaling_min_replica > 0): self.assertTrue(status_json['value']['ready'], "Container is not ready on port %s" % port) else: - self.assertFalse(status_json['value']['ready'], "Container is autoscaling with min replica set to 0") + self.assertFalse( + status_json['value']['ready'], "Container is autoscaling with min replica set to 0" + ) status_fetched = True except Exception as e: time.sleep(sleep_interval) @@ -53,11 +59,13 @@ def smoke_test_container(self, port): else: self.assertFalse(status_json['value']['ready'], "Container is autoscaling with min replica set to 0") - def client_verify_cert(self, port): grid_url_status = f'{SELENIUM_GRID_PROTOCOL}://{SELENIUM_GRID_HOST}:{port}/status' cert_path = os.environ.get("REQUESTS_CA_BUNDLE") - response = requests.get(grid_url_status, verify=cert_path, auth=HTTPBasicAuth(SELENIUM_GRID_USERNAME, SELENIUM_GRID_PASSWORD)) + response = requests.get( + grid_url_status, verify=cert_path, auth=HTTPBasicAuth(SELENIUM_GRID_USERNAME, SELENIUM_GRID_PASSWORD) + ) + class GridTest(SmokeTests): def test_grid_is_up(self): diff --git a/tests/build-backward-compatible/builder.py b/tests/build-backward-compatible/builder.py index f4695e5a6a..511fed559e 100755 --- a/tests/build-backward-compatible/builder.py +++ b/tests/build-backward-compatible/builder.py @@ -1,10 +1,12 @@ -import yaml -import sys import logging +import sys + +import yaml logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) + def load_template(yaml_file): try: with open(yaml_file) as file: @@ -13,6 +15,7 @@ def load_template(yaml_file): except yaml.YAMLError as error: logger.debug("Error in configuration file: ", error) + def recursive_merge(dict1, dict2): for key in dict2: if key in dict1 and isinstance(dict1[key], dict) and isinstance(dict2[key], dict): @@ -20,6 +23,7 @@ def recursive_merge(dict1, dict2): else: dict1[key] = dict2[key] + if __name__ == '__main__': # Load matrix configuration selenium_matrix = load_template('tests/build-backward-compatible/selenium-matrix.yml') @@ -33,28 +37,28 @@ def recursive_merge(dict1, dict2): browser_name = sys.argv[3] # Create .env with component versions with open('.env', 'w') as f: - BASE_RELEASE = matrix["selenium"][selenium_version]["BASE_RELEASE"] - BASE_VERSION = matrix["selenium"][selenium_version]["BASE_VERSION"] - VERSION = matrix["selenium"][selenium_version]["VERSION"] - BINDING_VERSION = matrix["selenium"][selenium_version]["BINDING_VERSION"] - f.write(f"BASE_RELEASE={BASE_RELEASE}\n") - f.write(f"BASE_VERSION={BASE_VERSION}\n") - f.write(f"VERSION={VERSION}\n") - f.write(f"BINDING_VERSION={BINDING_VERSION}\n") - if browser_name == "firefox" or browser_name == "all": - FIREFOX_VERSION = matrix["browser"][browser_version]["FIREFOX_VERSION"] - f.write(f"FIREFOX_VERSION={FIREFOX_VERSION}\n") - if "FIREFOX_DOWNLOAD_URL" in matrix["browser"][browser_version]: - FIREFOX_DOWNLOAD_URL = matrix["browser"][browser_version]["FIREFOX_DOWNLOAD_URL"] - f.write(f"FIREFOX_DOWNLOAD_URL={FIREFOX_DOWNLOAD_URL}\n") - if "FIREFOX_PLATFORMS" in matrix["browser"][browser_version]: - FIREFOX_PLATFORMS = matrix["browser"][browser_version]["FIREFOX_PLATFORMS"] - f.write(f"PLATFORMS={FIREFOX_PLATFORMS}\n") - else: - f.write(f"PLATFORMS=linux/amd64\n") - if browser_name == "edge" or browser_name == "all": - EDGE_VERSION = matrix["browser"][browser_version]["EDGE_VERSION"] - f.write(f"EDGE_VERSION={EDGE_VERSION}\n") - if browser_name == "chrome" or browser_name == "all": - CHROME_VERSION = matrix["browser"][browser_version]["CHROME_VERSION"] - f.write(f"CHROME_VERSION={CHROME_VERSION}") + BASE_RELEASE = matrix["selenium"][selenium_version]["BASE_RELEASE"] + BASE_VERSION = matrix["selenium"][selenium_version]["BASE_VERSION"] + VERSION = matrix["selenium"][selenium_version]["VERSION"] + BINDING_VERSION = matrix["selenium"][selenium_version]["BINDING_VERSION"] + f.write(f"BASE_RELEASE={BASE_RELEASE}\n") + f.write(f"BASE_VERSION={BASE_VERSION}\n") + f.write(f"VERSION={VERSION}\n") + f.write(f"BINDING_VERSION={BINDING_VERSION}\n") + if browser_name == "firefox" or browser_name == "all": + FIREFOX_VERSION = matrix["browser"][browser_version]["FIREFOX_VERSION"] + f.write(f"FIREFOX_VERSION={FIREFOX_VERSION}\n") + if "FIREFOX_DOWNLOAD_URL" in matrix["browser"][browser_version]: + FIREFOX_DOWNLOAD_URL = matrix["browser"][browser_version]["FIREFOX_DOWNLOAD_URL"] + f.write(f"FIREFOX_DOWNLOAD_URL={FIREFOX_DOWNLOAD_URL}\n") + if "FIREFOX_PLATFORMS" in matrix["browser"][browser_version]: + FIREFOX_PLATFORMS = matrix["browser"][browser_version]["FIREFOX_PLATFORMS"] + f.write(f"PLATFORMS={FIREFOX_PLATFORMS}\n") + else: + f.write(f"PLATFORMS=linux/amd64\n") + if browser_name == "edge" or browser_name == "all": + EDGE_VERSION = matrix["browser"][browser_version]["EDGE_VERSION"] + f.write(f"EDGE_VERSION={EDGE_VERSION}\n") + if browser_name == "chrome" or browser_name == "all": + CHROME_VERSION = matrix["browser"][browser_version]["CHROME_VERSION"] + f.write(f"CHROME_VERSION={CHROME_VERSION}") diff --git a/tests/build-backward-compatible/fetch_firefox_version.py b/tests/build-backward-compatible/fetch_firefox_version.py index fb5a9df0ef..5e36fd2100 100644 --- a/tests/build-backward-compatible/fetch_firefox_version.py +++ b/tests/build-backward-compatible/fetch_firefox_version.py @@ -1,10 +1,12 @@ -import requests import re -import yaml from collections import defaultdict +import requests +import yaml + local_file = 'tests/build-backward-compatible/firefox-matrix.yml' + def fetch_firefox_versions(): url = 'https://ftp.mozilla.org/pub/firefox/releases/' resp = requests.get(url) @@ -30,4 +32,5 @@ def fetch_firefox_versions(): with open(local_file, 'w') as file: yaml.dump(yaml_struct, file, default_flow_style=False, sort_keys=False) + fetch_firefox_versions() diff --git a/tests/build-backward-compatible/fetch_version.py b/tests/build-backward-compatible/fetch_version.py index 3d36a6bff5..4b0703432d 100755 --- a/tests/build-backward-compatible/fetch_version.py +++ b/tests/build-backward-compatible/fetch_version.py @@ -1,6 +1,7 @@ +from collections import OrderedDict + import requests import yaml -from collections import OrderedDict # URLs of the source YAML files chrome_url = 'https://raw.githubusercontent.com/NDViet/google-chrome-stable/refs/heads/main/browser-matrix.yml' @@ -10,7 +11,8 @@ # Local YAML file to update local_file = 'tests/build-backward-compatible/browser-matrix.yml' -def fetch_yaml(url, local = False): + +def fetch_yaml(url, local=False): if not local: response = requests.get(url) response.raise_for_status() @@ -19,6 +21,7 @@ def fetch_yaml(url, local = False): with open(url, 'r') as f: return yaml.load(f, Loader=yaml.SafeLoader) + def merge_dicts(dict1, dict2): for key, value in dict2.items(): if key in dict1 and isinstance(dict1[key], dict) and isinstance(value, dict): @@ -26,6 +29,7 @@ def merge_dicts(dict1, dict2): elif key in dict1 and '_PACKAGE_' not in key: dict1[key] = value if value is not None else "" + def update_local_yaml(local_data, source_data): updated = False for version, details in source_data['matrix']['browser'].items(): @@ -38,6 +42,7 @@ def update_local_yaml(local_data, source_data): merge_dicts(original_details, details) return updated + def main(): # Fetch source YAML data chrome_data = fetch_yaml(chrome_url) @@ -61,5 +66,6 @@ def main(): else: print("No updates needed.") + if __name__ == '__main__': main() diff --git a/tests/charts/templates/test.py b/tests/charts/templates/test.py index c61448ec58..5fc92a80e2 100644 --- a/tests/charts/templates/test.py +++ b/tests/charts/templates/test.py @@ -1,12 +1,14 @@ -import yaml -import unittest -import sys -import logging import base64 +import logging +import sys +import unittest + +import yaml logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) + def load_template(yaml_file): try: with open(yaml_file) as file: @@ -16,22 +18,30 @@ def load_template(yaml_file): except yaml.YAMLError as error: print("Error in configuration file: ", error) + class ChartTemplateTests(unittest.TestCase): def test_set_affinity(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-distributor', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox', - f'{RELEASE_NAME}selenium-event-bus', - f'{RELEASE_NAME}selenium-router', - f'{RELEASE_NAME}selenium-session-map', - f'{RELEASE_NAME}selenium-session-queue'] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-distributor', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + f'{RELEASE_NAME}selenium-event-bus', + f'{RELEASE_NAME}selenium-router', + f'{RELEASE_NAME}selenium-session-map', + f'{RELEASE_NAME}selenium-session-queue', + ] count = 0 logger.info(f"Assert affinity is set in global and nodes") for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': logger.info(f"Assert affinity is set in resource {doc['metadata']['name']}") - self.assertTrue(doc['spec']['template']['spec']['affinity']['podAffinity']['requiredDuringSchedulingIgnoredDuringExecution'][0]['labelSelector']['matchExpressions'] is not None) + self.assertTrue( + doc['spec']['template']['spec']['affinity']['podAffinity'][ + 'requiredDuringSchedulingIgnoredDuringExecution' + ][0]['labelSelector']['matchExpressions'] + is not None + ) count += 1 self.assertEqual(count, len(resources_name), "Not all resources have affinity set") @@ -42,18 +52,28 @@ def test_ingress_nginx_annotations(self): if doc['metadata']['name'] in resources_name and doc['kind'] == 'Ingress': logger.info(f"Assert ingress ingress annotations") logger.info(f"Config `ingress.nginx.proxyTimeout` is able to be set a different value") - self.assertTrue(doc['metadata']['annotations']['nginx.ingress.kubernetes.io/proxy-read-timeout'] == '360') + self.assertTrue( + doc['metadata']['annotations']['nginx.ingress.kubernetes.io/proxy-read-timeout'] == '360' + ) logger.info(f"Duplicated in `ingress.annotations` take precedence to overwrite the default value") - self.assertTrue(doc['metadata']['annotations']['nginx.ingress.kubernetes.io/proxy-connect-timeout'] == '3600') + self.assertTrue( + doc['metadata']['annotations']['nginx.ingress.kubernetes.io/proxy-connect-timeout'] == '3600' + ) logger.info(f"Default annotation is able to be disabled by setting it to null") - self.assertTrue(doc['metadata']['annotations'].get('nginx.ingress.kubernetes.io/proxy-buffers-number') is None) + self.assertTrue( + doc['metadata']['annotations'].get('nginx.ingress.kubernetes.io/proxy-buffers-number') is None + ) logger.info(f"Default annotation is added if no override value") - self.assertTrue(doc['metadata']['annotations']['nginx.ingress.kubernetes.io/client-body-buffer-size'] == '512M') + self.assertTrue( + doc['metadata']['annotations']['nginx.ingress.kubernetes.io/client-body-buffer-size'] == '512M' + ) count += 1 self.assertEqual(count, len(resources_name), "No ingress resources found") def test_sub_path_append_to_node_grid_url_and_basic_auth_should_not_include(self): - resources_name = [f'{RELEASE_NAME}selenium-secrets',] + resources_name = [ + f'{RELEASE_NAME}selenium-secrets', + ] for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Secret': logger.info(f"Assert graphql url is constructed without basic auth in url") @@ -74,20 +94,26 @@ def test_sub_path_set_to_grid_env_var(self): self.assertTrue(is_present, "ENV variable SE_SUB_PATH is not populated") def test_graphql_url_for_autoscaling_constructed_without_basic_auth_in_url(self): - resources_name = [f'{RELEASE_NAME}selenium-secrets',] + resources_name = [ + f'{RELEASE_NAME}selenium-secrets', + ] for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Secret': logger.info(f"Assert graphql url is constructed without basic auth in url") base64_url = doc['data']['SE_NODE_GRID_GRAPHQL_URL'] decoded_url = base64.b64decode(base64_url).decode('utf-8') - self.assertTrue(decoded_url == f'https://{RELEASE_NAME}selenium-router.default:4444/selenium/graphql', decoded_url) + self.assertTrue( + decoded_url == f'https://{RELEASE_NAME}selenium-router.default:4444/selenium/graphql', decoded_url + ) def test_distributor_new_session_thread_pool_size(self): resources_name = [f'{RELEASE_NAME}selenium-distributor'] is_present = False for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': - logger.info(f"Assert newSessionThreadPoolSize is set to Distributor env SE_NEW_SESSION_THREAD_POOL_SIZE") + logger.info( + f"Assert newSessionThreadPoolSize is set to Distributor env SE_NEW_SESSION_THREAD_POOL_SIZE" + ) list_env = doc['spec']['template']['spec']['containers'][0]['env'] for env in list_env: if env['name'] == 'SE_NEW_SESSION_THREAD_POOL_SIZE' and env['value'] == '24': @@ -107,14 +133,16 @@ def test_disable_ui_set_to_grid_env_var(self): self.assertTrue(is_present, "ENV variable SE_DISABLE_UI is not populated") def test_log_level_set_to_logging_config_map(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-distributor', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox', - f'{RELEASE_NAME}selenium-event-bus', - f'{RELEASE_NAME}selenium-router', - f'{RELEASE_NAME}selenium-session-map', - f'{RELEASE_NAME}selenium-session-queue'] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-distributor', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + f'{RELEASE_NAME}selenium-event-bus', + f'{RELEASE_NAME}selenium-router', + f'{RELEASE_NAME}selenium-session-map', + f'{RELEASE_NAME}selenium-session-queue', + ] logger.info(f"Assert log level value is set to logging ConfigMap") count_config = 0 for doc in LIST_OF_DOCUMENTS: @@ -137,15 +165,20 @@ def test_log_level_set_to_logging_config_map(self): self.assertEqual(count, len(resources_name), "Logging ConfigMap is not present in expected resources") def test_node_port_set_when_service_type_is_node_port(self): - single_node_port = {f'{RELEASE_NAME}selenium-distributor': 30553, - f'{RELEASE_NAME}selenium-router': 30444, - f'{RELEASE_NAME}selenium-session-queue': 30559} + single_node_port = { + f'{RELEASE_NAME}selenium-distributor': 30553, + f'{RELEASE_NAME}selenium-router': 30444, + f'{RELEASE_NAME}selenium-session-queue': 30559, + } count = 0 logger.info(f"Assert NodePort is set to components service") for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in single_node_port.keys() and doc['kind'] == 'Service': logger.info(f"Assert NodePort is set to service {doc['metadata']['name']}") - self.assertTrue(doc['spec']['ports'][0]['nodePort'] == single_node_port[doc['metadata']['name']], f"Service {doc['metadata']['name']} with expect NodePort {single_node_port[doc['metadata']['name']]} is not found") + self.assertTrue( + doc['spec']['ports'][0]['nodePort'] == single_node_port[doc['metadata']['name']], + f"Service {doc['metadata']['name']} with expect NodePort {single_node_port[doc['metadata']['name']]} is not found", + ) count += 1 self.assertEqual(count, len(single_node_port.keys()), "Number of services with NodePort is not correct") @@ -154,8 +187,10 @@ def test_all_metadata_name_is_prefixed_with_release_name(self): prefix = "selenium-" if RELEASE_NAME == "" else RELEASE_NAME for doc in LIST_OF_DOCUMENTS: logger.info(f"Assert metadata name: {doc['metadata']['name']}") - self.assertTrue(doc['metadata']['name'].startswith(RELEASE_NAME), - f"Metadata name {doc['metadata']['name']} is not prefixed with RELEASE NAME: {RELEASE_NAME}") + self.assertTrue( + doc['metadata']['name'].startswith(RELEASE_NAME), + f"Metadata name {doc['metadata']['name']} is not prefixed with RELEASE NAME: {RELEASE_NAME}", + ) def test_extra_script_import_to_node_configmap(self): resources_name = [f'{RELEASE_NAME}selenium-node-config'] @@ -193,9 +228,11 @@ def test_extra_script_import_to_recorder_configmap(self): self.assertEqual(count, len(resources_name), "No recorder config resources found") def test_upload_conf_mount_to_video_container(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + ] is_present = False for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': @@ -222,24 +259,36 @@ def test_upload_conf_mount_to_video_container(self): self.assertTrue(is_present, "Volume mount for upload config is not present in the container") def test_terminationGracePeriodSeconds_in_deployment_autoscaling(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + ] count = 0 for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': logger.info(f"Assert terminationGracePeriodSeconds is set in resource {doc['metadata']['name']}") self.assertTrue(doc['spec']['template']['spec']['terminationGracePeriodSeconds'] == 7200) count += 1 - self.assertEqual(count, len(resources_name), "node.terminationGracePeriodSeconds doesn't override a higher value than autoscaling.terminationGracePeriodSeconds") + self.assertEqual( + count, + len(resources_name), + "node.terminationGracePeriodSeconds doesn't override a higher value than autoscaling.terminationGracePeriodSeconds", + ) - resources_name = [f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + ] count = 0 for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': logger.info(f"Assert terminationGracePeriodSeconds is set in resource {doc['metadata']['name']}") self.assertTrue(doc['spec']['template']['spec']['terminationGracePeriodSeconds'] == 3600) count += 1 - self.assertEqual(count, len(resources_name), "node.terminationGracePeriodSeconds doesn't inherit the global value autoscaling.terminationGracePeriodSeconds") + self.assertEqual( + count, + len(resources_name), + "node.terminationGracePeriodSeconds doesn't inherit the global value autoscaling.terminationGracePeriodSeconds", + ) def test_enable_leftovers_cleanup(self): resources_name = [f'{RELEASE_NAME}selenium-node-config'] @@ -265,43 +314,58 @@ def test_enable_tracing(self): self.assertEqual(count, len(resources_name), "No node config resources found") def test_update_strategy_in_all_components(self): - recreate = [f'{RELEASE_NAME}selenium-distributor', - f'{RELEASE_NAME}selenium-event-bus', - f'{RELEASE_NAME}selenium-router', - f'{RELEASE_NAME}selenium-session-map', - f'{RELEASE_NAME}selenium-session-queue', - f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox',] + recreate = [ + f'{RELEASE_NAME}selenium-distributor', + f'{RELEASE_NAME}selenium-event-bus', + f'{RELEASE_NAME}selenium-router', + f'{RELEASE_NAME}selenium-session-map', + f'{RELEASE_NAME}selenium-session-queue', + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + ] rolling = [] count_recreate = 0 count_rolling = 0 for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in rolling and doc['kind'] == 'Deployment': logger.info(f"Assert updateStrategy is set in resource {doc['metadata']['name']}") - self.assertTrue(doc['spec']['strategy']['type'] == 'RollingUpdate', f"Resource {doc['metadata']['name']} doesn't have strategy RollingUpdate") + self.assertTrue( + doc['spec']['strategy']['type'] == 'RollingUpdate', + f"Resource {doc['metadata']['name']} doesn't have strategy RollingUpdate", + ) count_rolling += 1 if doc['metadata']['name'] in recreate and doc['kind'] == 'Deployment': logger.info(f"Assert updateStrategy is set in resource {doc['metadata']['name']}") - self.assertTrue(doc['spec']['strategy']['type'] == 'Recreate', f"Resource {doc['metadata']['name']} doesn't have strategy Recreate") + self.assertTrue( + doc['spec']['strategy']['type'] == 'Recreate', + f"Resource {doc['metadata']['name']} doesn't have strategy Recreate", + ) count_recreate += 1 self.assertEqual(count_rolling, len(rolling), "No deployment resources found with strategy RollingUpdate") self.assertEqual(count_recreate, len(recreate), "No deployment resources found with strategy Recreate") def test_topologySpreadConstraints_in_all_components(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox', - f'{RELEASE_NAME}selenium-distributor', - f'{RELEASE_NAME}selenium-event-bus', - f'{RELEASE_NAME}selenium-router', - f'{RELEASE_NAME}selenium-session-map', - f'{RELEASE_NAME}selenium-session-queue',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + f'{RELEASE_NAME}selenium-distributor', + f'{RELEASE_NAME}selenium-event-bus', + f'{RELEASE_NAME}selenium-router', + f'{RELEASE_NAME}selenium-session-map', + f'{RELEASE_NAME}selenium-session-queue', + ] count = 0 for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': logger.info(f"Assert topologySpreadConstraints is set in resource {doc['metadata']['name']}") - self.assertTrue(doc['spec']['template']['spec']['topologySpreadConstraints'][0]['labelSelector']['matchLabels']['app'] == doc['metadata']['name']) + self.assertTrue( + doc['spec']['template']['spec']['topologySpreadConstraints'][0]['labelSelector']['matchLabels'][ + 'app' + ] + == doc['metadata']['name'] + ) count += 1 self.assertEqual(count, len(resources_name), "No deployment resources found with topologySpreadConstraints") @@ -315,18 +379,22 @@ def test_not_create_basic_auth_secret_when_nameOverride_is_set(self): self.assertEqual(count, 0, "Basic auth secret resource is created when nameOverride is set") def test_router_envFrom_secretRef_name_use_external_secret_when_basicAuth_nameOverride_is_set(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox', - f'{RELEASE_NAME}selenium-distributor', - f'{RELEASE_NAME}selenium-event-bus', - f'{RELEASE_NAME}selenium-router', - f'{RELEASE_NAME}selenium-session-map', - f'{RELEASE_NAME}selenium-session-queue',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + f'{RELEASE_NAME}selenium-distributor', + f'{RELEASE_NAME}selenium-event-bus', + f'{RELEASE_NAME}selenium-router', + f'{RELEASE_NAME}selenium-session-map', + f'{RELEASE_NAME}selenium-session-queue', + ] is_present = False for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': - logger.info(f"Assert envFrom secretRef name is set to external secret when basicAuth nameOverride is set") + logger.info( + f"Assert envFrom secretRef name is set to external secret when basicAuth nameOverride is set" + ) list_env_from = doc['spec']['template']['spec']['containers'][0]['envFrom'] for env in list_env_from: if env.get('secretRef') is not None: @@ -335,9 +403,11 @@ def test_router_envFrom_secretRef_name_use_external_secret_when_basicAuth_nameOv self.assertTrue(is_present, "ENV variable from secretRef name is not set to external secret") def test_scaler_triggers_authenticationRef_name_is_added(self): - resources_name = [f'{RELEASE_NAME}selenium-node-chrome', - f'{RELEASE_NAME}selenium-node-edge', - f'{RELEASE_NAME}selenium-node-firefox',] + resources_name = [ + f'{RELEASE_NAME}selenium-node-chrome', + f'{RELEASE_NAME}selenium-node-edge', + f'{RELEASE_NAME}selenium-node-firefox', + ] is_present = False for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] in resources_name and doc['kind'] == 'ScaledObject': @@ -346,25 +416,35 @@ def test_scaler_triggers_authenticationRef_name_is_added(self): self.assertTrue(name, f'{RELEASE_NAME}selenium-scaler-trigger-auth') def test_scaler_triggers_parameter_nodeMaxSessions_global_and_individual_value(self): - resources_name = {f'{RELEASE_NAME}selenium-node-chrome': 2, - f'{RELEASE_NAME}selenium-node-edge': 3, - f'{RELEASE_NAME}selenium-node-firefox': 1,} + resources_name = { + f'{RELEASE_NAME}selenium-node-chrome': 2, + f'{RELEASE_NAME}selenium-node-edge': 3, + f'{RELEASE_NAME}selenium-node-firefox': 1, + } count = 0 for resource_name in resources_name.keys(): for doc in LIST_OF_DOCUMENTS: if doc['metadata']['name'] == resource_name and doc['kind'] == 'ScaledObject': logger.info(f"Assert nodeMaxSessions parameter is set in scaler triggers") - self.assertTrue(doc['spec']['triggers'][0]['metadata']['nodeMaxSessions'] == str(resources_name[doc['metadata']['name']])) + self.assertTrue( + doc['spec']['triggers'][0]['metadata']['nodeMaxSessions'] + == str(resources_name[doc['metadata']['name']]) + ) if doc['metadata']['name'] == resource_name and doc['kind'] == 'Deployment': for env in doc['spec']['template']['spec']['containers'][0]['env']: if env['name'] == 'SE_NODE_MAX_SESSIONS': - self.assertTrue(env['value'] == str(resources_name[doc['metadata']['name']]), "Value is not matched") + self.assertTrue( + env['value'] == str(resources_name[doc['metadata']['name']]), "Value is not matched" + ) if env['name'] == 'SE_NODE_PLATFORM_NAME': self.assertTrue(env['value'] == "", "Platform name is not matched") if env['name'] == 'SE_NODE_BROWSER_VERSION': self.assertTrue(env['value'] == "", "Browser version is not matched") count += 1 - self.assertEqual(count, len(resources_name.keys()), f"Expected {len(resources_name.keys())} resources but found {count}") + self.assertEqual( + count, len(resources_name.keys()), f"Expected {len(resources_name.keys())} resources but found {count}" + ) + if __name__ == '__main__': failed = False diff --git a/tests/get_started.py b/tests/get_started.py index ab777c13ad..4fe4f9acb5 100644 --- a/tests/get_started.py +++ b/tests/get_started.py @@ -1,9 +1,10 @@ import sys import time + from selenium import webdriver from selenium.webdriver.chrome.options import Options as ChromeOptions -from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.edge.options import Options as EdgeOptions +from selenium.webdriver.firefox.options import Options as FirefoxOptions if len(sys.argv) < 2: print("Usage: python3 get_started.py [chrome|firefox|edge]") @@ -20,6 +21,7 @@ import concurrent.futures + def run_browser_instance(browser, grid_url): options = None if browser == "chrome": @@ -41,6 +43,7 @@ def run_browser_instance(browser, grid_url): time.sleep(100) driver.quit() + with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor: for _ in range(3): executor.submit(run_browser_instance, browser, GRID_URL) diff --git a/tests/test.py b/tests/test.py index eae35ae00b..f03c14a06e 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,35 +1,38 @@ import logging import os +import platform import random -import sys -import unittest import re -import platform import signal +import sys +import unittest import docker from docker.errors import NotFound + def clean_up(): - logger.info("Cleaning up...") + logger.info("Cleaning up...") + + test_container = client.containers.get(test_container_id) + test_container.kill() + test_container.remove() - test_container = client.containers.get(test_container_id) - test_container.kill() - test_container.remove() + if standalone: + logger.info("Standalone Cleaned up") + else: + # Kill the launched hub + hub = client.containers.get(hub_id) + hub.kill() + hub.remove() + logger.info("Hub / Node Cleaned up") - if standalone: - logger.info("Standalone Cleaned up") - else: - # Kill the launched hub - hub = client.containers.get(hub_id) - hub.kill() - hub.remove() - logger.info("Hub / Node Cleaned up") def signal_handler(signum, frame): clean_up() sys.exit(0) + signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGQUIT, signal_handler) @@ -58,19 +61,15 @@ def signal_handler(signum, frame): IMAGE_NAME_MAP = { # Hub 'Hub': 'hub', - # Chrome Images 'NodeChrome': 'node-chrome', 'StandaloneChrome': 'standalone-chrome', - # Edge Images 'NodeEdge': 'node-edge', 'StandaloneEdge': 'standalone-edge', - # Firefox Images 'NodeFirefox': 'node-firefox', 'StandaloneFirefox': 'standalone-firefox', - # Chromium Images 'NodeChromium': 'node-chromium', 'StandaloneChromium': 'standalone-chromium', @@ -78,23 +77,18 @@ def signal_handler(signum, frame): TEST_NAME_MAP = { "Android": "ChromeTests", - # Chrome Images 'NodeChrome': 'ChromeTests', 'StandaloneChrome': 'ChromeTests', - # Edge Images 'NodeEdge': 'EdgeTests', 'StandaloneEdge': 'EdgeTests', - # Firefox Images 'NodeFirefox': 'FirefoxTests', 'StandaloneFirefox': 'FirefoxTests', - # Chromium Images 'NodeChromium': 'ChromeTests', 'StandaloneChromium': 'ChromeTests', - # Chart Parallel Test 'JobAutoscaling': 'JobAutoscalingTests', 'DeploymentAutoscaling': 'DeploymentAutoscalingTests', @@ -107,6 +101,7 @@ def signal_handler(signum, frame): 'BASE_RELEASE': BASE_RELEASE, } + def get_platform(): os_arch = platform.machine() if os_arch == 'x86_64': @@ -116,6 +111,7 @@ def get_platform(): logger.info("Current OS platform: %s" % os_arch) return os_arch + def launch_hub(network_name): """ Launch the hub @@ -141,11 +137,11 @@ def launch_hub(network_name): grid_ports = {'4442': 4442, '4443': 4443, '4444': 4444} if use_random_user_id: - hub_container_id = launch_container('Hub', network=network_name, name="selenium-hub", - ports=grid_ports, user=random_user_id) + hub_container_id = launch_container( + 'Hub', network=network_name, name="selenium-hub", ports=grid_ports, user=random_user_id + ) else: - hub_container_id = launch_container('Hub', network=network_name, name="selenium-hub", - ports=grid_ports) + hub_container_id = launch_container('Hub', network=network_name, name="selenium-hub", ports=grid_ports) logger.info("Hub Launched") return hub_container_id @@ -177,11 +173,13 @@ def launch_container(container, **kwargs): logger.info(f"Building {container} container in platform {PLATFORM}...") set_from_image_base_for_standalone(container) build_path = get_build_path(container) - client.images.build(path='../%s' % build_path, - tag=f"{NAMESPACE}/{IMAGE_NAME_MAP[container]}:{VERSION}", - rm=True, - buildargs=FROM_IMAGE_ARGS, - platform=PLATFORM,) + client.images.build( + path='../%s' % build_path, + tag=f"{NAMESPACE}/{IMAGE_NAME_MAP[container]}:{VERSION}", + rm=True, + buildargs=FROM_IMAGE_ARGS, + platform=PLATFORM, + ) logger.info("Done building %s" % container) # Run the container @@ -193,17 +191,19 @@ def launch_container(container, **kwargs): 'no_proxy': no_proxy, 'SE_EVENT_BUS_HOST': 'selenium-hub', 'SE_EVENT_BUS_PUBLISH_PORT': 4442, - 'SE_EVENT_BUS_SUBSCRIBE_PORT': 4443 + 'SE_EVENT_BUS_SUBSCRIBE_PORT': 4443, } if container != 'Hub': environment['SE_NODE_ENABLE_MANAGED_DOWNLOADS'] = "true" - container_id = client.containers.run(f"{NAMESPACE}/{IMAGE_NAME_MAP[container]}:{VERSION}", - detach=True, - environment=environment, - shm_size="2G", - read_only=FILESYSTEM_READ_ONLY, - tmpfs={'/tmp': 'rw'}, - **kwargs).short_id + container_id = client.containers.run( + f"{NAMESPACE}/{IMAGE_NAME_MAP[container]}:{VERSION}", + detach=True, + environment=environment, + shm_size="2G", + read_only=FILESYSTEM_READ_ONLY, + tmpfs={'/tmp': 'rw'}, + **kwargs, + ).short_id logger.info("%s up and running" % container) return container_id @@ -211,15 +211,15 @@ def launch_container(container, **kwargs): def set_from_image_base_for_standalone(container): match = standalone_browser_container_matches(container) if match != None: - FROM_IMAGE_ARGS['BASE'] = 'node-' + match.group(2).lower() + FROM_IMAGE_ARGS['BASE'] = 'node-' + match.group(2).lower() def get_build_path(container): match = standalone_browser_container_matches(container) if match == None: - return container + return container else: - return match.group(1) + return match.group(1) def standalone_browser_container_matches(container): @@ -254,9 +254,9 @@ def standalone_browser_container_matches(container): """ ports = {'4444': 4444} if use_random_user_id: - test_container_id = launch_container(image, ports=ports, user=random_user_id) + test_container_id = launch_container(image, ports=ports, user=random_user_id) else: - test_container_id = launch_container(image, ports=ports) + test_container_id = launch_container(image, ports=ports) else: """ Hub / Node Configuration @@ -266,9 +266,9 @@ def standalone_browser_container_matches(container): hub_id = launch_hub("grid") ports = {'5555': 5555, '7900': 7900} if use_random_user_id: - test_container_id = launch_container(image, network='grid', ports=ports, user=random_user_id) + test_container_id = launch_container(image, network='grid', ports=ports, user=random_user_id) else: - test_container_id = launch_container(image, network='grid', ports=ports) + test_container_id = launch_container(image, network='grid', ports=ports) prune_networks() logger.info('========== / Containers ready to go ==========') diff --git a/tests/test_grid_ui.py b/tests/test_grid_ui.py index c5cc820b12..3e4dc105cd 100644 --- a/tests/test_grid_ui.py +++ b/tests/test_grid_ui.py @@ -1,13 +1,13 @@ import sys +import time from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.chrome.options import Options as ChromeOptions -from selenium.webdriver.firefox.options import Options as FirefoxOptions +from selenium.webdriver.common.by import By from selenium.webdriver.edge.options import Options as EdgeOptions -import time +from selenium.webdriver.firefox.options import Options as FirefoxOptions +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait if len(sys.argv) < 2: print("Usage: python3 get_started.py [chrome|firefox|edge]") @@ -17,6 +17,7 @@ print("Unsupported browser. Use 'chrome', 'firefox', or 'edge'.") sys.exit(1) + def run_browser_instance(browser): while True: @@ -44,6 +45,7 @@ def run_browser_instance(browser): ) import random + elements = driver.find_elements(By.XPATH, "//*[@data-testid='VideocamIcon']/..") if elements: random.choice(elements).click() @@ -54,6 +56,7 @@ def run_browser_instance(browser): time.sleep(15) # Keep the browser open for 10 seconds driver.quit() + import concurrent.futures with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: