diff options
author | Frank Bergkemper <frank.bergkemper@bareos.com> | 2018-01-29 13:33:38 +0300 |
---|---|---|
committer | Frank Bergkemper <frank.bergkemper@bareos.com> | 2018-01-29 13:33:38 +0300 |
commit | dbd18bef2f7f7780ba8dbcd2e0c7895b92712ddc (patch) | |
tree | 816f2ecbd2be639d971c6ff7cb1d4d909904a0ad | |
parent | 71b0a510c4e81bdd96f7a637265683c2ab563a4d (diff) | |
parent | 216096d99b1ea40f33e2d3758a267961a8a106a1 (diff) |
Merge branch 'bareos-16.2' into bareos-17.2
-rw-r--r-- | tests/selenium/README.md | 33 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/selenium/webui-selenium-test.py | 341 |
2 files changed, 251 insertions, 123 deletions
diff --git a/tests/selenium/README.md b/tests/selenium/README.md index 20c89a2..60be403 100644 --- a/tests/selenium/README.md +++ b/tests/selenium/README.md @@ -2,23 +2,36 @@ This test checks the Bareos WebUI by using seleniums webdriver. +## Requirements + + * Python >= 2.7 + * Selenium >= 3.4.0 + * chromedriver or geckodriver ## Setting up the test To run the test you must set certain environment variables: - * **BROWSER**: The test takes either 'firefox' or 'chrome', where 'firefox' is the default. - * **USERNAME** and **PASSWORD**: These should contain the login information for the WebUI. - * **VM_IP**: This should be the IP adress of the system where the Bareos WebUI runs on. - * **RESTOREFILE**: The third test is designed to restore a certain file. The default path is '/usr/sbin/bconsole". - * **CLIENT**: Here you need to set what Client the restore test should select. + * `BAREOS_BROWSER`: The test takes either 'firefox' or 'chrome', default: `firefox` + * `BAREOS_BASE_URL`: The base url of the bareos-webui, default: `http://127.0.0.1/bareos-webui/`. + * `BAREOS_USERNAME`: Login user name, default: `admin` + * `BAREOS_PASSWORD`: Login password, default: `secret` + * `BAREOS_CLIENT_NAME`: The client to use. Default is `bareos-fd` + * `BAREOS_RESTOREFILE`: The third test is designed to restore a certain file. The default path is `/usr/sbin/bconsole` + * `BAREOS_LOG_PATH`: Directory to create selenium log files. The default path is the current directory. + * `BAREOS_DELAY`: Delay between action is seconds. Useful for debugging. Default is `0.0` ## Running the test -To run all tests included you need a system that runs the WebUI, a client for restore-testing, chromedriver or geckodriver as well as any Python >= 2.7. +` +BAREOS_BASE_URL=http://127.0.0.1/bareos-webui/ +BAREOS_USERNAME=admin +BAREOS_PASSWORD=linuxlinux +BAREOS_CLIENT=bareos-fd +BAREOS_RESTOREFILE=/etc/passwd +BAREOS_LOG_PATH=/tmp/selenium-logs/ +BAREOS_DELAY=1 +python webui-selenium-test.py -v +` If you meet all the requirements and set the environment variables you can run the test with `python webui-selenium-test.py`. - -## Debugging - -If the test should fail you will find additional informations in the webui-selenium-test.log file. You might want to adjust **SLEEPTIME** environment variable to be set above 1 as it increases the time waited between commands.
\ No newline at end of file diff --git a/tests/selenium/webui-selenium-test.py b/tests/selenium/webui-selenium-test.py index 59ba846..8a7bb8c 100644..100755 --- a/tests/selenium/webui-selenium-test.py +++ b/tests/selenium/webui-selenium-test.py @@ -1,80 +1,132 @@ +#!/usr/bin/env python + # -*- coding: utf-8 -*- -import logging, os, re, sys, time, unittest -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.common.desired_capabilities import DesiredCapabilities -from selenium.common.exceptions import WebDriverException, ElementNotInteractableException, ElementNotVisibleException, TimeoutException, NoAlertPresentException, NoSuchElementException -from selenium.webdriver.common.keys import Keys -from selenium.webdriver.support.ui import Select, WebDriverWait + +# selenium.common.exceptions.ElementNotInteractableException: requires >= selenium-3.4.0 + +import logging, os, re, sys, unittest +from datetime import datetime, timedelta +from selenium import webdriver +from selenium.common.exceptions import * + #WebDriverException, ElementNotInteractableException, ElementNotVisibleException, TimeoutException, NoAlertPresentException, NoSuchElementException +from selenium.webdriver.common.by import By +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import Select, WebDriverWait +#from selenium.webdriver.remote.remote_connection import LOGGER +from time import sleep + + class WebuiSeleniumTest(unittest.TestCase): + browser = 'firefox' + base_url = "http://127.0.0.1/bareos-webui" + username = "admin" + password = "secret" + client = 'bareos-fd' + restorefile = '/usr/sbin/bconsole' + # path to store logging files + logpath = os.getcwd() + # slow down test for debugging + sleeptime = 0.0 + # max seconds to wait for an element + maxwait = 10 + # time to wait before trying again + waittime = 0.1 + + def setUp(self): - if browser == "chrome": - d = DesiredCapabilities.CHROME - d['loggingPrefs'] = { 'browser':'ALL' } - self.driver = webdriver.Chrome('/usr/local/sbin/chromedriver') - if browser == "firefox": + # Configure the logger, for information about the timings set it to INFO + # Selenium driver itself will write additional debug messages when set to DEBUG + #logging.basicConfig(filename='webui-selenium-test.log', level=logging.DEBUG) + #logging.basicConfig(filename='webui-selenium-test.log', level=logging.INFO) + logging.basicConfig( + filename='%s/webui-selenium-test.log' % (self.logpath), + format='%(levelname)s %(module)s.%(funcName)s: %(message)s', + level=logging.INFO + ) + self.logger = logging.getLogger() + + if self.browser == "chrome": + #d = DesiredCapabilities.CHROME + #d['loggingPrefs'] = { 'browser':'ALL' } + self.driver = webdriver.Chrome('/usr/lib/chromium-browser/chromedriver') + if self.browser == "firefox": d = DesiredCapabilities.FIREFOX d['loggingPrefs'] = { 'browser':'ALL' } fp = webdriver.FirefoxProfile() - fp.set_preference('webdriver.log.file', os.getcwd() + '/firefox_console.log') - self.driver = webdriver.Firefox() - self.driver.implicitly_wait(4) - self.base_url = "http://%s" % targethost + fp.set_preference('webdriver.log.file', self.logpath + '/firefox_console.log') + self.driver = webdriver.Firefox(capabilities=d, firefox_profile=fp) + + self.driver.implicitly_wait(1) + + # used as timeout for selenium.webdriver.support.expected_conditions (EC) + self.wait = WebDriverWait(self.driver, self.maxwait) + + # take base url, but remove last / + self.base_url = base_url.rstrip('/') + self.verificationErrors = [] - self.accept_next_alert = True - + + + def test_login(self): self.login() - time.sleep(0.5+t) self.logout() + + def test_menue(self): driver = self.driver - # On windows we have a different baseurl - if os.getenv('DIST') == "windows": - driver.get(self.base_url + "/") - else: - driver.get(self.base_url + "/bareos-webui/") + + self.driver.get(self.base_url + "/") self.login() - self.wait_for_url('/bareos-webui/director/').click() - self.wait_for_url("/bareos-webui/schedule/").click() - self.wait_for_url("/bareos-webui/schedule/status/").click() - self.wait_for_url("/bareos-webui/storage/").click() - self.wait_for_url("/bareos-webui/client/").click() - self.wait_for_url("/bareos-webui/restore/").click() + self.wait_for_url_and_click('/director/') + self.wait_for_url_and_click("/schedule/") + self.wait_for_url_and_click("/schedule/status/") + self.wait_for_url_and_click("/storage/") + self.wait_for_url_and_click("/client/") + self.wait_for_url_and_click("/restore/") + self.wait_and_click(By.XPATH, "//a[contains(@href, '/dashboard/')]", By.XPATH, "//div[@id='modal-001']//button[.='Close']") + #self.assertRegexpMatches(self.close_alert_and_get_its_text(), r"^Oops, something went wrong, probably too many files.") + self.close_alert_and_get_its_text() self.logout() + + def test_restore(self): - pathlist = restorefile.split('/') - driver = self.driver # LOGGING IN: self.login() # CHANGING TO RESTORE TAB: - self.wait_for_url("/bareos-webui/restore/").click() + self.wait_for_url_and_click("/restore/") + self.wait_and_click(By.XPATH, "(//button[@data-id='client'])", By.XPATH, "//div[@id='modal-001']//button[.='Close']") # SELECTING CLIENT: # Selects the correct client - self.wait_for_element(By.XPATH, "(//button[@type='button'])[3]").click() - self.driver.find_element(By.LINK_TEXT, client).click() + self.wait_and_click(By.LINK_TEXT, self.client) # FILE-SELECTION: # Clicks on file and navigates through the tree # by using the arrow-keys. + pathlist = self.restorefile.split('/') for i in pathlist[:-1]: self.wait_for_element(By.XPATH, "//a[contains(text(),'%s/')]" % i).send_keys(Keys.ARROW_RIGHT) - else: - self.wait_for_element(By.XPATH, "//a[contains(text(),'%s')]" % pathlist[-1]).click() + self.wait_for_element(By.XPATH, "//a[contains(text(),'%s')]" % pathlist[-1]).click() # CONFIRMATION: # Clicks on 'submit' - self.wait_for_element(By.XPATH, "//input[@id='submit']").click() + self.wait_and_click(By.XPATH, "//input[@id='submit']") # Confirms alert that has text "Are you sure ?" self.assertRegexpMatches(self.close_alert_and_get_its_text(), r"^Are you sure[\s\S]$") + # switch to dashboard to prevent that modals are open + self.wait_and_click(By.XPATH, "//a[contains(@href, '/dashboard/')]", By.XPATH, "//div[@id='modal-002']//button[.='Close']") + #self.assertRegexpMatches(self.close_alert_and_get_its_text(), r"^Oops, something went wrong, probably too many files.") + self.close_alert_and_get_its_text() # LOGOUT: self.logout() @@ -83,72 +135,131 @@ class WebuiSeleniumTest(unittest.TestCase): def login(self): driver = self.driver - # on windows we have a different baseurl - if os.getenv('DIST') == "windows": - driver.get(self.base_url + "/auth/login") - else: - driver.get(self.base_url + "/bareos-webui/auth/login") + driver.get(self.base_url + "/auth/login") Select(driver.find_element_by_name("director")).select_by_visible_text("localhost-dir") driver.find_element_by_name("consolename").clear() - driver.find_element_by_name("consolename").send_keys(username) + driver.find_element_by_name("consolename").send_keys(self.username) driver.find_element_by_name("password").clear() - driver.find_element_by_name("password").send_keys(password) + driver.find_element_by_name("password").send_keys(self.password) driver.find_element_by_xpath("(//button[@type='button'])[2]").click() driver.find_element_by_link_text("English").click() driver.find_element_by_xpath("//input[@id='submit']").click() - while ("/bareos-webui/dashboard/" not in self.driver.current_url): - time.sleep(t*0.1) + while ("/dashboard/" not in self.driver.current_url): + sleep(self.waittime) def logout(self): - time.sleep(t) - self.wait_for_element(By.CSS_SELECTOR, "a.dropdown-toggle").click() - self.wait_for_element(By.LINK_TEXT, "Logout").click() - time.sleep(2) + + self.wait_and_click(By.CSS_SELECTOR, "a.dropdown-toggle") + self.wait_and_click(By.LINK_TEXT, "Logout") + sleep(self.sleeptime) + + def wait_for_url(self, what): value="//a[contains(@href, '%s')]" % what - time.sleep(t*0.5) return self.wait_for_element(By.XPATH, value) + + - def wait_for_element(self, by, value): - i=10 - element=None - while i>0 and element is None: - try: - time.sleep(0.5+(t*0.5)) - logging.info("Loading %s", value) - tmp_element = self.driver.find_element(by, value) - if tmp_element.is_displayed(): - element = tmp_element - except ElementNotInteractableException: - logging.info("Element %s not interactable", value) - except NoSuchElementException: - logging.info("Element %s not existing", value) - except ElementNotVisibleException: - logging.info("Element %s not visible", value) - i=i-1 - if(i==0): - logging.info("Timeout while loading %s .", value) - else: - logging.info("Element loaded after %s seconds." % (11-i)) + def wait_for_element(self, by, value, starttime = None): + logger = logging.getLogger() + element = None + #if starttime is None: + #starttime = datetime.now() + #seconds = (datetime.now() - starttime).total_seconds() + #logger.info("waiting for %s %s (%ds)", by, value, seconds) + #while (seconds < self.maxwait) and (element is None): + #try: + #tmp_element = self.driver.find_element(by, value) + #if tmp_element.is_displayed(): + #element = tmp_element + #except ElementNotInteractableException: + #sleep(self.waittime) + #logger.info("%s %s not interactable", by, value) + #except NoSuchElementException: + #sleep(self.waittime) + #logger.info("%s %s not existing", by, value) + #except ElementNotVisibleException: + #sleep(self.waittime) + #logger.info("%s %s not visible", by, value) + #seconds = (datetime.now() - starttime).total_seconds() + #if element: + #logger.info("%s %s loaded after %ss." % (by, value, seconds)) + #sleep(self.sleeptime) + #else: + #logger.warning("Timeout while loading %s %s (%d s)", by, value, seconds) + logger.info("waiting for %s %s", by, value) + element = self.wait.until(EC.element_to_be_clickable((by, value))) return element - def is_alert_present(self): - try: self.driver.switch_to_alert() - except NoAlertPresentException as e: return False - return True - def close_alert_and_get_its_text(self): + def wait_for_url_and_click(self, url): + logger = logging.getLogger() + value="//a[contains(@href, '%s')]" % url + element = self.wait_and_click(By.XPATH, value) + # wait for page to be loaded + starttime = datetime.now() + seconds = 0.0 + while seconds < self.maxwait: + if (url in self.driver.current_url): + logger.info("%s is loaded (%d s)", url, seconds) + return element + logger.info("waiting for url %s to be loaded", url) + sleep(self.waittime) + seconds = (datetime.now() - starttime).total_seconds() + logger.warning("Timeout while waiting for url %s (%d s)", url, seconds) + + + def wait_and_click(self, by, value, modal_by=None, modal_value=None): + logger = logging.getLogger() + element = None + starttime = datetime.now() + seconds = 0.0 + while seconds < self.maxwait: + if modal_by and modal_value: + try: + self.driver.find_element(modal_by, modal_value).click() + except: + logger.info("skipped modal: %s %s not found", modal_by, modal_value) + else: + logger.info("closing modal %s %s", modal_by, modal_value) + logger.info("waiting for %s %s (%ss)", by, value, seconds) + element = self.wait_for_element(by, value, starttime) + try: + element.click() + except WebDriverException as e: + #logger.info("WebDriverException while clicking %s %s", by, value) + logger.info("WebDriverException: %s", e) + #logger.exception(e) + sleep(self.waittime) + else: + return element + seconds = (datetime.now() - starttime).total_seconds() + logger.error("failed to click %s %s", by, value) + return + + + + def close_alert_and_get_its_text(self, accept=True): + logger = logging.getLogger() + try: alert = self.driver.switch_to_alert() alert_text = alert.text - if self.accept_next_alert: - alert.accept() - else: - alert.dismiss() - return alert_text - finally: self.accept_next_alert = True + except NoAlertPresentException: + return + + if accept: + alert.accept() + else: + alert.dismiss() + + logger.debug( 'alert message: %s' % (alert_text)) + + return alert_text + + def tearDown(self): self.driver.quit() @@ -157,34 +268,38 @@ class WebuiSeleniumTest(unittest.TestCase): if __name__ == "__main__": - # Configure the logger, for information about the timings set it to INFO - # Selenium driver itself will write additional debug messages when set to DEBUG - logging.basicConfig(filename='webui-selenium-test.log', level=logging.INFO) - logger = logging.getLogger() - # Get attributes as environment variables, # if not available or set use defaults. - browser = os.environ.get('BROWSER') - if not browser: - browser = 'firefox' - client = os.environ.get('CLIENT') - if not client: - client = 'bareos-fd' - restorefile = os.environ.get('RESTOREFILE') - if not restorefile: - restorefile = '/usr/sbin/bconsole' - username = os.environ.get('USERNAME') - if not username: - username = "citest" - password = os.environ.get('PASSWORD') - if not password: - password = "citestpass" - t = os.environ.get('SLEEPTIME') - if t: - t = float(t) - if not t: - t = 1.0 - targethost = os.environ.get('VM_IP') - if not targethost: - targethost = "127.0.0.1" - unittest.main()
\ No newline at end of file + browser = os.environ.get('BAREOS_BROWSER') + if browser: + WebuiSeleniumTest.browser = browser + + base_url = os.environ.get('BAREOS_BASE_URL') + if base_url: + WebuiSeleniumTest.base_url = base_url.rstrip('/') + + username = os.environ.get('BAREOS_USERNAME') + if username: + WebuiSeleniumTest.username = username + + password = os.environ.get('BAREOS_PASSWORD') + if password: + WebuiSeleniumTest.password = password + + client = os.environ.get('BAREOS_CLIENT_NAME') + if client: + WebuiSeleniumTest.client = client + + restorefile = os.environ.get('BAREOS_RESTOREFILE') + if restorefile: + WebuiSeleniumTest.restorefile = restorefile + + logpath = os.environ.get('BAREOS_LOG_PATH') + if logpath: + WebuiSeleniumTest.logpath = logpath + + sleeptime = os.environ.get('BAREOS_DELAY') + if sleeptime: + WebuiSeleniumTest.sleeptime = float(sleeptime) + + unittest.main() |