From 9bf4215782517c21ac40e7bfca9e3a43b1b31c5e Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 16 Feb 2021 14:39:47 +0100 Subject: [PATCH 1/3] bluez: Implement Pair() method on the Device interface Tested successfully against gnome-bluetooth. Note that pairing does not currently use agents at all, and always succeeds. --- dbusmock/templates/bluez5.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/dbusmock/templates/bluez5.py b/dbusmock/templates/bluez5.py index 75e8dcf..5d9676b 100644 --- a/dbusmock/templates/bluez5.py +++ b/dbusmock/templates/bluez5.py @@ -18,6 +18,7 @@ This supports BlueZ 5 only. __author__ = 'Philip Withnall' __copyright__ = '(c) 2013 Collabora Ltd.' +import os import dbus from dbusmock import OBJECT_MANAGER_IFACE, mockobject @@ -123,6 +124,18 @@ def AddAdapter(self, device_name, system_name): return path +@dbus.service.method(DEVICE_IFACE, + in_signature='', out_signature='') +def Pair(device): + if device.paired: + raise dbus.exceptions.DBusException( + 'Device already paired', + name='org.bluez.Error.AlreadyExists') + device_address = device.props[DEVICE_IFACE]['Address'] + adapter_device_name = os.path.basename(device.props[DEVICE_IFACE]['Adapter']) + device.PairDevice(adapter_device_name, device_address) + + @dbus.service.method(BLUEZ_MOCK_IFACE, in_signature='sss', out_signature='s') def AddDevice(self, adapter_device_name, device_address, alias): @@ -171,8 +184,10 @@ def AddDevice(self, adapter_device_name, device_address, alias): ('ConnectProfile', 's', '', ''), ('Disconnect', '', '', ''), ('DisconnectProfile', 's', '', ''), - ('Pair', '', '', ''), + ('Pair', '', '', Pair), ]) + device = mockobject.objects[path] + device.paired = False manager = mockobject.objects['/'] manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded', @@ -214,6 +229,7 @@ def PairDevice(_self, adapter_device_name, device_address, class_=5898764): name=BLUEZ_MOCK_IFACE + '.NoSuchDevice') device = mockobject.objects[device_path] + device.paired = True # Based off pairing with an Android phone. uuids = [ -- 2.30.2 From 2454e9fbfa9d0da3042c51d1a3241b9940a6f1c0 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 17 Feb 2021 16:11:17 +0100 Subject: [PATCH 2/3] tests: Fix bluez server never being closed down The same variable was used to store the obex server's process information so it was closed, and the bluez server's information was lost. --- tests/test_bluez5.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_bluez5.py b/tests/test_bluez5.py index b40950f..cbbc0f7 100644 --- a/tests/test_bluez5.py +++ b/tests/test_bluez5.py @@ -205,7 +205,7 @@ class TestBlueZObex(dbusmock.DBusTestCase): self.dbusmock_bluez = dbus.Interface(self.obj_bluez, 'org.bluez.Mock') # obexd - (self.p_mock, self.obj_obex) = self.spawn_server_template( + (self.p_mock_obex, self.obj_obex) = self.spawn_server_template( 'bluez5-obex', {}, stdout=subprocess.PIPE) self.dbusmock = dbus.Interface(self.obj_obex, dbusmock.MOCK_IFACE) self.dbusmock_obex = dbus.Interface(self.obj_obex, @@ -216,6 +216,10 @@ class TestBlueZObex(dbusmock.DBusTestCase): self.p_mock.terminate() self.p_mock.wait() + self.p_mock_obex.stdout.close() + self.p_mock_obex.terminate() + self.p_mock_obex.wait() + def test_everything(self): # Set up an adapter and device. adapter_name = 'hci0' -- 2.30.2 From 49f493784cf288c95bb90870c8e3a603c64865d3 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Wed, 17 Feb 2021 16:10:08 +0100 Subject: [PATCH 3/3] bluez: Implement the AgentManager1 interface methods The pairing agent still doesn't call into those, but this is good enough to register and unregister a pairing agent in gnome-bluetooth's test suite. --- dbusmock/templates/bluez5.py | 55 ++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/dbusmock/templates/bluez5.py b/dbusmock/templates/bluez5.py index 5d9676b..6a2f85a 100644 --- a/dbusmock/templates/bluez5.py +++ b/dbusmock/templates/bluez5.py @@ -37,11 +37,60 @@ NETWORK_SERVER_IFACE = 'org.bluez.Network1' DEVICE_IFACE = 'org.bluez.Device1' +@dbus.service.method(AGENT_MANAGER_IFACE, + in_signature='os', out_signature='') +def RegisterAgent(manager, agent_path, capability): + all_caps = ['DisplayOnly', 'DisplayYesNo', 'KeyboardOnly', + 'NoInputNoOutput', 'KeyboardDisplay'] + + if agent_path in manager.agent_paths: + raise dbus.exceptions.DBusException( + 'Another agent is already registered ' + manager.agent_path, + name='org.bluez.Error.AlreadyExists') + + if capability not in all_caps: + raise dbus.exceptions.DBusException( + 'Unsupported capability ' + capability, + name='org.bluez.Error.InvalidArguments') + + if not manager.default_agent: + manager.default_agent = agent_path + manager.agent_paths += [agent_path] + manager.capabilities[agent_path] = capability + + +@dbus.service.method(AGENT_MANAGER_IFACE, + in_signature='o', out_signature='') +def UnregisterAgent(manager, agent_path): + if agent_path not in manager.agent_paths: + raise dbus.exceptions.DBusException( + 'Agent not registered ' + agent_path, + name='org.bluez.Error.DoesNotExist') + + manager.agent_paths.remove(agent_path) + del manager.capabilities[agent_path] + if manager.default_agent == agent_path: + if len(manager.agent_paths) > 0: + manager.default_agent = manager.agent_paths[-1] + else: + manager.default_agent = None + + +@dbus.service.method(AGENT_MANAGER_IFACE, + in_signature='o', out_signature='') +def RequestDefaultAgent(manager, agent_path): + if agent_path not in manager.agent_paths: + raise dbus.exceptions.DBusException( + 'Agent not registered ' + agent_path, + name='org.bluez.Error.DoesNotExist') + manager.default_agent = agent_path + + def load(mock, _parameters): mock.AddObject('/org/bluez', AGENT_MANAGER_IFACE, {}, [ - ('RegisterAgent', 'os', '', ''), - ('RequestDefaultAgent', 'o', '', ''), - ('UnregisterAgent', 'o', '', ''), + ('RegisterAgent', 'os', '', RegisterAgent), + ('RequestDefaultAgent', 'o', '', RequestDefaultAgent), + ('UnregisterAgent', 'o', '', UnregisterAgent), ]) bluez = mockobject.objects['/org/bluez'] -- 2.30.2