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

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

Powered by Google App Engine
This is Rietveld 408576698