Implements RLZTrackerDelegate on iOS.
[chromium-blink-merge.git] / components / proximity_auth / e2e_test / setup_test.py
blob7ef26947fdf02fccf3644da0aabd0a398c5c51ed
1 # Copyright 2015 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.
5 """ Script that exercises the Smart Lock setup flow, testing that a nearby phone
6 can be found and used to unlock a Chromebook.
8 Note: This script does not currently automate Android phones, so make sure that
9 a phone is properly configured and online before starting the test.
11 Usage:
12 python setup_test.py --remote_address REMOTE_ADDRESS
13 --username USERNAME
14 --password PASSWORD
15 [--app_path APP_PATH]
16 [--ssh_port SSH_PORT]
17 [--cryptauth_staging_url STAGING_URL]
18 If |--app_path| is provided, then a copy of the Smart Lock app on the local
19 machine will be used instead of the app on the ChromeOS device.
20 """
22 import argparse
23 import cros
24 import cryptauth
25 import logging
26 import os
27 import subprocess
28 import sys
29 import tempfile
31 logger = logging.getLogger('proximity_auth.%s' % __name__)
33 class SmartLockSetupError(Exception):
34 pass
36 def pingable_address(address):
37 try:
38 subprocess.check_output(['ping', '-c', '1', '-W', '1', address])
39 except subprocess.CalledProcessError:
40 raise argparse.ArgumentError('%s cannot be reached.' % address)
41 return address
43 def email(arg):
44 tokens = arg.lower().split('@')
45 if len(tokens) != 2 or '.' not in tokens[1]:
46 raise argparse.ArgumentError('%s is not a valid email address' % arg)
47 name, domain = tokens
48 if domain == 'gmail.com':
49 name = name.replace('.', '')
50 return '@'.join([name, domain])
52 def directory(path):
53 if not os.path.isdir(path):
54 raise argparse.ArgumentError('%s is not a directory' % path)
55 return path
57 def ParseArgs():
58 parser = argparse.ArgumentParser(prog='python setup_test.py')
59 parser.add_argument('--remote_address', required=True, type=pingable_address)
60 parser.add_argument('--username', required=True, type=email)
61 parser.add_argument('--password', required=True)
62 parser.add_argument('--ssh_port', type=int)
63 parser.add_argument('--app_path', type=directory)
64 parser.add_argument('--cryptauth_staging_url', type=str)
65 args = parser.parse_args()
66 return args
68 def CheckCryptAuthState(access_token):
69 cryptauth_client = cryptauth.CryptAuthClient(access_token)
71 # Check if we can make CryptAuth requests.
72 if cryptauth_client.GetMyDevices() is None:
73 logger.error('Cannot reach CryptAuth on test machine.')
74 return False
76 if cryptauth_client.GetUnlockKey() is not None:
77 logger.info('Smart Lock currently enabled, turning off on Cryptauth...')
78 if not cryptauth_client.ToggleEasyUnlock(False):
79 logger.error('ToggleEasyUnlock request failed.')
80 return False
82 result = cryptauth_client.FindEligibleUnlockDevices()
83 if result is None:
84 logger.error('FindEligibleUnlockDevices request failed')
85 return False
86 eligibleDevices, _ = result
87 if len(eligibleDevices) == 0:
88 logger.warn('No eligible phones found, trying to ping phones...')
89 result = cryptauth_client.PingPhones()
90 if result is None or not len(result[0]):
91 logger.error('Pinging phones failed :(')
92 return False
93 else:
94 logger.info('Pinging phones succeeded!')
95 else:
96 logger.info('Found eligible device: %s' % (
97 eligibleDevices[0]['friendlyDeviceName']))
98 return True
100 def _NavigateSetupDialog(chromeos, app):
101 logger.info('Scanning for nearby phones...')
102 btmon = chromeos.RunBtmon()
103 find_phone_success = app.FindPhone()
104 btmon.terminate()
106 if not find_phone_success:
107 fd, filepath = tempfile.mkstemp(prefix='btmon-')
108 os.write(fd, btmon.stdout.read())
109 os.close(fd)
110 logger.info('Logs for btmon can be found at %s' % filepath)
111 raise SmartLockSetupError("Failed to find nearby phone.")
113 logger.info('Phone found! Starting pairing...')
114 if not app.PairPhone():
115 raise SmartLockSetupError("Failed to pair with phone.")
116 logger.info('Pairing success! Starting trial run...')
117 app.StartTrialRun()
119 logger.info('Unlocking for trial run...')
120 lock_screen = chromeos.GetAccountPickerScreen()
121 lock_screen.WaitForSmartLockState(
122 lock_screen.SmartLockState.AUTHENTICATED)
123 lock_screen.UnlockWithClick()
125 logger.info('Trial run success! Dismissing app...')
126 app.DismissApp()
128 def RunSetupTest(args):
129 logger.info('Starting test for %s at %s' % (
130 args.username, args.remote_address))
131 if args.app_path is not None:
132 logger.info('Replacing Smart Lock app with %s' % args.app_path)
134 chromeos = cros.ChromeOS(
135 args.remote_address, args.username, args.password, ssh_port=args.ssh_port)
136 with chromeos.Start(local_app_path=args.app_path):
137 logger.info('Chrome initialized')
139 # TODO(tengs): The access token is currently fetched from the Smart Lock
140 # app's background page. To be more robust, we should instead mint the
141 # access token ourselves.
142 if not CheckCryptAuthState(chromeos.cryptauth_access_token):
143 raise SmartLockSetupError('Failed to check CryptAuth state')
145 logger.info('Opening Smart Lock settings...')
146 settings = chromeos.GetSmartLockSettings()
147 assert(not settings.is_smart_lock_enabled)
149 if args.cryptauth_staging_url is not None:
150 chromeos.SetCryptAuthStaging(args.cryptauth_staging_url)
152 logger.info('Starting Smart Lock setup flow...')
153 app = settings.StartSetupAndReturnApp()
155 _NavigateSetupDialog(chromeos, app)
157 def main():
158 logging.basicConfig()
159 logging.getLogger('proximity_auth').setLevel(logging.INFO)
160 args = ParseArgs()
161 RunSetupTest(args)
163 if __name__ == '__main__':
164 main()