xref: /aosp_15_r20/external/autotest/server/site_tests/bluetooth_FastPair/bluetooth_FastPair.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
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""" Bluetooth test that tests the Fast Pair scenarios."""
6
7from __future__ import absolute_import
8from __future__ import division
9from __future__ import print_function
10
11from base64 import b64decode
12import logging
13
14from autotest_lib.client.common_lib import error
15from autotest_lib.server.cros.bluetooth.bluetooth_adapter_quick_tests import (
16        BluetoothAdapterQuickTests)
17from autotest_lib.server.cros.bluetooth.bluetooth_adapter_tests import (
18        UNSUPPORTED_BT_HW_FILTERING_CHIPSETS)
19from autotest_lib.server import autotest
20
21imported_password_util = True
22
23try:
24    # Importing this private util fails on public boards (e.g amd64-generic)
25    from autotest_lib.client.common_lib.cros import password_util
26except ImportError:
27    imported_password_util = False
28    logging.error('Failed to import password_util from autotest-private')
29
30test_wrapper = BluetoothAdapterQuickTests.quick_test_test_decorator
31batch_wrapper = BluetoothAdapterQuickTests.quick_test_batch_decorator
32
33
34class bluetooth_FastPair(BluetoothAdapterQuickTests):
35    """Fast Pair tests"""
36
37    UI_TEST = 'bluetooth_FastPairUI'
38
39    KEY_PEM_ARG_KEY = 'fast_pair_antispoofing_key_pem'
40    ACCOUNT_KEY_ARG_KEY = 'fast_pair_account_key'
41    USERNAME_ARG_KEY = 'fast_pair_username'
42    PASSWORD_ARG_KEY = 'fast_pair_password'
43
44    _key_pem = None
45    _account_key = None
46    _username = None
47    _password = None
48
49    def run_ui_test(self):
50        """Runs the UI client test, which clicks through the Fast Pair UI"""
51        client_at = autotest.Autotest(self.host)
52        client_at.run_test(self.UI_TEST,
53                           username=self._username,
54                           password=self._password)
55        client_at._check_client_test_result(self.host, self.UI_TEST)
56
57    @test_wrapper('Fast Pair Initial Pairing',
58                  devices={'BLE_FAST_PAIR': 1},
59                  skip_chipsets=UNSUPPORTED_BT_HW_FILTERING_CHIPSETS)
60    def fast_pair_initial_pairing_test(self):
61        """Test the Fast Pair initial pairing scenario"""
62        try:
63            # Setup the Fast Pair device.
64            device = self.devices['BLE_FAST_PAIR'][0]
65            device.SetAntispoofingKeyPem(self._key_pem)
66
67            # Toggling discoverable here ensures the device starts
68            # advertising during this test.
69            device.SetDiscoverable(False)
70            device.SetDiscoverable(True)
71
72            # Run UI test, which clicks through the pairing UI flow.
73            self.run_ui_test()
74            # Verify device is paired.
75            return self.bluetooth_facade.device_is_paired(device.address)
76        except Exception as e:
77            logging.error('exception in fast_pair_initial_pairing_test %s',
78                          str(e))
79            return False
80
81    @test_wrapper('Fast Pair Subsequent Pairing',
82                  devices={'BLE_FAST_PAIR': 1},
83                  skip_chipsets=UNSUPPORTED_BT_HW_FILTERING_CHIPSETS)
84    def fast_pair_subsequent_pairing_test(self):
85        """Test the Fast Pair subsequent pairing scenario"""
86        try:
87            # Setup the Fast Pair device.
88            device = self.devices['BLE_FAST_PAIR'][0]
89            device.SetAntispoofingKeyPem(None)
90            device.AddAccountKey(self._account_key)
91
92            # Toggling discoverable here ensures the device starts
93            # advertising during this test.
94            device.SetDiscoverable(False)
95            device.SetDiscoverable(True)
96
97            # Run UI test, which clicks through the pairing UI flow.
98            self.run_ui_test()
99
100            # Verify device is paired.
101            return self.bluetooth_facade.device_is_paired(device.address)
102        except Exception as e:
103            logging.error('exception in fast_pair_subsequent_pairing_test %s',
104                          str(e))
105            return False
106
107    def set_key_pem(self, args_dict):
108        if imported_password_util:
109            self._key_pem = b64decode(
110                    password_util.get_fast_pair_anti_spoofing_key())
111
112        elif args_dict is not None and self.KEY_PEM_ARG_KEY in args_dict:
113            self._key_pem = b64decode(args_dict[self.KEY_PEM_ARG_KEY])
114
115        if self._key_pem is None:
116            raise error.TestError('Valid %s arg is missing' %
117                                  self.KEY_PEM_ARG_KEY)
118
119    def set_account_key(self, args_dict):
120        if imported_password_util:
121            self._account_key = b64decode(
122                    password_util.get_fast_pair_account_key())
123
124        elif args_dict is not None and self.ACCOUNT_KEY_ARG_KEY in args_dict:
125            self._account_key = b64decode(args_dict[self.ACCOUNT_KEY_ARG_KEY])
126
127        if self._account_key is None:
128            raise error.TestError('Valid %s arg is missing' %
129                                  self.ACCOUNT_KEY_ARG_KEY)
130
131    def set_username(self, args_dict):
132        if imported_password_util:
133            self._username = (
134                    password_util.get_fast_pair_user_credentials().username)
135
136        elif args_dict is not None and self.USERNAME_ARG_KEY in args_dict:
137            self._username = args_dict[self.USERNAME_ARG_KEY]
138
139        if self._username is None:
140            raise error.TestError('Valid %s arg is missing' %
141                                  self.USERNAME_ARG_KEY)
142
143    def set_password(self, args_dict):
144        if imported_password_util:
145            self._password = (
146                    password_util.get_fast_pair_user_credentials().password)
147
148        elif args_dict is not None and self.PASSWORD_ARG_KEY in args_dict:
149            self._password = args_dict[self.PASSWORD_ARG_KEY]
150
151        if self._password is None:
152            raise error.TestError('Valid %s arg is missing' %
153                                  self.PASSWORD_ARG_KEY)
154
155    @batch_wrapper('Fast Pair')
156    def fast_pair_batch_run(self, num_iterations=1, test_name=None):
157        """ Batch of Fair Pair tests """
158        self.fast_pair_initial_pairing_test()
159        self.fast_pair_subsequent_pairing_test()
160
161    def run_once(self,
162                 host,
163                 num_iterations=1,
164                 args_dict=None,
165                 test_name=None,
166                 flag='Quick Health'):
167        """Running Fast Pair tests.
168
169        @param host: the DUT, usually a chromebook
170        @param num_iterations: the number of times to execute the test
171        @param test_name: the test to run or None for all tests
172        @param flag: run tests with this flag (default: Quick Health)
173
174        """
175
176        # First set required args
177        self.set_key_pem(args_dict)
178        self.set_account_key(args_dict)
179        self.set_username(args_dict)
180        self.set_password(args_dict)
181
182        # Initialize and run the test batch or the requested specific test
183        self.quick_test_init(host,
184                             use_btpeer=True,
185                             flag=flag,
186                             args_dict=args_dict)
187        self.fast_pair_batch_run(num_iterations, test_name)
188        self.quick_test_cleanup()
189