1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
from telemetry import decorators
import py_utils
class FormBasedCredentialsBackend(object):
def __init__(self):
self._logged_in = False
def IsAlreadyLoggedIn(self, tab):
return tab.EvaluateJavaScript(self.logged_in_javascript)
@property
def credentials_type(self):
raise NotImplementedError()
@property
def url(self):
raise NotImplementedError()
@property
def login_form_id(self):
raise NotImplementedError()
@property
def login_button_javascript(self):
"""Some sites have custom JS to log in."""
return None
@property
def login_input_id(self):
raise NotImplementedError()
@property
def password_input_id(self):
raise NotImplementedError()
@property
def logged_in_javascript(self):
"""Evaluates to true iff already logged in."""
raise NotImplementedError()
def IsLoggedIn(self):
return self._logged_in
def _ResetLoggedInState(self):
"""Makes the backend think we're not logged in even though we are.
Should only be used in unit tests to simulate --dont-override-profile.
"""
self._logged_in = False
def _WaitForLoginState(self, action_runner):
"""Waits until it can detect either the login form, or already logged in."""
action_runner.WaitForJavaScriptCondition(
'(document.querySelector({{ form_id }}) !== null) || ({{ @code }})',
form_id='#' + self.login_form_id, code=self.logged_in_javascript,
timeout_in_seconds=60)
def _SubmitLoginFormAndWait(self, action_runner, tab, username, password):
"""Submits the login form and waits for the navigation."""
tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
# TODO(catapult:#3028): Fix interpolation of JavaScript values.
email_id = 'document.querySelector("#%s #%s").value = "%s"; ' % (
self.login_form_id, self.login_input_id, username)
password = 'document.querySelector("#%s #%s").value = "%s"; ' % (
self.login_form_id, self.password_input_id, password)
tab.ExecuteJavaScript(email_id)
tab.ExecuteJavaScript(password)
if self.login_button_javascript:
tab.ExecuteJavaScript(self.login_button_javascript)
else:
# TODO(catapult:#3028): Fix interpolation of JavaScript values.
tab.ExecuteJavaScript(
'document.getElementById("%s").submit();' % self.login_form_id)
# Wait for the form element to disappear as confirmation of the navigation.
action_runner.WaitForNavigate()
# pylint: disable=line-too-long
@decorators.Deprecated(2017, 5, 5,
'FormBasedCredentialsBackend is deprecated. Use the '
'login helper modules in '
'https://code.google.com/p/chromium/codesearch#chromium/src/tools/perf/page_sets/login_helpers/'
' instead.')
# pylint: enable=line-too-long
def LoginNeeded(self, tab, action_runner, config):
"""Logs in to a test account.
Raises:
RuntimeError: if could not get credential information.
"""
if self._logged_in:
return True
if 'username' not in config or 'password' not in config:
message = ('Credentials for "%s" must include username and password.' %
self.credentials_type)
raise RuntimeError(message)
logging.debug('Logging into %s account...' % self.credentials_type)
if 'url' in config:
url = config['url']
else:
url = self.url
try:
logging.info('Loading %s...', url)
tab.Navigate(url)
self._WaitForLoginState(action_runner)
if self.IsAlreadyLoggedIn(tab):
self._logged_in = True
return True
self._SubmitLoginFormAndWait(
action_runner, tab, config['username'], config['password'])
self._logged_in = True
return True
except py_utils.TimeoutException:
logging.warning('Timed out while loading: %s', url)
return False
def LoginNoLongerNeeded(self, tab): # pylint: disable=unused-argument
assert self._logged_in
|