From ee6147c96ad13559886b732d4a86be90885fe9e7 Mon Sep 17 00:00:00 2001 From: Ian Castellanos Date: Sat, 9 Jul 2022 17:53:49 -0700 Subject: [PATCH 1/4] adding first selenium tests for Simoc --- selenium/README.md | 10 +++ selenium/selenium_simoc_test.py | 108 ++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 selenium/README.md create mode 100644 selenium/selenium_simoc_test.py diff --git a/selenium/README.md b/selenium/README.md new file mode 100644 index 000000000..2482243ba --- /dev/null +++ b/selenium/README.md @@ -0,0 +1,10 @@ +## SELENIUM WEB TESTING +To run with default parameters go to your terminal and enter: `python3 selenium_test.py` + +There are currently 3 supported args --browser(-b), --processes(-p), --days(-d) i.e. `python3 selenium_test.py -p 3 -d 30` + +This will run 3 browser windows and run a custom sim based off the SAM preset for 30 days + +Currently only Chrome is properly working but adding browser support for other browser should be easy within this script. + +Also can only currently be run on Python 3.10+ due to using the new `match` syntax but can easily be modified to run on versions pre 3.10 diff --git a/selenium/selenium_simoc_test.py b/selenium/selenium_simoc_test.py new file mode 100644 index 000000000..687bd3b4c --- /dev/null +++ b/selenium/selenium_simoc_test.py @@ -0,0 +1,108 @@ +import argparse +from os import wait +import time +import multiprocessing + +from selenium import webdriver +from selenium.webdriver.chrome.service import Service as ChromeService +from selenium.webdriver.chrome.options import Options as ChromeOptions +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities +from selenium.webdriver.common.by import By +from selenium.webdriver.support.select import Select +from selenium.webdriver.support.wait import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +from webdriver_manager.chrome import ChromeDriverManager + + +def select_browser(browser): + # TODO need to add browser support for different browsers and move + # the chrome options and webdriver install out of run_sim() and + # into this function and return browser to the function + # Due to different browser architecture loggin, browser settings, + # and a few other quirks need to be worked out to ensure compat + match browser: + case 'chrome': + chrome_options = ChromeOptions() + chrome_options.add_argument('--incognito') + chrome_options.add_argument('--disable-extenstions') + #chrome_options.add_argument('--headless') + + dc = DesiredCapabilities.CHROME + dc['goog:loggingPrefs'] = { 'browser':'ALL' } + + driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=chrome_options, desired_capabilities=dc) + return driver + case _: + print("Browser not currently targeted") + + +def run_sim(browser, days): + global select_browser + driver = select_browser(browser) + + print(multiprocessing.current_process().name+" has started") + + driver.get("https://beta.simoc.space") + + driver.find_element(By.XPATH, '//button[text()="PROCEED"]').click() + + driver.implicitly_wait(2) + driver.find_element(By.ID, 'guest-login').click() + + wait = WebDriverWait(driver, 10) + sign_in_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[text()="SIGN IN AS GUEST"]'))) + sign_in_button.click() + + driver.find_element(By.XPATH, '//button[text()="NEW CONFIGURATION"]').click() + + + sim_options = Select(driver.find_element(By.XPATH, '/html/body/div[1]/div/div[2]/div/div/section[1]/main/form/section/form/label/div[3]/div/select')) + sim_options.select_by_value('sam_one_human_garden') + + sim_days = driver.find_element(By.CLASS_NAME, 'input-field-number') + sim_days.clear() + sim_days.send_keys(days) + + plant_options = Select(driver.find_element(By.XPATH, '/html/body/div[1]/div/div[2]/div/div/section[1]/main/form/section/div[3]/label[2]/div[3]/select')) + plant_options.select_by_value('wheat') + plant_options.select_by_value('rice') + + driver.find_element(By.CLASS_NAME, 'btn-launch').click() + + print("Sim for "+multiprocessing.current_process().name+" has launched") + + time.sleep(240) + + steps = int(days) * 24 + message = str(steps)+"/"+str(steps)+" steps sent by the server" + found = False + + for log in driver.get_log('browser'): + if message in log['message']: + print("Sim "+multiprocessing.current_process().name+" was successful") + found = True + else: + continue + + if found is not True: + print("Sim "+multiprocessing.current_process().name+ " failed") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--processes', '-p', type=int, default=1, help='Number of processes to run') + parser.add_argument('--days', '-d', type=str, default='100', help='Number of days for sim to run. Min of 1 and max of 365') + parser.add_argument('--browser', '-b', type=str, default='chrome', help='Select browser to run SIMOC in') + + args = parser.parse_args() + + process = [multiprocessing.Process(target=run_sim, kwargs={'browser':args.browser,'days':args.days}) for _ in range(args.processes)] + + for p in process: + p.start() + + +if __name__ == '__main__': + main() + From cbfa276af233d80d09a72f6a754e5f5a77f7b410 Mon Sep 17 00:00:00 2001 From: IMBCIT <42709847+IMBCIT@users.noreply.github.com> Date: Sun, 17 Jul 2022 18:05:51 -0700 Subject: [PATCH 2/4] Apply suggestions from code review Co-authored-by: Ezio Melotti --- selenium/selenium_simoc_test.py | 64 ++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/selenium/selenium_simoc_test.py b/selenium/selenium_simoc_test.py index 687bd3b4c..6dfe2f2f4 100644 --- a/selenium/selenium_simoc_test.py +++ b/selenium/selenium_simoc_test.py @@ -1,8 +1,9 @@ -import argparse -from os import wait import time +import argparse import multiprocessing +from os import wait + from selenium import webdriver from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.chrome.options import Options as ChromeOptions @@ -29,19 +30,20 @@ def select_browser(browser): #chrome_options.add_argument('--headless') dc = DesiredCapabilities.CHROME - dc['goog:loggingPrefs'] = { 'browser':'ALL' } + dc['goog:loggingPrefs'] = {'browser': 'ALL'} - driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=chrome_options, desired_capabilities=dc) + service = ChromeService(ChromeDriverManager().install()) + driver = webdriver.Chrome(service=service, options=chrome_options, + desired_capabilities=dc) return driver case _: print("Browser not currently targeted") def run_sim(browser, days): - global select_browser driver = select_browser(browser) - print(multiprocessing.current_process().name+" has started") + print(f'{multiprocessing.current_process().name} has started") driver.get("https://beta.simoc.space") @@ -51,55 +53,61 @@ def run_sim(browser, days): driver.find_element(By.ID, 'guest-login').click() wait = WebDriverWait(driver, 10) - sign_in_button = wait.until(EC.element_to_be_clickable((By.XPATH, '//button[text()="SIGN IN AS GUEST"]'))) + sign_in_path = '//button[text()="SIGN IN AS GUEST"]' + cond = EC.element_to_be_clickable((By.XPATH, sign_in_path)) + sign_in_button = wait.until(cond) sign_in_button.click() driver.find_element(By.XPATH, '//button[text()="NEW CONFIGURATION"]').click() - sim_options = Select(driver.find_element(By.XPATH, '/html/body/div[1]/div/div[2]/div/div/section[1]/main/form/section/form/label/div[3]/div/select')) + presets_path = '//div[contains(@class, 'presets-dropdown')]/select' + sim_options = Select(driver.find_element(By.XPATH, presets_path)) sim_options.select_by_value('sam_one_human_garden') sim_days = driver.find_element(By.CLASS_NAME, 'input-field-number') sim_days.clear() sim_days.send_keys(days) - plant_options = Select(driver.find_element(By.XPATH, '/html/body/div[1]/div/div[2]/div/div/section[1]/main/form/section/div[3]/label[2]/div[3]/select')) + plant_path = '//div[contains(@class, 'input-plant-wrapper')]/select' + plant_options = Select(driver.find_element(By.XPATH, plant_path)) plant_options.select_by_value('wheat') plant_options.select_by_value('rice') driver.find_element(By.CLASS_NAME, 'btn-launch').click() - print("Sim for "+multiprocessing.current_process().name+" has launched") + print(f"Sim for {multiprocessing.current_process().name} has launched") time.sleep(240) steps = int(days) * 24 - message = str(steps)+"/"+str(steps)+" steps sent by the server" - found = False - - for log in driver.get_log('browser'): + message = f"/{steps} steps sent by the server" + for log in driver.get_log('browser'): if message in log['message']: - print("Sim "+multiprocessing.current_process().name+" was successful") - found = True - else: - continue - - if found is not True: - print("Sim "+multiprocessing.current_process().name+ " failed") + print("Step message found:", log['message']) + if f'{steps}/{steps}' in log['message']: + print(f"Sim {multiprocessing.current_process().name} was successful") + else: + print(f"Sim {multiprocessing.current_process().name} failed") + break + else: + print(f"Sim {multiprocessing.current_process().name} failed") def main(): parser = argparse.ArgumentParser() - parser.add_argument('--processes', '-p', type=int, default=1, help='Number of processes to run') - parser.add_argument('--days', '-d', type=str, default='100', help='Number of days for sim to run. Min of 1 and max of 365') - parser.add_argument('--browser', '-b', type=str, default='chrome', help='Select browser to run SIMOC in') + parser.add_argument('--processes', '-p', type=int, default=1, + help='Number of processes to run') + parser.add_argument('--days', '-d', type=str, default='100', + help='Number of days for sim to run. Min of 1 and max of 365') + parser.add_argument('--browser', '-b', type=str, default='chrome', + help='Select browser to run SIMOC in') args = parser.parse_args() - - process = [multiprocessing.Process(target=run_sim, kwargs={'browser':args.browser,'days':args.days}) for _ in range(args.processes)] - - for p in process: + kwargs = {'browser': args.browser, 'days': args.days} + processes = [multiprocessing.Process(target=run_sim, kwargs=kwargs) + for _ in range(args.processes)] + for p in processes: p.start() From 93f0d96c08d87053e073b11298b57c94d3046cda Mon Sep 17 00:00:00 2001 From: Ian Castellanos Date: Wed, 20 Jul 2022 19:44:53 -0700 Subject: [PATCH 3/4] Fixing issues from CR and adding log parsing --- selenium/selenium_simoc_test.py | 54 +++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/selenium/selenium_simoc_test.py b/selenium/selenium_simoc_test.py index 6dfe2f2f4..450f832ab 100644 --- a/selenium/selenium_simoc_test.py +++ b/selenium/selenium_simoc_test.py @@ -30,7 +30,7 @@ def select_browser(browser): #chrome_options.add_argument('--headless') dc = DesiredCapabilities.CHROME - dc['goog:loggingPrefs'] = {'browser': 'ALL'} + dc['goog:loggingPrefs'] = {'browser':'ALL'} service = ChromeService(ChromeDriverManager().install()) driver = webdriver.Chrome(service=service, options=chrome_options, @@ -42,26 +42,34 @@ def select_browser(browser): def run_sim(browser, days): driver = select_browser(browser) + wait = WebDriverWait(driver, 10) - print(f'{multiprocessing.current_process().name} has started") + print(f"{multiprocessing.current_process().name} has started") driver.get("https://beta.simoc.space") driver.find_element(By.XPATH, '//button[text()="PROCEED"]').click() +<<<<<<< Updated upstream driver.implicitly_wait(2) driver.find_element(By.ID, 'guest-login').click() wait = WebDriverWait(driver, 10) +======= + driver.find_element(By.ID, 'guest-login').click() + +>>>>>>> Stashed changes sign_in_path = '//button[text()="SIGN IN AS GUEST"]' cond = EC.element_to_be_clickable((By.XPATH, sign_in_path)) sign_in_button = wait.until(cond) sign_in_button.click() - driver.find_element(By.XPATH, '//button[text()="NEW CONFIGURATION"]').click() + new_config = '//button[text()="NEW CONFIGURATION"]' + cond = EC.element_to_be_clickable((By.XPATH, new_config)) + new_config_button = wait.until(cond) + new_config_button.click() - - presets_path = '//div[contains(@class, 'presets-dropdown')]/select' + presets_path = '//div[contains(@class, "presets-dropdown")]/select' sim_options = Select(driver.find_element(By.XPATH, presets_path)) sim_options.select_by_value('sam_one_human_garden') @@ -69,7 +77,9 @@ def run_sim(browser, days): sim_days.clear() sim_days.send_keys(days) - plant_path = '//div[contains(@class, 'input-plant-wrapper')]/select' + # wait until server has sent over all plant types and check for existence + wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'option[value="wheat"]'))) + plant_path = '//div[contains(@class, "input-plant-wrapper")]/select' plant_options = Select(driver.find_element(By.XPATH, plant_path)) plant_options.select_by_value('wheat') plant_options.select_by_value('rice') @@ -78,18 +88,32 @@ def run_sim(browser, days): print(f"Sim for {multiprocessing.current_process().name} has launched") - time.sleep(240) + # static wait time will need to be refactored to see if browser log can be polled + # and check for messages that are expected by the server + # time.sleep(240) steps = int(days) * 24 message = f"/{steps} steps sent by the server" - for log in driver.get_log('browser'): - if message in log['message']: - print("Step message found:", log['message']) - if f'{steps}/{steps}' in log['message']: - print(f"Sim {multiprocessing.current_process().name} was successful") - else: + failure = f"Error: Request failed" + + for _ in range(100): + for log in driver.get_log('browser'): + if message in log['message']: + print("Step message found:", log['message']) + if f'{steps}/{steps}' in log['message']: + print(f"Sim {multiprocessing.current_process().name} was successful") + break + else: + print(f"Sim {multiprocessing.current_process().name} failed") + break + elif failure in log['message']: + print("Failure message found:", log['message']) print(f"Sim {multiprocessing.current_process().name} failed") - break + break + else: + time.sleep(1.0) + continue + break else: print(f"Sim {multiprocessing.current_process().name} failed") @@ -102,7 +126,6 @@ def main(): help='Number of days for sim to run. Min of 1 and max of 365') parser.add_argument('--browser', '-b', type=str, default='chrome', help='Select browser to run SIMOC in') - args = parser.parse_args() kwargs = {'browser': args.browser, 'days': args.days} processes = [multiprocessing.Process(target=run_sim, kwargs=kwargs) @@ -113,4 +136,3 @@ def main(): if __name__ == '__main__': main() - From 8d33e2a5d7330423e142c18c1284826723f49d8e Mon Sep 17 00:00:00 2001 From: Ian Castellanos Date: Wed, 20 Jul 2022 19:54:01 -0700 Subject: [PATCH 4/4] Fixing issue from lazygit hunk changes --- selenium/selenium_simoc_test.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/selenium/selenium_simoc_test.py b/selenium/selenium_simoc_test.py index 450f832ab..e9b3a9f8e 100644 --- a/selenium/selenium_simoc_test.py +++ b/selenium/selenium_simoc_test.py @@ -50,15 +50,8 @@ def run_sim(browser, days): driver.find_element(By.XPATH, '//button[text()="PROCEED"]').click() -<<<<<<< Updated upstream - driver.implicitly_wait(2) driver.find_element(By.ID, 'guest-login').click() - wait = WebDriverWait(driver, 10) -======= - driver.find_element(By.ID, 'guest-login').click() - ->>>>>>> Stashed changes sign_in_path = '//button[text()="SIGN IN AS GUEST"]' cond = EC.element_to_be_clickable((By.XPATH, sign_in_path)) sign_in_button = wait.until(cond)