diff --git a/tests/meson.build b/tests/meson.build index 996c4a4fa..a87f89008 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -306,6 +306,7 @@ if enable_pytest 'test_email.py', 'test_globalshortcuts.py', 'test_inputcapture.py', + 'test_location.py', 'test_remotedesktop.py', 'test_trash.py', ] diff --git a/tests/templates/geoclue2.py b/tests/templates/geoclue2.py new file mode 100644 index 000000000..c67edc1ba --- /dev/null +++ b/tests/templates/geoclue2.py @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from tests.templates import init_template_logger +import dbus.service +import dbus +import tempfile + +from dbusmock import mockobject + +from gi.repository import GLib + +BUS_NAME = "org.freedesktop.GeoClue2" +MAIN_OBJ = "/org/freedesktop/GeoClue2/Manager" +MAIN_IFACE = "org.freedesktop.GeoClue2.Manager" +CLIENT_IFACE = "org.freedesktop.GeoClue2.Client" +LOCATION_IFACE = "org.freedesktop.GeoClue2.Location" +MOCK_IFACE = "org.freedesktop.GeoClue2.Mock" +SYSTEM_BUS = True +VERSION = 1 + +logger = init_template_logger(__name__) + + +def load(mock, parameters={}): + mock.AddMethods( + MAIN_IFACE, + [ + ("GetClient", "", "o", 'ret = dbus.ObjectPath("/org/freedesktop/GeoClue2/Client/1")'), + ], + ) + mock.AddObject( + "/org/freedesktop/GeoClue2/Client/1", + CLIENT_IFACE, + { + "DesktopId": "", + "DistanceThreshold": 0, + "TimeThreshold": 0, + "RequestedAccuracyLevel": 0, + }, + [ + ("Start", "", "", Start), + ("Stop", "", "", Stop), + ], + ) + mock.client = mockobject.objects["/org/freedesktop/GeoClue2/Client/1"] + mock.client.manager = mock + mock.client.started = False + mock.client.location = 0 + mock.client.props = { + "Latitude": 0, + "Longitude": 0, + "Accuracy": 0 + } + + mock.client.AddMethod(MOCK_IFACE, "ChangeLocation", "a{sv}", "", ChangeLocation) + + +@dbus.service.method( + CLIENT_IFACE, + in_signature="", + out_signature="", +) +def Start(self): + logger.debug(f"Start()") + self.started = True + self.ChangeLocation(self.props) + + +@dbus.service.method( + CLIENT_IFACE, + in_signature="", + out_signature="", +) +def Stop(self): + logger.debug(f"Stop()") + self.started = False + self.RemoveObject(f"/org/freedesktop/GeoClue2/Location/{self.location}") + + +@dbus.service.method( + MOCK_IFACE, + in_signature="a{sv}", + out_signature="", +) +def ChangeLocation(self, props): + logger.debug(f"ChangeLocation({props})") + + self.props = props + + if self.started != True: + return + + old_path = "/" + if self.location > 0: + old_path = f"/org/freedesktop/GeoClue2/Location/{self.location}" + self.location = self.location + 1 + new_path = f"/org/freedesktop/GeoClue2/Location/{self.location}" + + self.AddObject( + new_path, + LOCATION_IFACE, + { + "Latitude": props["Latitude"], + "Longitude": props["Longitude"], + "Accuracy": props["Accuracy"], + }, + [], + ) + + if old_path != "/": + self.RemoveObject(old_path) + + self.EmitSignal( + CLIENT_IFACE, + "LocationUpdated", + "oo", + [ + dbus.ObjectPath(old_path), + dbus.ObjectPath(new_path), + ], + ) + diff --git a/tests/templates/meson.build b/tests/templates/meson.build index 8a1a6a455..315832011 100644 --- a/tests/templates/meson.build +++ b/tests/templates/meson.build @@ -2,6 +2,7 @@ template_files = [ '__init__.py', 'clipboard.py', 'email.py', + 'geoclue2.py', 'globalshortcuts.py', 'inputcapture.py', 'remotedesktop.py', diff --git a/tests/test_location.py b/tests/test_location.py new file mode 100644 index 000000000..4e551ef67 --- /dev/null +++ b/tests/test_location.py @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + + +from tests import Session +from pathlib import Path +from gi.repository import GLib + +import os +import pytest +import tempfile +import dbus + + +@pytest.fixture +def portal_name(): + return "Location" + + +@pytest.fixture +def portal_has_impl(): + return False + + +@pytest.fixture +def required_templates(): + return {"geoclue2": {}} + + +class TestLocation: + def test_version(self, portal_mock): + portal_mock.check_version(1) + + + def get_client_mock(self, portal_mock): + geoclue_manager_proxy = portal_mock.dbus_con_sys.get_object( + "org.freedesktop.GeoClue2", + "/org/freedesktop/GeoClue2/Manager", + ) + geoclue_manager = dbus.Interface( + geoclue_manager_proxy, + "org.freedesktop.GeoClue2.Manager" + ) + geoclue_client_proxy = portal_mock.dbus_con_sys.get_object( + "org.freedesktop.GeoClue2", + geoclue_manager.GetClient() + ) + client_mock = dbus.Interface( + geoclue_client_proxy, + f"org.freedesktop.GeoClue2.Mock" + ) + return client_mock + + + def test_session_update(self, portal_mock): + mainloop = GLib.MainLoop() + GLib.timeout_add(2000, mainloop.quit) + updated_count = 0 + + location_intf = portal_mock.get_dbus_interface() + session = Session( + portal_mock.dbus_con, + location_intf.CreateSession({"session_handle_token": "session_token0"}) + ) + + def cb_location_updated(session_handle, location): + nonlocal mainloop + nonlocal updated_count + + if updated_count == 0: + assert location["Latitude"] == 0 + assert location["Longitude"] == 0 + assert location["Accuracy"] == 0 + elif updated_count == 1: + assert location["Latitude"] == 11 + assert location["Longitude"] == 22 + assert location["Accuracy"] == 3 + + updated_count += 1 + mainloop.quit() + + location_intf.connect_to_signal("LocationUpdated", cb_location_updated) + + start_session_request = portal_mock.create_request() + start_session_response = start_session_request.call( + "Start", + session_handle=session.handle, + parent_window="window-hndl", + options = {}, + ) + + assert start_session_response.response == 0 + + mainloop.run() + + assert updated_count == 1 + + client_mock = self.get_client_mock(portal_mock) + client_mock.ChangeLocation({ + "Latitude": dbus.UInt32(11), + "Longitude": dbus.UInt32(22), + "Accuracy": dbus.UInt32(3), + }) + + mainloop.run() + + assert updated_count == 2 + + + def test_bad_accuracy(self, portal_mock): + had_error = False + location_intf = portal_mock.get_dbus_interface() + try: + location_intf.CreateSession({ + "session_handle_token": "session_token0", + "accuracy": dbus.UInt32(22), + }) + except dbus.exceptions.DBusException as e: + had_error = True + assert e.get_dbus_name() == "org.freedesktop.portal.Error.InvalidArgument" + finally: + assert had_error +