• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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