| # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Server side bluetooth adapter subtests.""" |
| |
| import functools |
| import logging |
| import time |
| |
| from autotest_lib.client.bin import utils |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server import test |
| from autotest_lib.server.cros.multimedia import remote_facade_factory |
| |
| |
| # Delay binding the methods since host is only available at run time. |
| SUPPORTED_DEVICE_TYPES = { |
| 'MOUSE': lambda host: host.chameleon.get_bluetooh_hid_mouse} |
| |
| def get_bluetooth_emulated_device(host, device_type): |
| """Get the bluetooth emulated device object. |
| |
| @param host: the DUT, usually a chromebook |
| @param device_type : the bluetooth HID device type, e.g., 'MOUSE' |
| |
| @returns: the bluetooth device object |
| |
| """ |
| if device_type not in SUPPORTED_DEVICE_TYPES: |
| raise error.TestError('The device type is not supported: %s', |
| device_type) |
| |
| # Get the device object and query some important properties. |
| device = SUPPORTED_DEVICE_TYPES[device_type](host)() |
| device.Init() |
| device.name = device.GetChipName() |
| device.address = device.GetLocalBluetoothAddress() |
| device.pin = device.GetPinCode() |
| device.class_of_service = device.GetClassOfService() |
| device.class_of_device = device.GetClassOfDevice() |
| device.device_type = device.GetHIDDeviceType() |
| device.authenticaiton_mode = device.GetAuthenticationMode() |
| device.port = device.GetPort() |
| |
| logging.info('device type: %s', device_type) |
| logging.info('device name: %s', device.name) |
| logging.info('address: %s', device.address) |
| logging.info('pin: %s', device.pin) |
| logging.info('class of service: 0x%04X', device.class_of_service) |
| logging.info('class of device: 0x%04X', device.class_of_device) |
| logging.info('device type: %s', device.device_type) |
| logging.info('authenticaiton mode: %s', device.authenticaiton_mode) |
| logging.info('serial port: %s\n', device.port) |
| |
| return device |
| |
| |
| def _TestLog(func): |
| """A decorator that logs the test reuslts and collects error messages.""" |
| @functools.wraps(func) |
| def wrapper(instance, *args, **kwargs): |
| """A wrapper of the decorated method.""" |
| instance.results = None |
| test_result = func(instance, *args, **kwargs) |
| if test_result: |
| logging.info('[*** passed: %s]', func.__name__) |
| else: |
| fail_msg = '[--- failed: %s (%s)]' % (func.__name__, |
| str(instance.results)) |
| logging.error(fail_msg) |
| instance.fails.append(fail_msg) |
| return test_result |
| return wrapper |
| |
| |
| class BluetoothAdapterTests(test.test): |
| """Server side bluetooth adapter tests. |
| |
| This test class tries to thoroughly verify most of the important work |
| states of a bluetooth adapter. |
| |
| The various test methods are supposed to be invoked by actual autotest |
| tests such as server/cros/site_tests/bluetooth_Adapter*. |
| |
| """ |
| version = 1 |
| ADAPTER_POWER_STATE_TIMEOUT_SECS = 5 |
| ADAPTER_ACTION_SLEEP_SECS = 1 |
| ADAPTER_PAIRING_TIMEOUT_SECS = 60 |
| ADAPTER_CONNECTION_TIMEOUT_SECS = 15 |
| ADAPTER_DISCONNECTION_TIMEOUT_SECS = 15 |
| ADAPTER_PAIRING_POLLING_SLEEP_SECS = 3 |
| ADAPTER_DISCOVER_TIMEOUT_SECS = 60 # 30 seconds too short sometimes |
| ADAPTER_DISCOVER_POLLING_SLEEP_SECS = 1 |
| |
| # hci0 is the default hci device if there is no external bluetooth dongle. |
| EXPECTED_HCI = 'hci0' |
| |
| CLASS_OF_SERVICE_MASK = 0xFFE000 |
| CLASS_OF_DEVICE_MASK = 0x001FFF |
| |
| # Supported profiles by chrome os. |
| SUPPORTED_UUIDS = { |
| 'HSP_AG_UUID': '00001112-0000-1000-8000-00805f9b34fb', |
| 'GATT_UUID': '00001801-0000-1000-8000-00805f9b34fb', |
| 'A2DP_SOURCE_UUID': '0000110a-0000-1000-8000-00805f9b34fb', |
| 'HFP_AG_UUID': '0000111f-0000-1000-8000-00805f9b34fb', |
| 'PNP_UUID': '00001200-0000-1000-8000-00805f9b34fb', |
| 'GAP_UUID': '00001800-0000-1000-8000-00805f9b34fb'} |
| |
| |
| def get_device(self, host, device_type): |
| """Get the bluetooth device object. |
| |
| @param host: the DUT, usually a chromebook |
| @param device_type : the bluetooth HID device type, e.g., 'MOUSE' |
| |
| @returns: the bluetooth device object |
| |
| """ |
| if self.devices[device_type] is None: |
| self.devices[device_type] = get_bluetooth_emulated_device( |
| host, device_type) |
| return self.devices[device_type] |
| |
| |
| @_TestLog |
| def test_bluetoothd_running(self): |
| """Test that bluetoothd is running.""" |
| return self.bluetooth_hid_facade.is_bluetoothd_running() |
| |
| |
| @_TestLog |
| def test_start_bluetoothd(self): |
| """Test that bluetoothd could be started successfully.""" |
| return self.bluetooth_hid_facade.start_bluetoothd() |
| |
| |
| @_TestLog |
| def test_stop_bluetoothd(self): |
| """Test that bluetoothd could be stopped successfully.""" |
| return self.bluetooth_hid_facade.stop_bluetoothd() |
| |
| |
| @_TestLog |
| def test_adapter_work_state(self): |
| """Test that the bluetooth adapter is in the correct working state. |
| |
| This includes that the adapter is detectable, is powered on, |
| and its hci device is hci0. |
| """ |
| has_adapter = self.bluetooth_hid_facade.has_adapter() |
| is_powered_on = self.bluetooth_hid_facade.is_powered_on() |
| hci = self.bluetooth_hid_facade.get_hci() == self.EXPECTED_HCI |
| self.results = { |
| 'has_adapter': has_adapter, |
| 'is_powered_on': is_powered_on, |
| 'hci': hci} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_power_on_adapter(self): |
| """Test that the adapter could be powered on successfully.""" |
| power_on = self.bluetooth_hid_facade.set_powered(True) |
| is_powered_on = False |
| try: |
| utils.poll_for_condition( |
| condition=self.bluetooth_hid_facade.is_powered_on, |
| timeout=self.ADAPTER_POWER_STATE_TIMEOUT_SECS, |
| desc='Waiting for adapter powered on') |
| is_powered_on = True |
| except utils.TimeoutError as e: |
| logging.error('test_power_on_adapter: %s', e) |
| except: |
| logging.error('test_power_on_adapter: unpredicted error') |
| |
| self.results = {'power_on': power_on, 'is_powered_on': is_powered_on} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_power_off_adapter(self): |
| """Test that the adapter could be powered off successfully.""" |
| power_off = self.bluetooth_hid_facade.set_powered(False) |
| is_powered_off = False |
| try: |
| utils.poll_for_condition( |
| condition=(lambda: |
| not self.bluetooth_hid_facade.is_powered_on()), |
| timeout=self.ADAPTER_POWER_STATE_TIMEOUT_SECS, |
| desc='Waiting for adapter powered off') |
| is_powered_off = True |
| except utils.TimeoutError as e: |
| logging.error('test_power_off_adapter: %s', e) |
| except: |
| logging.error('test_power_off_adapter: unpredicted error') |
| |
| self.results = { |
| 'power_off': power_off, |
| 'is_powered_off': is_powered_off} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_reset_on_adapter(self): |
| """Test that the adapter could be reset on successfully. |
| |
| This includes restarting bluetoothd, and removing the settings |
| and cached devices. |
| """ |
| reset_on = self.bluetooth_hid_facade.reset_on() |
| is_powered_on = False |
| try: |
| utils.poll_for_condition( |
| condition=self.bluetooth_hid_facade.is_powered_on, |
| timeout=self.ADAPTER_POWER_STATE_TIMEOUT_SECS, |
| desc='Waiting for adapter reset on') |
| is_powered_on = True |
| except utils.TimeoutError as e: |
| logging.error('test_reset_on_adapter: %s', e) |
| except: |
| logging.error('test_reset_on_adapter: unpredicted error') |
| |
| self.results = {'reset_on': reset_on, 'is_powered_on': is_powered_on} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_reset_off_adapter(self): |
| """Test that the adapter could be reset off successfully. |
| |
| This includes restarting bluetoothd, and removing the settings |
| and cached devices. |
| """ |
| reset_off = self.bluetooth_hid_facade.reset_off() |
| is_powered_off = False |
| try: |
| utils.poll_for_condition( |
| condition=(lambda: |
| not self.bluetooth_hid_facade.is_powered_on()), |
| timeout=self.ADAPTER_POWER_STATE_TIMEOUT_SECS, |
| desc='Waiting for adapter reset off') |
| is_powered_off = True |
| except utils.TimeoutError as e: |
| logging.error('test_reset_off_adapter: %s', e) |
| except: |
| logging.error('test_reset_off_adapter: unpredicted error') |
| |
| self.results = { |
| 'reset_off': reset_off, |
| 'is_powered_off': is_powered_off} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_UUIDs(self): |
| """Test that basic profiles are supported.""" |
| adapter_UUIDs = self.bluetooth_hid_facade.get_UUIDs() |
| self.results = [uuid for uuid in self.SUPPORTED_UUIDS.values() |
| if uuid not in adapter_UUIDs] |
| return not bool(self.results) |
| |
| |
| @_TestLog |
| def test_start_discovery(self): |
| """Test that the adapter could start discovery.""" |
| start_discovery = self.bluetooth_hid_facade.start_discovery() |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_discovering = self.bluetooth_hid_facade.is_discovering() |
| self.results = { |
| 'start_discovery': start_discovery, |
| 'is_discovering': is_discovering} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_stop_discovery(self): |
| """Test that the adapter could stop discovery.""" |
| stop_discovery = self.bluetooth_hid_facade.stop_discovery() |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_not_discovering = not self.bluetooth_hid_facade.is_discovering() |
| self.results = { |
| 'stop_discovery': stop_discovery, |
| 'is_not_discovering': is_not_discovering} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_discoverable(self): |
| """Test that the adapter could be set discoverable.""" |
| set_discoverable = self.bluetooth_hid_facade.set_discoverable(True) |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_discoverable = self.bluetooth_hid_facade.is_discoverable() |
| self.results = { |
| 'set_discoverable': set_discoverable, |
| 'is_discoverable': is_discoverable} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_nondiscoverable(self): |
| """Test that the adapter could be set non-discoverable.""" |
| set_nondiscoverable = self.bluetooth_hid_facade.set_discoverable(False) |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_nondiscoverable = not self.bluetooth_hid_facade.is_discoverable() |
| self.results = { |
| 'set_nondiscoverable': set_nondiscoverable, |
| 'is_nondiscoverable': is_nondiscoverable} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_pairable(self): |
| """Test that the adapter could be set pairable.""" |
| set_pairable = self.bluetooth_hid_facade.set_pairable(True) |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_pairable = self.bluetooth_hid_facade.is_pairable() |
| self.results = { |
| 'set_pairable': set_pairable, |
| 'is_pairable': is_pairable} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_nonpairable(self): |
| """Test that the adapter could be set non-pairable.""" |
| set_nonpairable = self.bluetooth_hid_facade.set_pairable(False) |
| time.sleep(self.ADAPTER_ACTION_SLEEP_SECS) |
| is_nonpairable = not self.bluetooth_hid_facade.is_pairable() |
| self.results = { |
| 'set_nonpairable': set_nonpairable, |
| 'is_nonpairable': is_nonpairable} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_discover_device(self, device_address): |
| """Test that the adapter could discover the specified device address. |
| |
| @param device_address: Address of the device. |
| |
| @returns: True if the device is found. False otherwise. |
| |
| """ |
| has_device_initially = False |
| start_discovery = False |
| device_discovered = False |
| has_device = self.bluetooth_hid_facade.has_device |
| |
| if has_device(device_address): |
| has_device_initially = True |
| elif self.bluetooth_hid_facade.start_discovery(): |
| start_discovery = True |
| try: |
| utils.poll_for_condition( |
| condition=(lambda: has_device(device_address)), |
| timeout=self.ADAPTER_DISCOVER_TIMEOUT_SECS, |
| sleep_interval=self.ADAPTER_DISCOVER_POLLING_SLEEP_SECS, |
| desc='Waiting for discovering %s' % device_address) |
| device_discovered = True |
| except utils.TimeoutError as e: |
| logging.error('test_discover_device: %s', e) |
| except: |
| logging.error('test_discover_device: unpredicted error') |
| |
| self.results = { |
| 'has_device_initially': has_device_initially, |
| 'start_discovery': start_discovery, |
| 'device_discovered': device_discovered} |
| return has_device_initially or device_discovered |
| |
| |
| @_TestLog |
| def test_pairing(self, device_address, pin, trusted=True): |
| """Test that the adapter could pair with the device successfully. |
| |
| @param device_address: Address of the device. |
| @param pin: pin code to pair with the device. |
| @param trusted: indicating whether to set the device trusted. |
| |
| @returns: True if pairing succeeds. False otherwise. |
| |
| """ |
| |
| def _pair_device(): |
| """Pair to the device. |
| |
| @returns: True if it could pair with the device. False otherwise. |
| |
| """ |
| return self.bluetooth_hid_facade.pair_legacy_device( |
| device_address, pin, trusted, |
| self.ADAPTER_PAIRING_TIMEOUT_SECS) |
| |
| |
| has_device = False |
| paired = False |
| if self.bluetooth_hid_facade.has_device(device_address): |
| has_device = True |
| try: |
| utils.poll_for_condition( |
| condition=_pair_device, |
| timeout=self.ADAPTER_PAIRING_TIMEOUT_SECS, |
| sleep_interval=self.ADAPTER_PAIRING_POLLING_SLEEP_SECS, |
| desc='Waiting for pairing %s' % device_address) |
| paired = True |
| except utils.TimeoutError as e: |
| logging.error('test_pairing: %s', e) |
| except: |
| logging.error('test_pairing: unpredicted error') |
| |
| self.results = {'has_device': has_device, 'paired': paired} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_remove_pairing(self, device_address): |
| """Test that the adapter could remove the paired device. |
| |
| @param device_address: Address of the device. |
| |
| @returns: True if the device is removed successfully. False otherwise. |
| |
| """ |
| device_is_paired_initially = self.bluetooth_hid_facade.device_is_paired( |
| device_address) |
| remove_pairing = False |
| pairing_removed = False |
| |
| if device_is_paired_initially: |
| remove_pairing = self.bluetooth_hid_facade.remove_device_object( |
| device_address) |
| pairing_removed = not self.bluetooth_hid_facade.device_is_paired( |
| device_address) |
| |
| self.results = { |
| 'device_is_paired_initially': device_is_paired_initially, |
| 'remove_pairing': remove_pairing, |
| 'pairing_removed': pairing_removed} |
| return all(self.results.values()) |
| |
| |
| def test_set_trusted(self, device_address, trusted=True): |
| """Test whether the device with the specified address is trusted. |
| |
| @param device_address: Address of the device. |
| @param trusted : True or False indicating if trusted is expected. |
| |
| @returns: True if the device's "Trusted" property is as specified; |
| False otherwise. |
| |
| """ |
| |
| set_trusted = self.bluetooth_hid_facade.set_trusted( |
| device_address, trusted) |
| |
| properties = self.bluetooth_hid_facade.get_device_properties( |
| device_address) |
| actual_trusted = properties.get('Trusted') |
| |
| self.results = { |
| 'set_trusted': set_trusted, |
| 'actual trusted': actual_trusted, |
| 'expected trusted': trusted} |
| return actual_trusted == trusted |
| |
| |
| @_TestLog |
| def test_connection_by_adapter(self, device_address): |
| """Test that the adapter of dut could connect to the device successfully |
| |
| It is the caller's responsibility to pair to the device before |
| doing connection. |
| |
| @param device_address: Address of the device. |
| |
| @returns: True if connection is performed. False otherwise. |
| |
| """ |
| |
| def _connect_device(): |
| """Connect to the device. |
| |
| @returns: True if it could connect to the device. False otherwise. |
| |
| """ |
| return self.bluetooth_hid_facade.connect_device(device_address) |
| |
| |
| has_device = False |
| connected = False |
| if self.bluetooth_hid_facade.has_device(device_address): |
| has_device = True |
| try: |
| utils.poll_for_condition( |
| condition=_connect_device, |
| timeout=self.ADAPTER_PAIRING_TIMEOUT_SECS, |
| sleep_interval=self.ADAPTER_PAIRING_POLLING_SLEEP_SECS, |
| desc='Waiting for connecting to %s' % device_address) |
| connected = True |
| except utils.TimeoutError as e: |
| logging.error('test_connection_by_adapter: %s', e) |
| except: |
| logging.error('test_connection_by_adapter: unpredicted error') |
| |
| self.results = {'has_device': has_device, 'connected': connected} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_disconnection_by_adapter(self, device_address): |
| """Test that the adapter of dut could disconnect the device successfully |
| |
| @param device_address: Address of the device. |
| |
| @returns: True if disconnection is performed. False otherwise. |
| |
| """ |
| return self.bluetooth_hid_facade.disconnect_device(device_address) |
| |
| |
| def _enter_command_mode(self, device): |
| """Let the device enter command mode. |
| |
| Before using the device, need to call this method to make sure |
| it is in the command mode. |
| |
| @param device: the device object |
| |
| """ |
| try: |
| return device.EnterCommandMode() |
| except Exception as e: |
| return False |
| |
| |
| @_TestLog |
| def test_connection_by_device(self, device): |
| """Test that the device could connect to the adapter successfully. |
| |
| This emulates the behavior that a device may initiate a |
| connection request after waking up from power saving mode. |
| |
| @param device: the device object such as a mouse or keyboard. |
| |
| @returns: True if connection is performed correctly by device and |
| the adapter also enters connection state. |
| False otherwise. |
| |
| """ |
| enter_command_mode = self._enter_command_mode(device) |
| |
| connection_by_device = False |
| adapter_address = self.bluetooth_hid_facade.address |
| try: |
| device.ConnectToRemoteAddress(adapter_address) |
| connection_by_device = True |
| except Exception as e: |
| logging.error('test_connection_by_device: %s', e) |
| except: |
| logging.error('test_connection_by_device: unpredicted error') |
| |
| connection_seen_by_adapter = False |
| device_is_connected = self.bluetooth_hid_facade.device_is_connected |
| try: |
| utils.poll_for_condition( |
| condition=lambda: device_is_connected(device.address), |
| timeout=self.ADAPTER_CONNECTION_TIMEOUT_SECS, |
| desc='Waiting for connection from %s' % device.address) |
| connection_seen_by_adapter = True |
| except utils.TimeoutError as e: |
| logging.error('test_connection_by_device: %s', e) |
| except: |
| logging.error('test_connection_by_device: unpredicted error') |
| |
| self.results = { |
| 'enter_command_mode': enter_command_mode, |
| 'connection_by_device': connection_by_device, |
| 'connection_seen_by_adapter': connection_seen_by_adapter} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_disconnection_by_device(self, device): |
| """Test that the device could disconnect the adapter successfully. |
| |
| This emulates the behavior that a device may initiate a |
| disconnection request before going into power saving mode. |
| |
| @param device: the device object such as a mouse or keyboard. |
| |
| @returns: True if disconnection is performed correctly by device and |
| the adapter also observes the disconnection. |
| False otherwise. |
| |
| """ |
| disconnection_by_device = False |
| try: |
| device.Disconnect() |
| disconnection_by_device = True |
| except Exception as e: |
| logging.error('test_disconnection_by_device: %s', e) |
| except: |
| logging.error('test_disconnection_by_device: unpredicted error') |
| |
| disconnection_seen_by_adapter = False |
| device_is_connected = self.bluetooth_hid_facade.device_is_connected |
| try: |
| utils.poll_for_condition( |
| condition=lambda: not device_is_connected(device.address), |
| timeout=self.ADAPTER_DISCONNECTION_TIMEOUT_SECS, |
| desc='Waiting for disconnection from %s' % device.address) |
| disconnection_seen_by_adapter = True |
| except utils.TimeoutError as e: |
| logging.error('test_disconnection_by_device: %s', e) |
| except: |
| logging.error('test_disconnection_by_device: unpredicted error') |
| |
| self.results = { |
| 'disconnection_by_device': disconnection_by_device, |
| 'disconnection_seen_by_adapter': disconnection_seen_by_adapter} |
| return all(self.results.values()) |
| |
| |
| @_TestLog |
| def test_device_name(self, device_address, expected_device_name): |
| """Test that the device name discovered by the adapter is correct. |
| |
| @param device_address: Address of the device. |
| @param expected_device_name: the bluetooth device name |
| |
| @returns: True if the discovered_device_name is expected_device_name. |
| False otherwise. |
| |
| """ |
| properties = self.bluetooth_hid_facade.get_device_properties( |
| device_address) |
| discovered_device_name = properties.get('Name') |
| self.results = { |
| 'expected_device_name': expected_device_name, |
| 'discovered_device_name': discovered_device_name} |
| return discovered_device_name == expected_device_name |
| |
| |
| @_TestLog |
| def test_device_class_of_service(self, device_address, |
| expected_class_of_service): |
| """Test that the discovered device class of service is as expected. |
| |
| @param device_address: Address of the device. |
| @param expected_class_of_service: the expected class of service |
| |
| @returns: True if the discovered class of service matches the |
| expected class of service. False otherwise. |
| |
| """ |
| properties = self.bluetooth_hid_facade.get_device_properties( |
| device_address) |
| device_class = properties.get('Class') |
| discovered_class_of_service = device_class & self.CLASS_OF_SERVICE_MASK |
| self.results = { |
| 'device_class': device_class, |
| 'expected_class_of_service': expected_class_of_service, |
| 'discovered_class_of_service': discovered_class_of_service} |
| return discovered_class_of_service == expected_class_of_service |
| |
| |
| @_TestLog |
| def test_device_class_of_device(self, device_address, |
| expected_class_of_device): |
| """Test that the discovered device class of device is as expected. |
| |
| @param device_address: Address of the device. |
| @param expected_class_of_device: the expected class of device |
| |
| @returns: True if the discovered class of device matches the |
| expected class of device. False otherwise. |
| |
| """ |
| properties = self.bluetooth_hid_facade.get_device_properties( |
| device_address) |
| device_class = properties.get('Class') |
| discovered_class_of_device = device_class & self.CLASS_OF_DEVICE_MASK |
| self.results = { |
| 'device_class': device_class, |
| 'expected_class_of_device': expected_class_of_device, |
| 'discovered_class_of_device': discovered_class_of_device} |
| return discovered_class_of_device == expected_class_of_device |
| |
| |
| def initialize(self): |
| """Initialize bluetooth adapter tests.""" |
| # Run through every tests and collect failed tests in self.fails. |
| self.fails = [] |
| |
| # If a test depends on multiple conditions, write the results of |
| # the conditions in self.results so that it is easy to know |
| # what conditions failed by looking at the log. |
| self.results = None |
| |
| # Some tests may instantiate a peripheral device for testing. |
| self.devices = dict() |
| for device_type in SUPPORTED_DEVICE_TYPES: |
| self.devices[device_type] = None |
| |
| |
| def run_once(self, *args, **kwargs): |
| """This method should be implemented by children classes. |
| |
| Typically, the run_once() method would look like: |
| |
| factory = remote_facade_factory.RemoteFacadeFactory(host) |
| self.bluetooth_hid_facade = factory.create_bluetooth_hid_facade() |
| |
| self.test_bluetoothd_running() |
| # ... |
| # invoke more self.test_xxx() tests. |
| # ... |
| |
| if self.fails: |
| raise error.TestFail(self.fails) |
| |
| """ |
| raise NotImplementedError |
| |
| |
| def cleanup(self): |
| """Clean up bluetooth adapter tests.""" |
| # Close the device properly if a device is instantiated. |
| # Note: do not write something like the following statements |
| # if self.devices[device_type]: |
| # or |
| # if bool(self.devices[device_type]): |
| # Othereise, it would try to invoke bluetooth_mouse.__nonzero__() |
| # which just does not exist. |
| for device_type in SUPPORTED_DEVICE_TYPES: |
| if self.devices[device_type] is not None: |
| self.devices[device_type].Close() |