Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Unified Diff: components/test/data/password_manager/environment.py

Issue 273523004: Password Manager testing automation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: renaming Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/test/data/password_manager/environment.py
diff --git a/components/test/data/password_manager/environment.py b/components/test/data/password_manager/environment.py
new file mode 100644
index 0000000000000000000000000000000000000000..094dc4cf611bcd4038cd7b5fd34b4b497bde52e8
--- /dev/null
+++ b/components/test/data/password_manager/environment.py
@@ -0,0 +1,289 @@
+"""The testing Environment class."""
+
+import logging
+import shutil
+import time
+
+from selenium import webdriver
+from selenium.common.exceptions import NoSuchElementException
+from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.chrome.options import Options
+from xml.etree import ElementTree
+
+
+class Environment:
+ """Sets up the testing Environment. """
+
+ def __init__(self, chrome_path, chromedriver_path, profile_path,
+ passwords_path, enable_automatic_password_saving,
+ numeric_level, log_screen, log_file):
vabr (Chromium) 2014/05/20 14:47:25 nit: log_screen -> log_to_console
vabr (Chromium) 2014/05/20 14:47:25 Please provide default values for numeric_level, l
rchtara 2014/05/22 08:44:38 Done.
rchtara 2014/05/22 08:44:38 Done.
+ """Creates a new testing Environment.
+
+ Args:
+ chrome_path: The chrome binary file.y
vabr (Chromium) 2014/05/20 14:47:25 typo: "y" at the end of the line
rchtara 2014/05/22 08:44:38 Done.
+ chromedriver_path: The chromedriver binary file.
+ profile_path: The testing profile folder.
vabr (Chromium) 2014/05/20 14:47:25 nit: "profile" -> "Chrome profile", just for clari
rchtara 2014/05/22 08:44:38 Done.
+ passwords_path: The usernames and passwords file.
+ enable_automatic_password_saving: If set, the passwords are going to be
+ saved without showing the prompt.
+ numeric_level: The log numeric level.
vabr (Chromium) 2014/05/20 14:47:25 nit: "log" -> "log verbosity"
rchtara 2014/05/22 08:44:38 Done.
+ log_screen: If set, the tests log is going to be shown on the screen.
vabr (Chromium) 2014/05/20 14:47:25 nit: change "screen" to console also in the commen
vabr (Chromium) 2014/05/20 14:47:25 nit: "tests log is going to be" -> "debug logs wil
vabr (Chromium) 2014/05/20 14:47:25 nit: "set" -> "true"
rchtara 2014/05/22 08:44:38 Done.
rchtara 2014/05/22 08:44:38 Done.
rchtara 2014/05/22 08:44:38 Done.
+ log_file: The file where to store the log.
vabr (Chromium) 2014/05/20 14:47:25 nit: Comment on what happens if it is empty.
rchtara 2014/05/22 08:44:38 Done.
+
+ Raises:
+ Exception: An exception is raised if |profile_path| folder could not be
+ removed.
+ """
+ # Setting up the login.
+ if numeric_level is not None:
+ if log_file:
+ # Set up logging to file.
+ logging.basicConfig(level=numeric_level,
+ filename=log_file,
+ filemode='w')
+
+ if log_screen:
+ console = logging.StreamHandler()
+ console.setLevel(numeric_level)
+ # Add the handler to the root logger.
+ logging.getLogger('').addHandler(console)
+
+ elif log_screen:
+ logging.basicConfig(level=numeric_level)
+
+ # Cleaning the profile folder.
+ try:
+ shutil.rmtree(profile_path)
+ except Exception, e:
+ # The tests execution can continue, but this make them less stable.
+ logging.error("""Error: %s.\n The tests execution is continuing. But
vabr (Chromium) 2014/05/20 14:47:25 I don't think you use """ correctly here. If you o
rchtara 2014/05/22 08:44:38 Done.
+ the tests are going to be less stable.""" % e)
vabr (Chromium) 2014/05/20 14:47:25 Please be more specific: write what is the error,
rchtara 2014/05/22 08:44:38 Done.
+ options = Options()
+ if enable_automatic_password_saving:
+ options.add_argument("enable-automatic-password-saving")
+ options.add_argument("enable-password-manager-internals-ui")
vabr (Chromium) 2014/05/20 14:47:25 You probably missed my comment earlier: enable-pas
rchtara 2014/05/22 08:44:38 I didn't update my chromium yet, so I will keep us
+ # Chrome path.
+ options.binary_location = chrome_path
+ # Testing profile path.
+ options.add_argument("user-data-dir=%s" % profile_path)
+
+ # The webdriver. It's possible to choose the port the service is going to
+ # run on. If it's left to 0, a free port will be found.
+ self.driver = webdriver.Chrome(chromedriver_path, 0, options)
+ # The password internals window.
+ self.internals_window = self.driver.current_window_handle
+ # Password internals page.
+ self.internals_page = "chrome://password-manager-internals/"
+ # The Website window.
+ self.website_window = None
+ # The WebsiteTests list.
+ self.websitetests = []
+ # An xml tree filled with logins and passwords.
+ self.passwords_tree = None
+ if passwords_path:
+ self.passwords_tree = ElementTree.parse(passwords_path).getroot()
+ # The enabled WebsiteTests list.
+ self.working_tests = []
+ # The number of the save operations done through all the tests.
+ self.save_count = 0
vabr (Chromium) 2014/05/20 14:47:25 Note: I see you use this to deal with the internal
rchtara 2014/05/22 08:44:38 No, it's going make it harder, because I will need
+ # Show whether or not it's the first time to execute GoTo.
vabr (Chromium) 2014/05/20 14:47:25 "Show"? It's not clear how and to whom this is sho
rchtara 2014/05/22 08:44:38 Done.
+ self.first_go_to = True
+
+ def AddWebsiteTest(self, websitetest, disabled=False):
+ """Adds a WebsiteTest to the testing Environment.
+
+ Args:
+ websitetest: The WebsiteTest instance that's going to be added to the
vabr (Chromium) 2014/05/20 14:47:25 nit: You can simply write: "The WebsiteTest instan
rchtara 2014/05/22 08:44:38 Done.
+ testing Environment.
+ disabled: Test is disabled.
vabr (Chromium) 2014/05/20 14:47:25 nit: Whether test is disabled.
rchtara 2014/05/22 08:44:38 Done.
+ """
+ websitetest.environment = self
+ websitetest.driver = self.driver
+ if self.passwords_tree is not None:
+ if not websitetest.username:
+ username_tag = (
+ self.passwords_tree.find(
+ ".//*[@name='%s']/username" % websitetest.name))
+ if username_tag.text:
+ websitetest.username = username_tag.text
+ if not websitetest.password:
+ password_tag = (
+ self.passwords_tree.find(
+ ".//*[@name='%s']/password" % websitetest.name))
+ if password_tag.text:
+ websitetest.password = password_tag.text
+ self.websitetests.append(websitetest)
+ if not disabled:
+ self.working_tests.append(websitetest.name)
+
+ def RemoveAllPasswords(self):
+ """Removes all the stored passwords."""
+ logging.info("\nRemoveAllPasswords\n")
+ self.driver.get("chrome://settings/passwords")
+ self.driver.switch_to_frame("settings")
+ while True:
+ try:
+ self.driver.execute_script("document.querySelector('"
+ "#saved-passwords-list .row-delete-button').click()")
+ time.sleep(1)
+ except NoSuchElementException:
+ break
+ except WebDriverException:
+ break
+
+ def OpenTabAndGoToInternals(self, url):
+ """If there is no |self.website_window|, opens a new tab and navigates to
+ |url| in the new tab. Navigates to the passwords internals page in the
+ first tab. Raises an exception otherwise.
vabr (Chromium) 2014/05/20 14:47:25 It's not clear what "otherwise" refers to. I belie
rchtara 2014/05/22 08:44:38 Done.
+
+ Args:
+ url: Url to go to in the new tab.
+
+ Raises:
+ Exception: An exception is raised if |self.website_window| already exists.
+ """
+ if not self.website_window:
vabr (Chromium) 2014/05/20 14:47:25 nit: Consider starting with if self.website_window
rchtara 2014/05/22 08:44:38 Done.
+ self.driver.get("chrome://newtab")
+ # There is no straightforward way to open a new tab with chromedriver.
+ # One work-around is to go to a website, insert a link that is going
+ # to be opened in a new tab, click on it.
+ a = self.driver.execute_script(
+ "var a = document.createElement('a');"
+ "a.target = '_blank';"
+ "a.href = arguments[0];"
+ "a.innerHTML = '.';"
+ "document.body.appendChild(a);"
+ "return a;",
+ url)
+
+ a.click()
+ time.sleep(1)
+
+ self.website_window = self.driver.window_handles[-1]
+ self.driver.get(self.internals_page)
+ self.driver.switch_to_window(self.website_window)
+ else:
+ raise Exception("Error: The window was already opened.")
+
+ def SwitchToInternals(self):
+ """Switches from the Website window to internals tab."""
+ self.driver.switch_to_window(self.internals_window)
+
+ def SwitchFromInternals(self):
+ """Switches from internals tab to the Website window."""
+ self.driver.switch_to_window(self.website_window)
+
+ def CheckPrompt(self, log_message, prompt_should_show_up,
+ error_message, timeout=10):
+ """Detects whether the save password prompt is shown, and raises an
+ exception if the result does not match the expectation.
+
+ Args:
+ log_message: Log message to look for in the password internals.
+ prompt_should_show_up: Whether or not the prompt is expected to be shown.
+ error_message: Error message for the exception .
vabr (Chromium) 2014/05/20 14:47:25 nit: Remove the two spaces at the end of the sente
rchtara 2014/05/22 08:44:38 Done.
+ timeout: There is some delay between the login and the password
+ internals update. The method checks periodically during the first
+ |timeout| seconds if the internals page reports the prompt being
+ shown. If the prompt is not reported shown within the first
+ |timeout| seconds, it is considered not shown at all.
+
+ Raises:
+ Exception: An exception is raised in case there is a problem.
vabr (Chromium) 2014/05/20 14:47:25 nit: "there is a problem" -> "the result does not
rchtara 2014/05/22 08:44:38 Done.
+ """
+ if prompt_should_show_up:
+ self.save_count += 1
+ log = self.driver.find_element_by_css_selector("#log-entries")
+ count = log.text.count(log_message)
+
+ if count < self.save_count and timeout > 0:
+ time.sleep(1)
+ self.CheckPrompt(log_message, False, error_message, timeout - 1)
vabr (Chromium) 2014/05/20 14:47:25 You hard-code False as the "prompt_should_show_up"
rchtara 2014/05/22 08:44:38 Done.
+
+ elif not self.save_count == count:
+ raise Exception(error_message)
+
+ def AllTests(self, prompt_test):
+ """Runs the tests on all the WebsiteTests.
vabr (Chromium) 2014/05/20 14:47:25 typo: two consequent spaces between "the" and "Web
rchtara 2014/05/22 08:44:38 Done.
+
+ Args:
+ prompt_test: Prompt tests or normal tests.
vabr (Chromium) 2014/05/20 14:47:25 Please explain what are "prompt tests". The most p
rchtara 2014/05/22 08:44:38 Done.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ if prompt_test:
+ self.PromptTestList(self.websitetests)
+ else:
+ self.TestList(self.websitetests)
+
+ def WorkingTests(self, prompt_test):
+ """Runs the tests on all the enabled WebsiteTests.
+
+ Args:
+ prompt_test: Prompt tests or normal tests.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.Test(self.working_tests, prompt_test)
+
+ def Test(self, tests, prompt_test):
+ """Runs the tests on many WebsiteTests.
vabr (Chromium) 2014/05/20 14:47:25 many WebsiteTests -> websites named in |tests| Al
rchtara 2014/05/22 08:44:38 Done.
+
+ Args:
+ tests: A list of the names of the WebsiteTests that are going to be
+ tested.
+ prompt_test: Prompt tests or normal tests.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ websitetests = []
+ for websitetest in self.websitetests:
+ if websitetest.name in tests:
+ websitetests.append(websitetest)
+
+ if prompt_test:
+ self.PromptTestList(websitetests)
+ else:
+ self.TestList(websitetests)
+
+ def TestList(self, websitetests):
+ """Runs the tests on many WebsiteTests.
+
+ Args:
+ websitetests: A list of WebsiteTests that are going to be tested.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.RemoveAllPasswords()
+
+ for websitetest in websitetests:
+ websitetest.WrongLoginTest()
+ websitetest.SuccessfulLoginTest()
+ websitetest.SuccessfulLoginWithAutofilledPasswordTest()
+
+ self.RemoveAllPasswords()
+ for websitetest in websitetests:
+ websitetest.SuccessfulLoginTest()
+
+ def PromptTestList(self, websitetests):
+ """Runs the prompt tests on many WebsiteTests.
+
+ Args:
+ websitetests: A list of WebsiteTests that are going to be tested.
+
+ Raises:
+ Exception: An exception is raised if the tests fail.
+ """
+ self.RemoveAllPasswords()
+
+ for websitetest in websitetests:
+ websitetest.PromptTest()
+
+ def Quit(self):
+ """Closes the tests."""
+ # Close the webdriver.
+ self.driver.quit()

Powered by Google App Engine
This is Rietveld 408576698