bluetooth: Add battery reporting test
This adds basic battery reporting test to test that battery reporting
via GATT BAS is received by BlueZ and exposed through org.bluez.Battery1
interface.
BUG=b:166319884
TEST=Ran test_that bluetooth_AdapterLEHealth.battery_reporting
Change-Id: Iea5886cf73224183b60dff5bf3cd9f99960d9399
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2561558
Reviewed-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Reviewed-by: Daniel Winkler <danielwinkler@google.com>
Tested-by: Sonny Sasaka <sonnysasaka@chromium.org>
Commit-Queue: Sonny Sasaka <sonnysasaka@chromium.org>
diff --git a/client/cros/multimedia/bluetooth_facade_native.py b/client/cros/multimedia/bluetooth_facade_native.py
index 334ac66..4cce4a9 100644
--- a/client/cros/multimedia/bluetooth_facade_native.py
+++ b/client/cros/multimedia/bluetooth_facade_native.py
@@ -344,6 +344,7 @@
BLUEZ_DEBUG_LOG_IFACE = 'org.chromium.Bluetooth.Debug'
BLUEZ_MANAGER_IFACE = 'org.freedesktop.DBus.ObjectManager'
BLUEZ_ADAPTER_IFACE = 'org.bluez.Adapter1'
+ BLUEZ_BATTERY_IFACE = 'org.bluez.Battery1'
BLUEZ_DEVICE_IFACE = 'org.bluez.Device1'
BLUEZ_GATT_SERV_IFACE = 'org.bluez.GattService1'
BLUEZ_GATT_CHAR_IFACE = 'org.bluez.GattCharacteristic1'
@@ -1478,6 +1479,29 @@
return self._encode_base64_json(prop_val)
+ @xmlrpc_server.dbus_safe(None)
+ def get_battery_property(self, address, prop_name):
+ """Read a property from Battery1 interface.
+
+ @param address: Address of the device to query
+ @param prop_name: Property to be queried
+
+ @return The battery percentage value, or None if does not exist.
+ """
+
+ prop_val = None
+
+ # Grab dbus object, _find_battery will catch any thrown dbus error
+ battery_obj = self._find_battery(address)
+
+ if battery_obj:
+ # Query dbus object for property
+ prop_val = battery_obj.Get(self.BLUEZ_BATTERY_IFACE,
+ prop_name,
+ dbus_interface=dbus.PROPERTIES_IFACE)
+
+ return dbus_util.dbus2primitive(prop_val)
+
@xmlrpc_server.dbus_safe(False)
def set_discovery_filter(self, filter):
"""Set the discovery filter.
@@ -1670,6 +1694,25 @@
logging.info('Device not found')
return None
+ @xmlrpc_server.dbus_safe(None)
+ def _find_battery(self, address):
+ """Finds the battery with a given address.
+
+ Find the battery with a given address and returns the
+ battery interface.
+
+ @param address: Address of the device.
+
+ @returns: An 'org.bluez.Battery1' interface to the device.
+ None if device can not be found.
+ """
+ path = self._get_device_path(address)
+ if path:
+ obj = self._system_bus.get_object(self.BLUEZ_SERVICE_NAME, path)
+ return dbus.Interface(obj, self.BLUEZ_BATTERY_IFACE)
+ logging.info('Battery not found')
+ return None
+
@xmlrpc_server.dbus_safe(False)
def _get_device_path(self, address):
"""Gets the path for a device with a given address.
diff --git a/server/cros/bluetooth/bluetooth_adapter_hidreports_tests.py b/server/cros/bluetooth/bluetooth_adapter_hidreports_tests.py
index e8aca7e..1999889 100644
--- a/server/cros/bluetooth/bluetooth_adapter_hidreports_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_hidreports_tests.py
@@ -51,6 +51,15 @@
self.test_keyboard_input_from_trace(device, "simple_text")
+ def run_battery_reporting_tests(self, device):
+ """Run battery reporting tests.
+
+ @param device: the Bluetooth device.
+
+ """
+
+ self.test_battery_reporting(device)
+
def run_hid_reports_test(self, device,
check_connected_method=lambda device: True,
suspend_resume=False, reboot=False):
diff --git a/server/cros/bluetooth/bluetooth_adapter_tests.py b/server/cros/bluetooth/bluetooth_adapter_tests.py
index 48547e1..9edc326 100644
--- a/server/cros/bluetooth/bluetooth_adapter_tests.py
+++ b/server/cros/bluetooth/bluetooth_adapter_tests.py
@@ -4279,6 +4279,21 @@
return all(self.results.values())
+ @test_retry_and_log
+ def test_battery_reporting(self, device):
+ """ Tests that battery reporting through GATT can be received
+
+ @param device: the meta device containing a Bluetooth device
+
+ @returns: true if battery reporting is received
+ """
+
+ percentage = self.bluetooth_facade.get_battery_property(
+ device.address, 'Percentage')
+
+ return percentage > 0
+
+
# -------------------------------------------------------------------
# Autotest methods
# -------------------------------------------------------------------
diff --git a/server/cros/bluetooth/bluetooth_device.py b/server/cros/bluetooth/bluetooth_device.py
index 83db633..9a0fd4c 100644
--- a/server/cros/bluetooth/bluetooth_device.py
+++ b/server/cros/bluetooth/bluetooth_device.py
@@ -594,6 +594,19 @@
@proxy_thread_safe
+ def get_battery_property(self, address, prop_name):
+ """Read a property of battery by directly querying the dbus object
+
+ @param address: Address of the device to query
+ @param prop_name: Property to be queried
+
+ @return The property if battery is found and has property,
+ None otherwise
+ """
+
+ return self._proxy.get_battery_property(address, prop_name)
+
+ @proxy_thread_safe
def start_discovery(self):
"""Start discovery of remote devices.
diff --git a/server/site_tests/bluetooth_AdapterLEHealth/bluetooth_AdapterLEHealth.py b/server/site_tests/bluetooth_AdapterLEHealth/bluetooth_AdapterLEHealth.py
index 9f0f1a1..cae17f0 100644
--- a/server/site_tests/bluetooth_AdapterLEHealth/bluetooth_AdapterLEHealth.py
+++ b/server/site_tests/bluetooth_AdapterLEHealth/bluetooth_AdapterLEHealth.py
@@ -95,6 +95,18 @@
self.run_keyboard_tests(device=device)
+ @test_wrapper('Battery Reporting', devices={'BLE_MOUSE': 1})
+ def battery_reporting(self):
+ """Run battery reporting tests"""
+
+ device = self.devices['BLE_MOUSE'][0]
+ # Let the adapter pair, and connect to the target device.
+ self.assert_on_fail(self.test_discover_device(device.address))
+ self.assert_on_fail(
+ self.test_pairing(device.address, device.pin, trusted=True))
+
+ self.run_battery_reporting_tests(device=device)
+
@test_wrapper('Auto Reconnect', devices={'BLE_MOUSE':1})
def le_auto_reconnect(self):
"""LE reconnection loop by reseting HID and check reconnection"""
diff --git a/server/site_tests/bluetooth_AdapterLEHealth/control.battery_reporting b/server/site_tests/bluetooth_AdapterLEHealth/control.battery_reporting
new file mode 100644
index 0000000..595dc53
--- /dev/null
+++ b/server/site_tests/bluetooth_AdapterLEHealth/control.battery_reporting
@@ -0,0 +1,32 @@
+# Copyright 2020 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.
+
+from autotest_lib.server import utils
+
+AUTHOR = 'chromeos-bluetooth'
+NAME = 'bluetooth_AdapterLEHealth.battery_reporting'
+PURPOSE = ('Test the GATT Battery Service profile')
+CRITERIA = 'Pass all health test'
+ATTRIBUTES = 'suite:bluetooth_flaky'
+TIME = 'MEDIUM'
+TEST_CATEGORY = 'Functional'
+TEST_CLASS = 'bluetooth'
+TEST_TYPE = 'server'
+DEPENDENCIES = 'bluetooth, working_bluetooth_btpeer:1'
+
+DOC = """
+
+ Server side bluetooth tests about receiving battery reports via GATT.
+
+ """
+
+args_dict = utils.args_to_dict(args)
+
+def run(machine):
+ host = hosts.create_host(machine)
+ job.run_test('bluetooth_AdapterLEHealth', host=host,
+ num_iterations=1, args_dict=args_dict,
+ test_name=NAME.split('.')[1])
+
+parallel_simple(run, machines)