From 5e9ec4ee981bf36a8d446d33c3919cf7c7aad366 Mon Sep 17 00:00:00 2001 From: Kenneth Skovhede Date: Mon, 1 Jul 2024 13:36:27 +0200 Subject: [PATCH] Fixed selenium tests --- guiTests/guiTest.py | 228 +++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 99 deletions(-) diff --git a/guiTests/guiTest.py b/guiTests/guiTest.py index de415ebdd..37866094e 100644 --- a/guiTests/guiTest.py +++ b/guiTests/guiTest.py @@ -24,7 +24,6 @@ parser.add_argument( "--chrome-path" ) - parser.set_defaults(headless=True) cmdopt = parser.parse_args() @@ -60,6 +59,7 @@ elif cmdopt.use_chrome: opt = ["--ignore-certificate-errors", "--window-size=1280,800" ] if cmdopt.headless: opt += ["--headless"] for o in opt: chr_opt.add_argument(o) + chr_opt.set_capability('goog:loggingPrefs', { 'browser':'ALL' }) driver = webdriver.Chrome(options=chr_opt) else: from selenium.webdriver.firefox.options import Options @@ -121,129 +121,159 @@ def wait_for_redirect(expected_url, timeout=10): def wait_for_title(title, timeout=10): WebDriverWait(driver, timeout).until(lambda driver: title in driver.title) -HOME_URL = "http://localhost:8200/ngax/index.html" -LOGIN_URL = "http://localhost:8200/login.html" -WEBSERVICE_PASSWORD = "easy1234" -BACKUP_NAME = "BackupName" -PASSWORD = "the_backup_password_is_really_long_and_safe" -SOURCE_FOLDER = os.path.abspath("duplicati_gui_test_source") -DESTINATION_FOLDER = os.path.abspath("duplicati_gui_test_destination") -DESTINATION_FOLDER_DIRECT_RESTORE = os.path.abspath("duplicati_gui_test_destination_direct_restore") -RESTORE_FOLDER = os.path.abspath("duplicati_gui_test_restore") -DIRECT_RESTORE_FOLDER = os.path.abspath("duplicati_gui_test_direct_restore") +def runTests(): + HOME_URL = "http://localhost:8200/ngax/index.html" + LOGIN_URL = "http://localhost:8200/login.html" + WEBSERVICE_PASSWORD = "easy1234" + BACKUP_NAME = "BackupName" + PASSWORD = "the_backup_password_is_really_long_and_safe" + SOURCE_FOLDER = os.path.abspath("duplicati_gui_test_source") + DESTINATION_FOLDER = os.path.abspath("duplicati_gui_test_destination") + DESTINATION_FOLDER_DIRECT_RESTORE = os.path.abspath("duplicati_gui_test_destination_direct_restore") + RESTORE_FOLDER = os.path.abspath("duplicati_gui_test_restore") + DIRECT_RESTORE_FOLDER = os.path.abspath("duplicati_gui_test_direct_restore") -driver.maximize_window() -driver.get(LOGIN_URL) -wait_for_load(By.ID, "login-password").send_keys(WEBSERVICE_PASSWORD) -wait_for_load(By.ID, "login-button").click() + driver.maximize_window() + driver.get(LOGIN_URL) + wait_for_load(By.ID, "login-password").send_keys(WEBSERVICE_PASSWORD) + wait_for_load(By.ID, "login-button").click() -wait_for_redirect(HOME_URL) -wait_for_title("Duplicati") + wait_for_redirect(HOME_URL) + time.sleep(1) -# Create and hash random files in the source folder -write_random_file(1024 * 1024, SOURCE_FOLDER + os.sep + "1MB.test") -write_random_file(100 * 1024, SOURCE_FOLDER + os.sep + "subfolder" + os.sep + "100KB.test") -sha1_source = sha1_folder(SOURCE_FOLDER) + # Load attempts + attempts = 10 -# Add new backup -wait_for_load(By.LINK_TEXT, "Add backup") -wait_for_clickable(By.LINK_TEXT, "Add backup").click() + # When running in headless mode the requests are too fast + # and index.html loads multiple .js files which exhaust the + # Chrome pending request queue, + # So we re-issue the "get" to depend on cached results + # meaning less requests and less chance of exhausting the queue + # Upgrading to a newer Angular version will fix this issue + while attempts > 0: + try: + wait_for_title("Duplicati") + wait_for_clickable(By.LINK_TEXT, "Add backup") + break + except: + print("Loading failed, retrying") + attempts -= 1 + driver.get(HOME_URL) + time.sleep(1) -# Choose the "add new" option -wait_for_clickable(By.ID, "blank").click() -wait_for_load(By.XPATH, "//input[@class='submit next']").click() + # Create and hash random files in the source folder + write_random_file(1024 * 1024, SOURCE_FOLDER + os.sep + "1MB.test") + write_random_file(100 * 1024, SOURCE_FOLDER + os.sep + "subfolder" + os.sep + "100KB.test") + sha1_source = sha1_folder(SOURCE_FOLDER) -# Add new backup - General page -wait_for_load(By.ID, "name").send_keys(BACKUP_NAME) -wait_for_load(By.ID, "passphrase").send_keys(PASSWORD) -wait_for_load(By.ID, "repeat-passphrase").send_keys(PASSWORD) -wait_for_load(By.ID, "nextStep1").click() + # Add new backup + wait_for_load(By.LINK_TEXT, "Add backup") + wait_for_clickable(By.LINK_TEXT, "Add backup").click() -# Add new backup - Destination page -wait_for_load(By.LINK_TEXT, "Manually type path").click() -wait_for_load(By.ID, "file_path").send_keys(DESTINATION_FOLDER) -wait_for_load(By.ID, "nextStep2").click() + # Choose the "add new" option + wait_for_clickable(By.ID, "blank").click() + wait_for_load(By.XPATH, "//input[@class='submit next']").click() -# Add new backup - Source Data page -wait_for_load(By.ID, "sourcePath").send_keys(os.path.abspath(SOURCE_FOLDER) + os.sep) -wait_for_load(By.ID, "sourceFolderPathAdd").click() -wait_for_load(By.ID, "nextStep3").click() + # Add new backup - General page + wait_for_load(By.ID, "name").send_keys(BACKUP_NAME) + wait_for_load(By.ID, "passphrase").send_keys(PASSWORD) + wait_for_load(By.ID, "repeat-passphrase").send_keys(PASSWORD) + wait_for_load(By.ID, "nextStep1").click() -# Add new backup - Schedule page -useScheduleRun = wait_for_load(By.ID, "useScheduleRun") -if useScheduleRun.is_selected(): - useScheduleRun.click() -wait_for_load(By.ID, "nextStep4").click() + # Add new backup - Destination page + wait_for_load(By.LINK_TEXT, "Manually type path").click() + wait_for_load(By.ID, "file_path").send_keys(DESTINATION_FOLDER) + wait_for_load(By.ID, "nextStep2").click() -# Add new backup - Options page -wait_for_load(By.ID, "save").click() + # Add new backup - Source Data page + wait_for_load(By.ID, "sourcePath").send_keys(os.path.abspath(SOURCE_FOLDER) + os.sep) + wait_for_load(By.ID, "sourceFolderPathAdd").click() + wait_for_load(By.ID, "nextStep3").click() -# Run the backup job and wait for finish -wait_for_clickable(By.LINK_TEXT, BACKUP_NAME).click() -[n for n in driver.find_elements("xpath", "//dl[@class='taskmenu']/dd/p/span[contains(text(),'Run now')]") if n.is_displayed()][0].click() -wait_for_text("//div[@class='task ng-scope']/dl[2]/dd[1]", "(took ", 60) + # Add new backup - Schedule page + useScheduleRun = wait_for_load(By.ID, "useScheduleRun") + if useScheduleRun.is_selected(): + useScheduleRun.click() + wait_for_load(By.ID, "nextStep4").click() -# Restore -if len([n for n in driver.find_elements("xpath", u"//span[contains(text(),'Restore files \u2026')]") if n.is_displayed()]) == 0: + # Add new backup - Options page + wait_for_load(By.ID, "save").click() + + # Run the backup job and wait for finish wait_for_clickable(By.LINK_TEXT, BACKUP_NAME).click() + [n for n in driver.find_elements("xpath", "//dl[@class='taskmenu']/dd/p/span[contains(text(),'Run now')]") if n.is_displayed()][0].click() + wait_for_text("//div[@class='task ng-scope']/dl[2]/dd[1]", "(took ", 60) -[n for n in driver.find_elements("xpath", u"//span[contains(text(),'Restore files \u2026')]") if n.is_displayed()][0].click() -wait_for_load(By.XPATH, "//span[contains(text(),'" + SOURCE_FOLDER + "')]") # wait for filelist -time.sleep(1) # Delay so page has time to load -wait_for_load(By.XPATH, "//restore-file-picker/ul/li/div/a[2]").click() # select root folder checkbox + # Restore + if len([n for n in driver.find_elements("xpath", u"//span[contains(text(),'Restore files \u2026')]") if n.is_displayed()]) == 0: + wait_for_clickable(By.LINK_TEXT, BACKUP_NAME).click() -wait_for_load(By.XPATH, "//form[@id='restore']/div[1]/div[@class='buttons']/a/span[contains(text(), 'Continue')]").click() -wait_for_load(By.ID, "restoretonewpath").click() -wait_for_load(By.ID, "restore_path").send_keys(RESTORE_FOLDER) -wait_for_load(By.XPATH, "//form[@id='restore']/div/div[@class='buttons']/a/span[contains(text(),'Restore')]").click() + [n for n in driver.find_elements("xpath", u"//span[contains(text(),'Restore files \u2026')]") if n.is_displayed()][0].click() + wait_for_load(By.XPATH, "//span[contains(text(),'" + SOURCE_FOLDER + "')]") # wait for filelist + time.sleep(1) # Delay so page has time to load + wait_for_load(By.XPATH, "//restore-file-picker/ul/li/div/a[2]").click() # select root folder checkbox -# wait for restore to finish -wait_for_text("//form[@id='restore']/div[3]/h3/div[1]", "Your files and folders have been restored successfully.", 60) + wait_for_load(By.XPATH, "//form[@id='restore']/div[1]/div[@class='buttons']/a/span[contains(text(), 'Continue')]").click() + wait_for_load(By.ID, "restoretonewpath").click() + wait_for_load(By.ID, "restore_path").send_keys(RESTORE_FOLDER) + wait_for_load(By.XPATH, "//form[@id='restore']/div/div[@class='buttons']/a/span[contains(text(),'Restore')]").click() -# hash restored files -sha1_restore = sha1_folder(RESTORE_FOLDER) + # wait for restore to finish + wait_for_text("//form[@id='restore']/div[3]/h3/div[1]", "Your files and folders have been restored successfully.", 60) -# cleanup: delete source and restore folder and rename destination folder for direct restore -if os.path.exists(SOURCE_FOLDER): - shutil.rmtree(SOURCE_FOLDER) -if os.path.exists(RESTORE_FOLDER): - shutil.rmtree(RESTORE_FOLDER) -os.rename(DESTINATION_FOLDER, DESTINATION_FOLDER_DIRECT_RESTORE) + # hash restored files + sha1_restore = sha1_folder(RESTORE_FOLDER) -# direct restore -wait_for_load(By.LINK_TEXT, "Restore").click() + # cleanup: delete source and restore folder and rename destination folder for direct restore + if os.path.exists(SOURCE_FOLDER): + shutil.rmtree(SOURCE_FOLDER) + if os.path.exists(RESTORE_FOLDER): + shutil.rmtree(RESTORE_FOLDER) + os.rename(DESTINATION_FOLDER, DESTINATION_FOLDER_DIRECT_RESTORE) -# Choose the "restore direct" option -wait_for_load(By.ID, "direct").click() -wait_for_load(By.XPATH, "//input[@class='submit next']").click() + # direct restore + wait_for_load(By.LINK_TEXT, "Restore").click() -wait_for_load(By.LINK_TEXT, "Manually type path").click() -wait_for_load(By.ID, "file_path").send_keys(DESTINATION_FOLDER_DIRECT_RESTORE) -wait_for_load(By.ID, "nextStep1").click() + # Choose the "restore direct" option + wait_for_load(By.ID, "direct").click() + wait_for_load(By.XPATH, "//input[@class='submit next']").click() -wait_for_load(By.ID, "password").send_keys(PASSWORD) -wait_for_load(By.ID, "connect").click() -wait_for_load(By.XPATH, "//span[contains(text(),'" + SOURCE_FOLDER + "')]") # wait for filelist -time.sleep(1) # Delay so page has time to load -wait_for_load(By.XPATH, "//restore-file-picker/ul/li/div/a[2]").click() # select root folder checkbox -wait_for_load(By.XPATH, "//form[@id='restore']/div[1]/div[@class='buttons']/a/span[contains(text(), 'Continue')]").click() + wait_for_load(By.LINK_TEXT, "Manually type path").click() + wait_for_load(By.ID, "file_path").send_keys(DESTINATION_FOLDER_DIRECT_RESTORE) + wait_for_load(By.ID, "nextStep1").click() -wait_for_load(By.ID, "restoretonewpath").click() -wait_for_load(By.ID, "restore_path").send_keys(DIRECT_RESTORE_FOLDER) -wait_for_load(By.XPATH, "//form[@id='restore']/div/div[@class='buttons']/a/span[contains(text(),'Restore')]").click() + wait_for_load(By.ID, "password").send_keys(PASSWORD) + wait_for_load(By.ID, "connect").click() + wait_for_load(By.XPATH, "//span[contains(text(),'" + SOURCE_FOLDER + "')]") # wait for filelist -# wait for restore to finish -wait_for_text("//form[@id='restore']/div[3]/h3/div[1]", "Your files and folders have been restored successfully.", 60) + time.sleep(1) # Delay so page has time to load + wait_for_load(By.XPATH, "//restore-file-picker/ul/li/div/a[2]").click() # select root folder checkbox + wait_for_load(By.XPATH, "//form[@id='restore']/div[1]/div[@class='buttons']/a/span[contains(text(), 'Continue')]").click() -# hash direct restore files -sha1_direct_restore = sha1_folder(DIRECT_RESTORE_FOLDER) + wait_for_load(By.ID, "restoretonewpath").click() + wait_for_load(By.ID, "restore_path").send_keys(DIRECT_RESTORE_FOLDER) + wait_for_load(By.XPATH, "//form[@id='restore']/div/div[@class='buttons']/a/span[contains(text(),'Restore')]").click() -print("Source hashes: " + str(sha1_source)) -print("Restore hashes: " + str(sha1_restore)) -print("Direct Restore hashes: " + str(sha1_direct_restore)) + # wait for restore to finish + wait_for_text("//form[@id='restore']/div[3]/h3/div[1]", "Your files and folders have been restored successfully.", 60) -# Tell Sauce Labs to stop the test -driver.quit() + # hash direct restore files + sha1_direct_restore = sha1_folder(DIRECT_RESTORE_FOLDER) -if not (sha1_source == sha1_restore and sha1_source == sha1_direct_restore): - sys.exit(1) # return with error + print("Source hashes: " + str(sha1_source)) + print("Restore hashes: " + str(sha1_restore)) + print("Direct Restore hashes: " + str(sha1_direct_restore)) + + # Tell Sauce Labs to stop the test + driver.quit() + + if not (sha1_source == sha1_restore and sha1_source == sha1_direct_restore): + sys.exit(1) # return with error + +try: + runTests() +except: + print("Test failed, emitting browser log lines: ") + for entry in driver.get_log('browser'): + print(entry) + raise