• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lint as: python2, python3
2# Copyright 2019 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
6"""
7Server side bluetooth tests on adapter pairing and connecting to a bluetooth
8HID device.
9"""
10
11from __future__ import absolute_import
12from __future__ import division
13from __future__ import print_function
14
15import logging
16import time
17
18import common
19from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
20from six.moves import range
21
22
23class BluetoothAdapterPairingTests(
24        bluetooth_adapter_tests.BluetoothAdapterTests):
25    """Server side bluetooth adapter pairing and connecting to bluetooth device
26
27    This test tries to verify that the adapter of the DUT could
28    pair and connect to a bluetooth HID device correctly.
29
30    In particular, the following subtests are performed. Look at the
31    docstrings of the subtests for more details.
32    -
33
34    Refer to BluetoothAdapterTests for all subtests performed in this test.
35
36    """
37
38    # TODO(josephsih): Reduce the sleep intervals to speed up the tests.
39    PAIR_TEST_SLEEP_SECS = 5
40
41    def pairing_test(self, device, check_connected_method=lambda device: True,
42                     pairing_twice=False, suspend_resume=False, reboot=False):
43        """Running Bluetooth adapter tests about pairing to a device."""
44
45        # Reset the adapter to forget previously paired devices if any.
46        self.test_reset_on_adapter()
47
48        # The adapter must be set to the pairable state.
49        self.test_pairable()
50
51        # Test if the adapter could discover the target device.
52        time.sleep(self.PAIR_TEST_SLEEP_SECS)
53        self.test_discover_device(device.address)
54
55        # Test if the discovered device class of service is correct.
56        self.test_device_class_of_service(device.address,
57                                          device.class_of_service)
58
59        # Test if the discovered device class of device is correct.
60        self.test_device_class_of_device(device.address,
61                                         device.class_of_device)
62
63        # Verify that the adapter could pair with the device.
64        # Also set the device trusted when pairing is done.
65        # Device will be connected at the end of pairing.
66        self.test_pairing(device.address, device.pin, trusted=True)
67
68        # Test if the discovered device name is correct.
69        # Sometimes, it takes quite a long time after discovering
70        # the device (more than 60 seconds) to resolve the device name.
71        # Hence, it is safer to test the device name after pairing and
72        # connection is done.
73        self.test_device_name(device.address, device.name)
74
75        # Run hid test to make sure profile is connected
76        check_connected_method(device)
77
78        # Test if the device is still connected after suspend/resume.
79        if suspend_resume:
80            self.suspend_resume()
81
82            time.sleep(self.PAIR_TEST_SLEEP_SECS)
83            self.test_device_is_paired(device.address)
84
85
86            # check if peripheral is connected after suspend resume
87            if not self.ignore_failure(check_connected_method, device):
88                logging.info("device not connected after suspend_resume")
89                self.test_connection_by_device(device)
90            else:
91                logging.info("device remains connected after suspend_resume")
92
93            time.sleep(self.PAIR_TEST_SLEEP_SECS)
94            check_connected_method(device)
95
96            time.sleep(self.PAIR_TEST_SLEEP_SECS)
97            self.test_device_name(device.address, device.name)
98
99        # Test if the device is still connected after reboot.
100        # if reboot:
101        #     self.host.reboot()
102
103        #     time.sleep(self.PAIR_TEST_SLEEP_SECS)
104        #     self.test_device_is_paired(device.address)
105
106        #     # After a reboot, we need to wake the peripheral
107        #     # as it is not connected.
108        #     time.sleep(self.PAIR_TEST_SLEEP_SECS)
109        #     self.test_connection_by_adapter(device.address)
110
111        #     time.sleep(self.PAIR_TEST_SLEEP_SECS)
112        #     self.test_device_is_connected(device.address)
113
114        #     time.sleep(self.PAIR_TEST_SLEEP_SECS)
115        #     self.test_device_name(device.address, device.name)
116
117        # Verify that the adapter could disconnect the device.
118        self.test_disconnection_by_adapter(device.address)
119
120        time.sleep(self.PAIR_TEST_SLEEP_SECS)
121        if device.can_init_connection:
122            # Verify that the device could initiate the connection.
123            self.test_connection_by_device(device)
124
125            # With raspberry pi peer, it takes a moment before the device is
126            # registered as an input device. Without delay, the input recorder
127            # doesn't find the device
128            time.sleep(1)
129            check_connected_method(device)
130        else:
131            # Reconnect so that we can test disconnection from the kit
132            self.test_connection_by_adapter(device.address)
133
134        # TODO(alent): Needs a new capability, but this is a good proxy
135        if device.can_init_connection:
136            # Verify that the device could initiate the disconnection.
137            self.test_disconnection_by_device(device)
138        else:
139            # Reconnect so that we can test disconnection from the kit
140            self.test_disconnection_by_adapter(device.address)
141
142        # Verify that the adapter could remove the paired device.
143        self.test_remove_pairing(device.address)
144
145        # Check if the device could be re-paired after being forgotten.
146        if pairing_twice:
147            # Test if the adapter could discover the target device again.
148            time.sleep(self.PAIR_TEST_SLEEP_SECS)
149            self.test_discover_device(device.address)
150
151            # Verify that the adapter could pair with the device again.
152            # Also set the device trusted when pairing is done.
153            time.sleep(self.PAIR_TEST_SLEEP_SECS)
154            self.test_pairing(device.address, device.pin, trusted=True)
155
156            # Verify that the adapter could remove the paired device again.
157            time.sleep(self.PAIR_TEST_SLEEP_SECS)
158            self.test_remove_pairing(device.address)
159
160
161    def connect_disconnect_loop(self, device, loops):
162        """Perform a connect disconnect loop test"""
163
164        # First pair and disconnect, to emulate real life scenario
165        self.test_discover_device(device.address)
166        # self.bluetooth_facade.is_discovering() doesn't work as expected:
167        # crbug:905374
168        # self.test_stop_discovery()
169        time.sleep(self.PAIR_TEST_SLEEP_SECS)
170        self.test_pairing(device.address, device.pin, trusted=True)
171
172        # Verify device is now connected
173        self.test_device_is_connected(device.address)
174        self.test_hid_device_created(device.address)
175
176        # Disconnect the device
177        self.test_disconnection_by_adapter(device.address)
178        total_duration_by_adapter = 0
179        loop_cnt = 0
180        for i in range(0, loops):
181
182            # Verify device didn't connect automatically
183            time.sleep(2)
184            self.test_device_is_not_connected(device.address)
185
186            start_time = time.time()
187            self.test_connection_by_adapter(device.address)
188            end_time = time.time()
189            time_diff = end_time - start_time
190
191            # Verify device is now connected
192            self.test_device_is_connected(device.address)
193            self.test_hid_device_created(device.address)
194
195            self.test_disconnection_by_adapter(device.address)
196
197            if not bool(self.fails):
198                loop_cnt += 1
199                total_duration_by_adapter += time_diff
200                logging.info('%d: Connection establishment duration %f sec',
201                             i, time_diff)
202            else:
203                break
204
205        if not bool(self.fails):
206            logging.info('Average duration (by adapter) %f sec',
207                         total_duration_by_adapter/loop_cnt)
208
209
210    def auto_reconnect_loop(self,
211                            device,
212                            loops,
213                            check_connected_method=lambda device: True,
214                            restart_adapter=False):
215        """Running a loop to verify the paired peer can auto reconnect"""
216
217        # Let the adapter pair, and connect to the target device first
218        self.test_discover_device(device.address)
219        self.test_pairing(device.address, device.pin, trusted=True)
220
221        # Verify device is now connected
222        self.test_connection_by_adapter(device.address)
223        self.test_hid_device_created(device.address)
224
225        total_reconnection_duration = 0
226        loop_cnt = 0
227        for i in range(loops):
228            # Restart either the adapter or the peer
229            if restart_adapter:
230                self.test_power_off_adapter()
231                self.test_power_on_adapter()
232                start_time = time.time()
233            else:
234                # Restart and clear peer HID device
235                self.restart_peers()
236                start_time = time.time()
237
238            # Verify that the device is reconnected. Wait for the input device
239            # to become available before checking the profile connection.
240            self.test_device_is_connected(device.address)
241            self.test_hid_device_created(device.address)
242
243            check_connected_method(device)
244            end_time = time.time()
245            time_diff = end_time - start_time
246
247            if not bool(self.fails):
248                total_reconnection_duration += time_diff
249                loop_cnt += 1
250                logging.info('%d: Reconnection duration %f sec', i, time_diff)
251            else:
252                break
253
254        if not bool(self.fails):
255            logging.info('Average Reconnection duration %f sec',
256                         total_reconnection_duration/loop_cnt)
257