1# Lint as: python2, python3 2# Copyright 2022 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import logging 7 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.common_lib import ui_utils 11from autotest_lib.client.common_lib.cros import chrome 12from autotest_lib.client.cros.graphics import graphics_utils 13from autotest_lib.client.cros.bluetooth import bluetooth_device_xmlrpc_server 14 15 16class bluetooth_FastPairUI(graphics_utils.GraphicsTest): 17 """Click through the Fast Pair pairing flow UI""" 18 19 version = 1 20 21 # Notification IDs 22 DISCOVERY_GUEST_ID = 'cros_fast_pair_discovery_guest_notification_id' 23 DISCOVERY_USER_ID = 'cros_fast_pair_discovery_user_notification_id' 24 PAIRING_ID = 'cros_fast_pair_pairing_notification_id' 25 ERROR_ID = 'cros_fast_pair_error_notification_id' 26 27 # Node roles 28 BUTTON_ROLE = 'button' 29 30 # Node names 31 CONNECT = 'CONNECT' 32 33 # Amount of seconds we wait for notifications to show/disappear 34 NOTIFICATION_WAIT_TIMEOUT = 30 35 36 def initialize(self): 37 """Autotest initialize function""" 38 self.xmlrpc_delegate = \ 39 bluetooth_device_xmlrpc_server.BluetoothDeviceXmlRpcDelegate() 40 super(bluetooth_FastPairUI, self).initialize(raise_error_on_hang=True) 41 42 def cleanup(self): 43 """Autotest cleanup function""" 44 if self._GSC: 45 keyvals = self._GSC.get_memory_difference_keyvals() 46 for key, val in keyvals.items(): 47 self.output_perf_value(description=key, 48 value=val, 49 units='bytes', 50 higher_is_better=False) 51 self.write_perf_keyval(keyvals) 52 super(bluetooth_FastPairUI, self).cleanup() 53 54 def find_notification(self, expected_id): 55 """Returns True if notification with expected_id is found""" 56 notifications = self._cr.get_visible_notifications() 57 return any([n['id'] == expected_id for n in (notifications or [])]) 58 59 def wait_for_notification_to_show(self, expected_id): 60 """Wait for the notification with expected_id to show""" 61 logging.info('Waiting for notificaiton with id:%s to show', 62 expected_id) 63 utils.poll_for_condition( 64 condition=lambda: self.find_notification(expected_id), 65 exception=error.TestError( 66 """Timed out waiting for {} notification 67 to show""".format(expected_id)), 68 timeout=self.NOTIFICATION_WAIT_TIMEOUT) 69 70 def wait_for_notification_to_disappear(self, expected_id): 71 """Wait for the notification with expected_id to disappear""" 72 logging.info('Waiting for notificaiton with id:%s to disappear', 73 expected_id) 74 utils.poll_for_condition( 75 condition=lambda: not self.find_notification(expected_id), 76 exception=error.TestError( 77 """Timed out waiting for {} notification 78 to disappear""".format(expected_id)), 79 timeout=self.NOTIFICATION_WAIT_TIMEOUT) 80 81 def wait_for_discovery_notification(self): 82 """Wait for an instance of the discovery notification to show""" 83 logging.info('Waiting for discovery notification to show.') 84 utils.poll_for_condition( 85 condition=lambda: (self.find_notification( 86 self.DISCOVERY_GUEST_ID) or self.find_notification( 87 self.DISCOVERY_USER_ID)), 88 exception=error.TestError("""Timed out waiting for discovery 89 notification to show"""), 90 timeout=self.NOTIFICATION_WAIT_TIMEOUT) 91 92 def run_once(self, username, password): 93 """Click through the Fast Pair pairing flow UI""" 94 try: 95 # (b/221155928) Remove enable_features when it is on by default. 96 with chrome.Chrome(autotest_ext=True, 97 enable_features='FastPair', 98 gaia_login=True, 99 username=username, 100 password=password) as cr: 101 ui = ui_utils.UI_Handler() 102 ui.start_ui_root(cr) 103 self._cr = cr 104 105 # Wait for the initial discovery notification to show. 106 self.wait_for_discovery_notification() 107 108 # Click 'connect' on the discovery notification. 109 ui.doDefault_on_obj(name=self.CONNECT, 110 isRegex=False, 111 role=self.BUTTON_ROLE) 112 113 # Wait for the pairing notification to show and then disappear. 114 self.wait_for_notification_to_show(self.PAIRING_ID) 115 self.wait_for_notification_to_disappear(self.PAIRING_ID) 116 117 # Check if the error notification is shown. 118 if self.find_notification(self.ERROR_ID): 119 raise error.TestFail('Pairing failed.') 120 except error.TestFail: 121 raise 122 except Exception as e: 123 logging.error('Exception "%s" seen during test', e) 124 raise error.TestFail('Exception "%s" seen during test' % e) 125 finally: 126 self.xmlrpc_delegate.reset_on() 127