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 about sending bluetooth HID reports.""" 6 7 import logging 8 import time 9 10 from autotest_lib.client.common_lib import error 11 from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests 12 from autotest_lib.server.cros.multimedia import remote_facade_factory 13 14 15 class bluetooth_AdapterHIDReports( 16 bluetooth_adapter_tests.BluetoothAdapterTests): 17 """Server side bluetooth tests about sending bluetooth HID reports. 18 19 This test tries to send HID reports to a DUT and verifies if the DUT 20 could receive the reports correctly. For the time being, only bluetooth 21 mouse events are tested. Bluetooth keyboard events will be supported 22 later. 23 """ 24 25 TEST_SLEEP_SECS = 5 26 27 def _run_mouse_tests(self, device): 28 """Run all bluetooth mouse reports tests. 29 30 @param device: the bluetooth HID device. 31 32 """ 33 self.test_mouse_left_click(device) 34 self.test_mouse_right_click(device) 35 self.test_mouse_move_in_x(device, 80) 36 self.test_mouse_move_in_y(device, -50) 37 self.test_mouse_move_in_xy(device, -60, 100) 38 self.test_mouse_scroll_down(device, 70) 39 self.test_mouse_scroll_up(device, 40) 40 self.test_mouse_click_and_drag(device, 90, 30) 41 42 43 def run_once(self, host, device_type, num_iterations=1, min_pass_count=1, 44 suspend_resume=False, reboot=False): 45 """Running Bluetooth HID reports tests. 46 47 @param host: the DUT, usually a chromebook 48 @param device_type : the bluetooth HID device type, e.g., 'MOUSE' 49 @param num_iterations: the number of rounds to execute the test 50 @param min_pass_count: the minimal pass count to pass this test 51 52 """ 53 self.host = host 54 factory = remote_facade_factory.RemoteFacadeFactory(host) 55 self.bluetooth_facade = factory.create_bluetooth_hid_facade() 56 self.input_facade = factory.create_input_facade() 57 self.check_chameleon() 58 59 pass_count = 0 60 self.total_fails = {} 61 for iteration in xrange(1, num_iterations + 1): 62 self.fails = [] 63 64 # Get the bluetooth device object. 65 device = self.get_device(device_type) 66 67 # Reset the adapter and set it pairable. 68 self.test_reset_on_adapter() 69 self.test_pairable() 70 71 # Let the adapter pair, and connect to the target device. 72 time.sleep(self.TEST_SLEEP_SECS) 73 self.test_discover_device(device.address) 74 time.sleep(self.TEST_SLEEP_SECS) 75 self.test_pairing(device.address, device.pin, trusted=True) 76 time.sleep(self.TEST_SLEEP_SECS) 77 self.test_connection_by_adapter(device.address) 78 79 if suspend_resume: 80 self.suspend_resume() 81 82 time.sleep(self.TEST_SLEEP_SECS) 83 self.test_device_is_paired(device.address) 84 85 # After a suspend/resume, we should check if the device is 86 # connected. 87 # NOTE: After a suspend/resume, the RN42 kit remains connected. 88 # However, this is not expected behavior for all bluetooth 89 # peripherals. 90 time.sleep(self.TEST_SLEEP_SECS) 91 self.test_device_is_connected(device.address) 92 93 time.sleep(self.TEST_SLEEP_SECS) 94 self.test_device_name(device.address, device.name) 95 96 if reboot: 97 self.host.reboot() 98 99 # NOTE: We need to recreate the bluetooth_facade after a reboot. 100 self.bluetooth_facade = factory.create_bluetooth_hid_facade() 101 self.input_facade = factory.create_input_facade() 102 103 time.sleep(self.TEST_SLEEP_SECS) 104 self.test_device_is_paired(device.address) 105 106 time.sleep(self.TEST_SLEEP_SECS) 107 self.test_connection_by_device(device) 108 109 time.sleep(self.TEST_SLEEP_SECS) 110 self.test_device_name(device.address, device.name) 111 112 # Run tests about mouse reports. 113 if device_type.endswith('MOUSE'): 114 self._run_mouse_tests(device) 115 116 # Disconnect the device, and remove the pairing. 117 self.test_disconnection_by_adapter(device.address) 118 self.test_remove_pairing(device.address) 119 120 if bool(self.fails): 121 self.total_fails['Round %d' % iteration] = self.fails 122 else: 123 pass_count += 1 124 125 fail_count = iteration - pass_count 126 logging.info('=== (pass = %d, fail = %d) / total %d ===\n', 127 pass_count, fail_count, num_iterations) 128 129 if pass_count < min_pass_count: 130 raise error.TestFail(self.total_fails) 131