1# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Server side bluetooth tests on adapter pairing and connecting to a bluetooth
6HID device.
7"""
8
9import logging
10import time
11
12from autotest_lib.client.common_lib import error
13from autotest_lib.server.cros.bluetooth.bluetooth_adpater_tests import (
14        BluetoothAdapterTests)
15from autotest_lib.server.cros.multimedia import remote_facade_factory
16
17
18class bluetooth_AdapterPairing(BluetoothAdapterTests):
19    """Server side bluetooth adapter pairing and connecting to bluetooth device
20
21    This test tries to verify that the adapter of the DUT could
22    pair and connect to a bluetooth HID device correctly.
23
24    In particular, the following subtests are performed. Look at the
25    docstrings of the subtests for more details.
26    -
27
28    Refer to BluetoothAdapterTests for all subtests performed in this test.
29
30    """
31
32    # TODO(josephsih): Reduce the sleep intervals to speed up the tests.
33    TEST_SLEEP_SECS = 5
34
35    def run_once(self, host, device_type, num_iterations=1, min_pass_count=1,
36                 pairing_twice=False):
37        """Running Bluetooth adapter tests about pairing to a device.
38
39        @param host: the DUT, usually a chromebook
40        @param device_type : the bluetooth HID device type, e.g., 'MOUSE'
41        @param num_iterations: the number of rounds to execute the test
42        @param min_pass_count: the minimal pass count to pass this test
43        @param pairing_twice: True if the host tries to pair the device
44                again after the paired device is removed.
45
46        """
47        self.host = host
48        factory = remote_facade_factory.RemoteFacadeFactory(host)
49        self.bluetooth_facade = factory.create_bluetooth_hid_facade()
50
51        pass_count = 0
52        self.total_fails = {}
53        for iteration in xrange(1, num_iterations + 1):
54            self.fails = []
55
56            # Get the device object and query some important properties.
57            device = self.get_device(device_type)
58
59            # Reset the adapter to forget previously paired devices if any.
60            self.test_reset_on_adapter()
61
62            # The adapter must be set to the pairable state.
63            self.test_pairable()
64
65            # Test if the adapter could discover the target device.
66            time.sleep(self.TEST_SLEEP_SECS)
67            self.test_discover_device(device.address)
68
69            # Test if the discovery could be stopped.
70            time.sleep(self.TEST_SLEEP_SECS)
71            self.test_stop_discovery()
72
73            # Test if the discovered device class of service is correct.
74            self.test_device_class_of_service(device.address,
75                                              device.class_of_service)
76
77            # Test if the discovered device class of device is correct.
78            self.test_device_class_of_device(device.address,
79                                             device.class_of_device)
80
81            # Verify that the adapter could pair with the device.
82            # Also set the device trusted when pairing is done.
83            time.sleep(self.TEST_SLEEP_SECS)
84            self.test_pairing(device.address, device.pin, trusted=True)
85
86            # Verify that the adapter could connect to the device.
87            time.sleep(self.TEST_SLEEP_SECS)
88            self.test_connection_by_adapter(device.address)
89
90            # Test if the discovered device name is correct.
91            # Sometimes, it takes quite a long time after discovering
92            # the device (more than 60 seconds) to resolve the device name.
93            # Hence, it is safer to test the device name after pairing and
94            # connection is done.
95            time.sleep(self.TEST_SLEEP_SECS)
96            self.test_device_name(device.address, device.name)
97
98            # Verify that the adapter could disconnect the device.
99            self.test_disconnection_by_adapter(device.address)
100
101            # Verify that the device could initiate the connection.
102            time.sleep(self.TEST_SLEEP_SECS)
103            self.test_connection_by_device(device)
104
105            # Verify that the device could initiate the disconnection.
106            self.test_disconnection_by_device(device)
107
108            # Verify that the adapter could remove the paired device.
109            self.test_remove_pairing(device.address)
110
111            # Check if the device could be re-paired after being forgotten.
112            if pairing_twice:
113                # Test if the adapter could discover the target device again.
114                time.sleep(self.TEST_SLEEP_SECS)
115                self.test_discover_device(device.address)
116
117                # Verify that the adapter could pair with the device again.
118                # Also set the device trusted when pairing is done.
119                time.sleep(self.TEST_SLEEP_SECS)
120                self.test_pairing(device.address, device.pin, trusted=True)
121
122                # Verify that the adapter could remove the paired device again.
123                time.sleep(self.TEST_SLEEP_SECS)
124                self.test_remove_pairing(device.address)
125
126            if bool(self.fails):
127                self.total_fails['Round %d' % iteration] = self.fails
128            else:
129                pass_count += 1
130
131            fail_count = iteration - pass_count
132            logging.info('===  (pass = %d, fail = %d) / total %d  ===\n',
133                         pass_count, fail_count, num_iterations)
134
135        if pass_count < min_pass_count:
136            raise error.TestFail(self.total_fails)
137