Index: components/proximity_auth/e2e_test/setup_test.py |
diff --git a/components/proximity_auth/e2e_test/setup_test.py b/components/proximity_auth/e2e_test/setup_test.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..fbd8242120dc86e3b56908dc8294827cae8837da |
--- /dev/null |
+++ b/components/proximity_auth/e2e_test/setup_test.py |
@@ -0,0 +1,156 @@ |
+# Copyright 2015 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. |
+ |
+""" Script that exercises the Smart Lock setup flow, testing that a nearby phone |
+can be found and used to unlock a Chromebook. |
+ |
+Note: This script does not currently automate Android phones, so make sure that |
+a phone is properly configured and online before starting the test. |
+ |
+Usage: |
+ python setup_test.py --remote_address REMOTE_ADDRESS |
+ --username USERNAME |
+ --password PASSWORD |
+ [--app_path APP_PATH] |
+ |
+ If |--app_path| is provided, then a copy of the Smart Lock app on the local |
+ machine will be used instead of the app on the ChromeOS device. |
+""" |
+ |
+import argparse |
+import cros |
+import cryptauth |
+import logging |
+import os |
+import subprocess |
+import sys |
+import tempfile |
+ |
+logger = logging.getLogger('proximity_auth.%s' % __name__) |
+ |
+class SmartLockSetupError(Exception): |
+ pass |
+ |
+def pingable_address(address): |
+ try: |
+ subprocess.check_output(['ping', '-c', '1', '-W', '1', address]) |
+ except subprocess.CalledProcessError: |
+ raise argparse.ArgumentError('%s cannot be reached.' % address) |
+ return address |
+ |
+def email(arg): |
+ tokens = arg.lower().split('@') |
+ if len(tokens) != 2 or '.' not in tokens[1]: |
+ raise argparse.ArgumentError('%s is not a valid email address' % arg) |
+ name, domain = tokens |
+ if domain == 'gmail.com': |
+ name = name.replace('.', '') |
+ return '@'.join([name, domain]) |
+ |
+def directory(path): |
+ if not os.path.isdir(path): |
+ raise argparse.ArgumentError('%s is not a directory' % path) |
+ return path |
+ |
+def ParseArgs(): |
+ parser = argparse.ArgumentParser(prog='python setup_test.py') |
+ parser.add_argument('--remote_address', required=True, type=pingable_address) |
+ parser.add_argument('--username', required=True, type=email) |
+ parser.add_argument('--password', required=True) |
+ parser.add_argument('--app_path', type=directory) |
+ args = parser.parse_args() |
+ return args |
+ |
+def CheckCryptAuthState(access_token): |
+ cryptauth_client = cryptauth.CryptAuthClient(access_token) |
+ |
+ # Check if we can make CryptAuth requests. |
+ if cryptauth_client.GetMyDevices() is None: |
+ logger.error('Cannot reach CryptAuth on test machine.') |
+ return False |
+ |
+ if cryptauth_client.GetUnlockKey() is not None: |
+ logger.info('Smart Lock currently enabled, turning off on Cryptauth...') |
+ if not cryptauth_client.ToggleEasyUnlock(False): |
+ logger.error('ToggleEasyUnlock request failed.') |
+ return False |
+ |
+ result = cryptauth_client.FindEligibleUnlockDevices() |
+ if result is None: |
+ logger.error('FindEligibleUnlockDevices request failed') |
+ return False |
+ eligibleDevices, _ = result |
+ if len(eligibleDevices) == 0: |
+ logger.warn('No eligible phones found, trying to ping phones...') |
+ result = cryptauth_client.PingPhones() |
+ if result is None or not len(result[0]): |
+ logger.error('Pinging phones failed :(') |
+ return False |
+ else: |
+ logger.inro('Pinging phones succeeded!') |
Ilya Sherman
2015/03/24 01:25:14
nit: logger.info. This is why I prefer compiled l
Tim Song
2015/03/25 23:08:44
Done. I agree!
|
+ else: |
+ logger.info('Found eligible device: %s' % \ |
+ eligibleDevices[0]['friendlyDeviceName']) |
+ return True |
+ |
+def _NavigateSetupDialog(chromeos, app): |
+ logger.info('Scanning for nearby phones...') |
+ btmon = chromeos.RunBtmon() |
+ find_phone_success = app.FindPhone() |
+ btmon.terminate() |
+ |
+ if not find_phone_success: |
+ fd, filepath = tempfile.mkstemp(prefix='btmon-') |
+ os.write(fd, btmon.stdout.read()) |
+ os.close(fd) |
+ logger.info('Logs for btmon can be found at %s' % filepath) |
+ raise SmartLockSetupError("Failed to find nearby phone.") |
+ |
+ logger.info('Phone found! Starting pairing...') |
+ if not app.PairPhone(): |
+ raise SmartLockSetupError("Failed to pair with phone.") |
+ logger.info('Pairing success! Starting trial run...') |
+ app.StartTrialRun() |
+ |
+ logger.info('Unlocking for trial run...') |
+ lock_screen = chromeos.GetAccountPickerScreen() |
+ lock_screen.WaitForSmartLockState( |
+ lock_screen.SmartLockState.AUTHENTICATED) |
+ lock_screen.UnlockWithClick() |
+ |
+ logger.info('Trial run success! Dismissing app...') |
+ app.DismissApp() |
+ |
+def RunSetupTest(args): |
+ logger.info('Starting test for %s at %s' % \ |
+ (args.username, args.remote_address)) |
+ if args.app_path is not None: |
+ logger.info('Replacing Smart Lock app with %s' % args.app_path) |
+ |
+ chromeos = cros.ChromeOS(args.remote_address, args.username, args.password) |
+ with chromeos.Start(local_app_path=args.app_path): |
+ logger.info('Chrome initialized') |
+ |
+ # TODO(tengs): The access token is currently fetched from the Smart Lock |
+ # app's background page. To be more robust, we should instead mint the |
+ # access token ourselves. |
+ if not CheckCryptAuthState(chromeos.cryptauth_access_token): |
+ raise SmartLockSetupError('Failed to check CryptAuth state') |
+ |
+ logger.info('Opening Smart Lock settings...') |
+ settings = chromeos.GetSmartLockSettings() |
+ assert(not settings.smart_lock_enabled) |
+ logger.info('Starting Smart Lock setup flow...') |
+ app = settings.StartSetupAndReturnApp() |
+ |
+ _NavigateSetupDialog(chromeos, app) |
+ |
+def main(): |
+ logging.basicConfig() |
+ logging.getLogger('proximity_auth').setLevel(logging.INFO) |
+ args = ParseArgs() |
+ RunSetupTest(args) |
+ |
+if __name__ == '__main__': |
+ main() |