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

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: 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 # Chrome path.
67 options.binary_location = chrome_path
68 # Chrome testing profile path.
69 options.add_argument("user-data-dir=%s" % profile_path)
70
71 # The webdriver. It's possible to choose the port the service is going to
72 # run on. If it's left to 0, a free port will be found.
73 self.driver = webdriver.Chrome(chromedriver_path, 0, options)
74 # The password internals window.
75 self.internals_window = self.driver.current_window_handle
76 # Password internals page.
77 self.internals_page = "chrome://password-manager-internals/"
78 # The Website window.
79 self.website_window = None
80 # The WebsiteTests list.
81 self.websitetests = []
82 # An xml tree filled with logins and passwords.
83 self.passwords_tree = ElementTree.parse(passwords_path).getroot()
84 # The enabled WebsiteTests list.
85 self.working_tests = []
86 # Map messages to the number of their appearance in the log.
87 self.message_count = dict()
88 self.message_count["Message: Decision: ASK the user"] = 0
vabr (Chromium) 2014/05/22 15:46:24 nit: Since you provide the strings on multiple pla
rchtara 2014/05/22 16:22:26 Done.
89 self.message_count["Message: Decision: SAVE the password"] = 0
90 # The tests needs two tabs to work. A new tab is opened with the first
91 # GoTo. This is why we store here whether or not it's the first time to
92 # execute GoTo.
93 self.first_go_to = True
94
95 def AddWebsiteTest(self, websitetest, disabled=False):
96 """Adds a WebsiteTest to the testing Environment.
97
98 Args:
99 websitetest: The WebsiteTest instance to be added.
100 disabled: Whether test is disabled.
101 """
102 websitetest.environment = self
103 websitetest.driver = self.driver
104 if self.passwords_tree is not None:
105 if not websitetest.username:
106 username_tag = (
107 self.passwords_tree.find(
108 ".//*[@name='%s']/username" % websitetest.name))
109 if username_tag.text:
110 websitetest.username = username_tag.text
111 if not websitetest.password:
112 password_tag = (
113 self.passwords_tree.find(
114 ".//*[@name='%s']/password" % websitetest.name))
115 if password_tag.text:
116 websitetest.password = password_tag.text
117 self.websitetests.append(websitetest)
118 if not disabled:
119 self.working_tests.append(websitetest.name)
120
121 def RemoveAllPasswords(self):
122 """Removes all the stored passwords."""
123 logging.info("\nRemoveAllPasswords\n")
124 self.driver.get("chrome://settings/passwords")
125 self.driver.switch_to_frame("settings")
126 while True:
127 try:
128 self.driver.execute_script("document.querySelector('"
129 "#saved-passwords-list .row-delete-button').click()")
130 time.sleep(1)
131 except NoSuchElementException:
132 break
133 except WebDriverException:
134 break
135
136 def OpenTabAndGoToInternals(self, url):
137 """If there is no |self.website_window|, opens a new tab and navigates to
138 |url| in the new tab. Navigates to the passwords internals page in the
139 first tab. Raises an exception otherwise.
140
141 Args:
142 url: Url to go to in the new tab.
143
144 Raises:
145 Exception: An exception is raised if |self.website_window| already
146 exists.
147 """
148 if self.website_window:
149 raise Exception("Error: The window was already opened.")
150
151 self.driver.get("chrome://newtab")
152 # There is no straightforward way to open a new tab with chromedriver.
153 # One work-around is to go to a website, insert a link that is going
154 # to be opened in a new tab, click on it.
155 a = self.driver.execute_script(
156 "var a = document.createElement('a');"
157 "a.target = '_blank';"
158 "a.href = arguments[0];"
159 "a.innerHTML = '.';"
160 "document.body.appendChild(a);"
161 "return a;",
162 url)
163
164 a.click()
165 time.sleep(1)
166
167 self.website_window = self.driver.window_handles[-1]
168 self.driver.get(self.internals_page)
169 self.driver.switch_to_window(self.website_window)
170
171 def SwitchToInternals(self):
172 """Switches from the Website window to internals tab."""
173 self.driver.switch_to_window(self.internals_window)
174
175 def SwitchFromInternals(self):
176 """Switches from internals tab to the Website window."""
177 self.driver.switch_to_window(self.website_window)
178
179 def _DidMessageAppearUntilTimeout(self, log_message, timeout):
180 """Checks whether the save password prompt is shown.
181
182 Args:
183 log_message: Log message to look for in the password internals.
184 timeout: There is some delay between the login and the password
185 internals update. The method checks periodically during the first
186 |timeout| seconds if the internals page reports the prompt being
187 shown. If the prompt is not reported shown within the first
188 |timeout| seconds, it is considered not shown at all.
189
190 Returns:
191 True if the save password prompt is shown.
192 False otherwise.
193 """
194 log = self.driver.find_element_by_css_selector("#log-entries")
195 count = log.text.count(log_message)
196
197 if count > self.message_count[log_message]:
198 self.message_count[log_message] = count
199 return True
200 elif timeout > 0:
201 time.sleep(1)
202 return self._DidMessageAppearUntilTimeout(log_message, timeout - 1)
203 else:
204 return False
205
206 def CheckForNewMessage(self, log_message, message_should_show_up,
207 error_message, timeout=3):
208 """Detects whether the save password prompt is shown.
209
210 Args:
211 log_message: Log message to look for in the password internals.
vabr (Chromium) 2014/05/22 15:46:24 Because for arbitrary messages this will throw an
rchtara 2014/05/22 16:22:26 Done.
212 message_should_show_up: Whether or not the message is expected to be shown .
213 error_message: Error message for the exception.
214 timeout: There is some delay between the login and the password
215 internals update. The method checks periodically during the first
216 |timeout| seconds if the internals page reports the prompt being
217 shown. If the prompt is not reported shown within the first
218 |timeout| seconds, it is considered not shown at all.
219
220 Raises:
221 Exception: An exception is raised in case the result does not match the
222 expectation
223 """
224 if (self._DidMessageAppearUntilTimeout(log_message, timeout) !=
225 message_should_show_up):
226 raise Exception(error_message)
227
228 def AllTests(self, prompt_test):
229 """Runs the tests on all the WebsiteTests.
230
231 Args:
232 prompt_test: If True, tests caring about showing the save-password
233 prompt are going to be run, otherwise tests which don't care about
234 the prompt are going to be run.
235
236 Raises:
237 Exception: An exception is raised if the tests fail.
238 """
239 if prompt_test:
240 self.PromptTestList(self.websitetests)
241 else:
242 self.TestList(self.websitetests)
243
244 def WorkingTests(self, prompt_test):
245 """Runs the tests on all the enabled WebsiteTests.
246
247 Args:
248 prompt_test: If True, tests caring about showing the save-password
249 prompt are going to be run, otherwise tests which don't care about
250 the prompt are going to be executed.
251
252 Raises:
253 Exception: An exception is raised if the tests fail.
254 """
255 self.Test(self.working_tests, prompt_test)
256
257 def Test(self, tests, prompt_test):
258 """Runs the tests on websites named in |tests|.
259
260 Args:
261 tests: A list of the names of the WebsiteTests that are going to be
262 tested.
263 prompt_test: If True, tests caring about showing the save-password
264 prompt are going to be run, otherwise tests which don't care about
265 the prompt are going to be executed.
266
267 Raises:
268 Exception: An exception is raised if the tests fail.
269 """
270 websitetests = []
271 for websitetest in self.websitetests:
272 if websitetest.name in tests:
273 websitetests.append(websitetest)
274
275 if prompt_test:
276 self.PromptTestList(websitetests)
277 else:
278 self.TestList(websitetests)
279
280 def TestList(self, websitetests):
281 """Runs the tests on the websites in |websitetests|.
282
283 Args:
284 websitetests: A list of WebsiteTests that are going to be tested.
285
286 Raises:
287 Exception: An exception is raised if the tests fail.
288 """
289 self.RemoveAllPasswords()
290
291 for websitetest in websitetests:
292 websitetest.WrongLoginTest()
293 websitetest.SuccessfulLoginTest()
294 websitetest.SuccessfulLoginWithAutofilledPasswordTest()
295
296 self.RemoveAllPasswords()
297 for websitetest in websitetests:
298 websitetest.SuccessfulLoginTest()
299
300 def PromptTestList(self, websitetests):
301 """Runs the prompt tests on the websites in |websitetests|.
302
303 Args:
304 websitetests: A list of WebsiteTests that are going to be tested.
305
306 Raises:
307 Exception: An exception is raised if the tests fail.
308 """
309 self.RemoveAllPasswords()
310
311 for websitetest in websitetests:
312 websitetest.PromptTest()
313
314 def Quit(self):
315 """Closes the tests."""
316 # Close the webdriver.
317 self.driver.quit()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698