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

Side by Side 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: rev 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 unified diff | Download patch
OLDNEW
(Empty)
1 """The testing Environment class."""
2
3 import logging
4 import shutil
5 import time
6
7 from selenium import webdriver
8 from selenium.common.exceptions import NoSuchElementException
9 from selenium.common.exceptions import WebDriverException
10 from selenium.webdriver.chrome.options import Options
11 from xml.etree import ElementTree
12
13
14 class Environment:
15 """Sets up the testing Environment. """
16
17 def __init__(self, chrome_path, chromedriver_path, profile_path,
18 passwords_path, enable_automatic_password_saving,
19 numeric_level=None, log_to_console=False, log_file=""):
20 """Creates a new testing Environment.
21
22 Args:
23 chrome_path: The chrome binary file.
24 chromedriver_path: The chromedriver binary file.
25 profile_path: The chrome testing profile folder.
26 passwords_path: The usernames and passwords file.
27 enable_automatic_password_saving: If True, the passwords are going to be
28 saved without showing the prompt.
29 numeric_level: The log verbosity.
30 log_to_console: If True, the debug logs will be shown on the console.
31 log_file: The file where to store the log. If it's empty, the log will
32 not be stored.
33
34 Raises:
35 Exception: An exception is raised if |profile_path| folder could not be
36 removed.
37 """
38 # Setting up the login.
39 if numeric_level is not None:
40 if log_file:
41 # Set up logging to file.
42 logging.basicConfig(level=numeric_level,
43 filename=log_file,
44 filemode='w')
45
46 if log_to_console:
47 console = logging.StreamHandler()
48 console.setLevel(numeric_level)
49 # Add the handler to the root logger.
50 logging.getLogger('').addHandler(console)
51
52 elif log_to_console:
53 logging.basicConfig(level=numeric_level)
54
55 # Cleaning the chrome testing profile folder.
56 try:
57 shutil.rmtree(profile_path)
58 except Exception, e:
59 # The tests execution can continue, but this make them less stable.
60 logging.error("Error: Could not wipe the chrome profile directory (%s). \
61 This affects the stability of the tests. Continuing to run tests."
62 % e)
63 options = Options()
64 if enable_automatic_password_saving:
65 options.add_argument("enable-automatic-password-saving")
66 options.add_argument("enable-password-manager-internals-ui")
67 # Chrome path.
68 options.binary_location = chrome_path
69 # Chrome testing profile path.
70 options.add_argument("user-data-dir=%s" % profile_path)
71
72 # The webdriver. It's possible to choose the port the service is going to
73 # run on. If it's left to 0, a free port will be found.
74 self.driver = webdriver.Chrome(chromedriver_path, 0, options)
75 # The password internals window.
76 self.internals_window = self.driver.current_window_handle
77 # Password internals page.
78 self.internals_page = "chrome://password-manager-internals/"
79 # The Website window.
80 self.website_window = None
81 # The WebsiteTests list.
82 self.websitetests = []
83 # An xml tree filled with logins and passwords.
84 self.passwords_tree = None
85 if passwords_path:
86 self.passwords_tree = ElementTree.parse(passwords_path).getroot()
87 # The enabled WebsiteTests list.
88 self.working_tests = []
89 # The number of the save operations done through all the tests.
90 self.save_count = 0
91 # The tests needs two tabs to work. A new tab is opened with the first
92 # GoTo. This is why we store here whether or not it's the first time to
93 # execute GoTo.
94 self.first_go_to = True
95
96 def AddWebsiteTest(self, websitetest, disabled=False):
97 """Adds a WebsiteTest to the testing Environment.
98
99 Args:
100 websitetest: The WebsiteTest instance to be added.
101 disabled: Whether test is disabled.
102 """
103 websitetest.environment = self
104 websitetest.driver = self.driver
105 if self.passwords_tree is not None:
106 if not websitetest.username:
107 username_tag = (
108 self.passwords_tree.find(
109 ".//*[@name='%s']/username" % websitetest.name))
110 if username_tag.text:
111 websitetest.username = username_tag.text
112 if not websitetest.password:
113 password_tag = (
114 self.passwords_tree.find(
115 ".//*[@name='%s']/password" % websitetest.name))
116 if password_tag.text:
117 websitetest.password = password_tag.text
118 self.websitetests.append(websitetest)
119 if not disabled:
120 self.working_tests.append(websitetest.name)
121
122 def RemoveAllPasswords(self):
123 """Removes all the stored passwords."""
124 logging.info("\nRemoveAllPasswords\n")
125 self.driver.get("chrome://settings/passwords")
126 self.driver.switch_to_frame("settings")
127 while True:
128 try:
129 self.driver.execute_script("document.querySelector('"
130 "#saved-passwords-list .row-delete-button').click()")
131 time.sleep(1)
132 except NoSuchElementException:
133 break
134 except WebDriverException:
135 break
136
137 def OpenTabAndGoToInternals(self, url):
138 """If there is no |self.website_window|, opens a new tab and navigates to
139 |url| in the new tab. Navigates to the passwords internals page in the
140 first tab. Raises an exception otherwise.
141
142 Args:
143 url: Url to go to in the new tab.
144
145 Raises:
146 Exception: An exception is raised if |self.website_window| already
147 exists.
148 """
149 if self.website_window:
150 raise Exception("Error: The window was already opened.")
151 else:
vabr (Chromium) 2014/05/22 10:07:02 nit: remove "else" (and indent the code below 2 co
rchtara 2014/05/22 12:42:01 Done.
152 self.driver.get("chrome://newtab")
153 # There is no straightforward way to open a new tab with chromedriver.
154 # One work-around is to go to a website, insert a link that is going
155 # to be opened in a new tab, click on it.
156 a = self.driver.execute_script(
157 "var a = document.createElement('a');"
158 "a.target = '_blank';"
159 "a.href = arguments[0];"
160 "a.innerHTML = '.';"
161 "document.body.appendChild(a);"
162 "return a;",
163 url)
164
165 a.click()
166 time.sleep(1)
167
168 self.website_window = self.driver.window_handles[-1]
169 self.driver.get(self.internals_page)
170 self.driver.switch_to_window(self.website_window)
171
172 def SwitchToInternals(self):
173 """Switches from the Website window to internals tab."""
174 self.driver.switch_to_window(self.internals_window)
175
176 def SwitchFromInternals(self):
177 """Switches from internals tab to the Website window."""
178 self.driver.switch_to_window(self.website_window)
179
180 def _WaitUntilPromptAppear(self, log_message, timeout):
vabr (Chromium) 2014/05/22 10:07:02 Please add a documentation comment for this method
vabr (Chromium) 2014/05/22 10:07:02 Maybe rename to _DidPromptAppearUntilTimeout to em
rchtara 2014/05/22 12:42:01 Done.
rchtara 2014/05/22 12:42:01 Done.
181 log = self.driver.find_element_by_css_selector("#log-entries")
182 count = log.text.count(log_message)
183 if count > self.save_count:
184 return True
vabr (Chromium) 2014/05/22 10:07:02 What about adding self.save_count = count before "
rchtara 2014/05/22 12:42:01 Done.
185 elif timeout > 0:
186 time.sleep(1)
187 return self._WaitUntilPromptAppear(log_message, timeout - 1)
188 else:
189 return False
190
191 def CheckPrompt(self, log_message, prompt_should_show_up,
192 error_message, timeout=3):
193 """Detects whether the save password prompt is shown.
194
195 Args:
196 log_message: Log message to look for in the password internals.
197 prompt_should_show_up: Whether or not the prompt is expected to be shown.
198 error_message: Error message for the exception.
199 timeout: There is some delay between the login and the password
200 internals update. The method checks periodically during the first
201 |timeout| seconds if the internals page reports the prompt being
202 shown. If the prompt is not reported shown within the first
203 |timeout| seconds, it is considered not shown at all.
204
205 Raises:
206 Exception: An exception is raised in case the result does not match the
207 expectation
208 """
209 if (self._WaitUntilPromptAppear(log_message, timeout) ==
210 prompt_should_show_up):
211 if prompt_should_show_up:
212 self.save_count += 1
213 else:
214 raise Exception(error_message)
215
216 def AllTests(self, prompt_test):
217 """Runs the tests on all the WebsiteTests.
218
219 Args:
220 prompt_test: If True, tests caring about the save-password prompt are
vabr (Chromium) 2014/05/22 10:07:02 nit: "caring about the save-password prompt" -> "c
rchtara 2014/05/22 12:42:01 Done.
221 going to be ran, otherwise tests which don't are going to be
vabr (Chromium) 2014/05/22 10:07:02 typu: ran -> run
vabr (Chromium) 2014/05/22 10:07:02 nit: "don't" -> "don't care about the prompt"
rchtara 2014/05/22 12:42:01 Done.
rchtara 2014/05/22 12:42:01 Done.
222 executed.
223
224 Raises:
225 Exception: An exception is raised if the tests fail.
226 """
227 if prompt_test:
228 self.PromptTestList(self.websitetests)
229 else:
230 self.TestList(self.websitetests)
231
232 def WorkingTests(self, prompt_test):
233 """Runs the tests on all the enabled WebsiteTests.
234
235 Args:
236 prompt_test: If True, tests caring about the save-password prompt are
vabr (Chromium) 2014/05/22 10:07:02 Please apply the changes to the explanation of pro
rchtara 2014/05/22 12:42:01 Done.
237 going to be ran, otherwise tests which don't are going to be
238 executed.
239
240 Raises:
241 Exception: An exception is raised if the tests fail.
242 """
243 self.Test(self.working_tests, prompt_test)
244
245 def Test(self, tests, prompt_test):
246 """Runs the tests on websites named in |tests|.
247
248 Args:
249 tests: A list of the names of the WebsiteTests that are going to be
250 tested.
251 prompt_test: If True, tests caring about the save-password prompt are
252 going to be ran, otherwise tests which don't are going to be
253 executed.
254
255 Raises:
256 Exception: An exception is raised if the tests fail.
257 """
258 websitetests = []
259 for websitetest in self.websitetests:
260 if websitetest.name in tests:
261 websitetests.append(websitetest)
262
263 if prompt_test:
264 self.PromptTestList(websitetests)
265 else:
266 self.TestList(websitetests)
267
268 def TestList(self, websitetests):
269 """Runs the tests on the websites in |websitetests|.
270
271 Args:
272 websitetests: A list of WebsiteTests that are going to be tested.
273
274 Raises:
275 Exception: An exception is raised if the tests fail.
276 """
277 self.RemoveAllPasswords()
278
279 for websitetest in websitetests:
280 websitetest.WrongLoginTest()
281 websitetest.SuccessfulLoginTest()
282 websitetest.SuccessfulLoginWithAutofilledPasswordTest()
283
284 self.RemoveAllPasswords()
285 for websitetest in websitetests:
286 websitetest.SuccessfulLoginTest()
287
288 def PromptTestList(self, websitetests):
289 """Runs the prompt tests on the websites in |websitetests|.
290
291 Args:
292 websitetests: A list of WebsiteTests that are going to be tested.
293
294 Raises:
295 Exception: An exception is raised if the tests fail.
296 """
297 self.RemoveAllPasswords()
298
299 for websitetest in websitetests:
300 websitetest.PromptTest()
301
302 def Quit(self):
303 """Closes the tests."""
304 # Close the webdriver.
305 self.driver.quit()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698