Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-python-dbusmock for openSUSE:Factory checked in at 2024-08-20 16:12:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-python-dbusmock (Old) and /work/SRC/openSUSE:Factory/.python-python-dbusmock.new.2698 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-python-dbusmock" Tue Aug 20 16:12:28 2024 rev:12 rq:1194576 version:0.32.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-python-dbusmock/python-python-dbusmock.changes 2024-03-18 16:44:32.170908315 +0100 +++ /work/SRC/openSUSE:Factory/.python-python-dbusmock.new.2698/python-python-dbusmock.changes 2024-08-20 16:12:31.083980002 +0200 @@ -1,0 +2,8 @@ +Sun Aug 18 17:06:33 UTC 2024 - Dirk Müller <dmuel...@suse.com> + +- update to 0.32.1: + * ModemManager: Add initial mock + * bluez5: Add advertising API + * Fix loading of libglib on macOS + +------------------------------------------------------------------- Old: ---- python-dbusmock-0.31.1.tar.gz New: ---- python-dbusmock-0.32.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-python-dbusmock.spec ++++++ --- /var/tmp/diff_new_pack.OkB9uR/_old 2024-08-20 16:12:31.692005257 +0200 +++ /var/tmp/diff_new_pack.OkB9uR/_new 2024-08-20 16:12:31.692005257 +0200 @@ -17,7 +17,7 @@ Name: python-python-dbusmock -Version: 0.31.1 +Version: 0.32.1 Release: 0 Summary: Python library for creating mock D-Bus objects License: LGPL-3.0-or-later ++++++ python-dbusmock-0.31.1.tar.gz -> python-dbusmock-0.32.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/.github/workflows/release.yml new/python-dbusmock-0.32.1/.github/workflows/release.yml --- old/python-dbusmock-0.31.1/.github/workflows/release.yml 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/.github/workflows/release.yml 2024-07-14 09:17:09.000000000 +0200 @@ -45,7 +45,7 @@ rm -rf tmp - name: Create GitHub release - uses: cockpit-project/action-release@88d994da62d1451c7073e26748c18413fcdf46e9 + uses: cockpit-project/action-release@7d2e2657382e8d34f88a24b5987f2b81ea165785 with: filename: "dist/python-dbusmock-${{ github.ref_name }}.tar.gz" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/.github/workflows/tests.yml new/python-dbusmock-0.32.1/.github/workflows/tests.yml --- old/python-dbusmock-0.31.1/.github/workflows/tests.yml 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/.github/workflows/tests.yml 2024-07-14 09:17:09.000000000 +0200 @@ -17,8 +17,8 @@ - docker.io/ubuntu:latest - registry.fedoraproject.org/fedora:latest - registry.fedoraproject.org/fedora:rawhide - - quay.io/centos/centos:stream8 - quay.io/centos/centos:stream9 + - quay.io/centos/centos:stream10-development timeout-minutes: 30 steps: @@ -28,6 +28,14 @@ # need this to also fetch tags fetch-depth: 0 + - name: Workaround for https://github.com/actions/checkout/pull/697 + run: | + set -ex + TAG=$(git describe --tags) + if echo "$TAG" | grep -q '^[0-9.]\+$'; then + git fetch --force origin $TAG:refs/tags/$TAG + fi + - name: Run unit tests run: | dpkg -s podman docker || true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/PKG-INFO new/python-dbusmock-0.32.1/PKG-INFO --- old/python-dbusmock-0.31.1/PKG-INFO 2024-02-23 14:06:27.321855500 +0100 +++ new/python-dbusmock-0.32.1/PKG-INFO 2024-07-14 09:17:21.458633000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-dbusmock -Version: 0.31.1 +Version: 0.32.1 Summary: Mock D-Bus objects Home-page: https://github.com/martinpitt/python-dbusmock Author: Martin Pitt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/__main__.py new/python-dbusmock-0.32.1/dbusmock/__main__.py --- old/python-dbusmock-0.31.1/dbusmock/__main__.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/__main__.py 2024-07-14 09:17:09.000000000 +0200 @@ -16,6 +16,7 @@ import argparse import json import os +import platform import subprocess import sys @@ -51,7 +52,7 @@ help="template to load (instead of specifying name, path, interface)", ) parser.add_argument( - "name", # fmt: off + "name", metavar="NAME", nargs="?", help='D-Bus name to claim (e. g. "com.example.MyService") (if not using -t)', @@ -160,7 +161,10 @@ if args.template: main_object.AddTemplate(args.template, parameters) - libglib = ctypes.cdll.LoadLibrary("libglib-2.0.so.0") + if platform.system() == "Darwin": + libglib = ctypes.cdll.LoadLibrary("libglib-2.0.dylib") + else: + libglib = ctypes.cdll.LoadLibrary("libglib-2.0.so.0") dbusmock.mockobject.objects[args.path] = main_object diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/_version.py new/python-dbusmock-0.32.1/dbusmock/_version.py --- old/python-dbusmock-0.31.1/dbusmock/_version.py 2024-02-23 14:06:27.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/_version.py 2024-07-14 09:17:21.000000000 +0200 @@ -1,2 +1,2 @@ '''auto-generated version from setuptools_scm''' -__version__ = "0.31.1" +__version__ = "0.32.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/templates/bluez5.py new/python-dbusmock-0.32.1/dbusmock/templates/bluez5.py --- old/python-dbusmock-0.31.1/dbusmock/templates/bluez5.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/templates/bluez5.py 2024-07-14 09:17:09.000000000 +0200 @@ -38,9 +38,17 @@ NETWORK_SERVER_IFACE = "org.bluez.Network1" DEVICE_IFACE = "org.bluez.Device1" +LE_ADVERTISING_MANAGER_IFACE = "org.bluez.LEAdvertisingManager1" +LE_ADVERTISEMENT_IFACE = "org.bluez.LEAdvertisement1" +ADVERTISEMENT_MONITOR_MANAGER_IFACE = "org.bluez.AdvertisementMonitorManager1" +ADVERTISEMENT_MONITOR_IFACE = "org.bluez.AdvertisementMonitor1" + # The device class of some arbitrary Android phone. MOCK_PHONE_CLASS = 5898764 +# Maximum number of BLE advertisements supported per adapter. +MAX_ADVERTISEMENT_INSTANCES = 5 + @dbus.service.method(AGENT_MANAGER_IFACE, in_signature="os", out_signature="") def RegisterAgent(manager, agent_path, capability): @@ -48,9 +56,13 @@ if agent_path in manager.agent_paths: raise dbus.exceptions.DBusException( - "Another agent is already registered " + manager.agent_path, name="org.bluez.Error.AlreadyExists" + "Another agent is already registered " + agent_path, name="org.bluez.Error.AlreadyExists" ) + # Fallback to "KeyboardDisplay" as per BlueZ spec + if not capability: + capability = "KeyboardDisplay" + if capability not in all_caps: raise dbus.exceptions.DBusException( "Unsupported capability " + capability, name="org.bluez.Error.InvalidArguments" @@ -107,6 +119,11 @@ bluez.capabilities = {} bluez.default_agent = None + # whether to expose the LEAdvertisingManager1 interface on adapters (BLE advertising) + bluez.enable_advertise_api = _parameters.get("enable_advertise_api", True) + # whether to expose the AdvertisementMonitorManager1 interface on adapters (Passive scanning) + bluez.enable_monitor_api = _parameters.get("enable_monitor_api", True) + @dbus.service.method(ADAPTER_IFACE, in_signature="o", out_signature="") def RemoveDevice(adapter, path): @@ -221,6 +238,7 @@ "Class": dbus.UInt32(268, variant_level=1), # Computer, Laptop "DiscoverableTimeout": dbus.UInt32(180, variant_level=1), "PairableTimeout": dbus.UInt32(0, variant_level=1), + "Roles": dbus.Array(["central", "peripheral"], variant_level=1), } self.AddObject( @@ -253,6 +271,63 @@ ], ) + bluez = mockobject.objects["/org/bluez"] + + # Advertising Manager + if bluez.enable_advertise_api: + # Example values below from an Intel AX200 adapter + advertising_manager_properties = { + "ActiveInstances": dbus.Byte(0, variant_level=1), + "SupportedInstances": dbus.Byte(MAX_ADVERTISEMENT_INSTANCES, variant_level=1), + "SupportedIncludes": dbus.Array(["tx-power", "appearance", "local-name", "rssi"], variant_level=1), + "SupportedSecondaryChannels": dbus.Array(["1M", "2M", "Coded"], variant_level=1), + "SupportedCapabilities": dbus.Dictionary( + { + "MaxAdvLen": dbus.Byte(251), + "MaxScnRspLen": dbus.Byte(251), + "MinTxPower": dbus.Int16(-34), + "MaxTxPower": dbus.Int16(7), + }, + signature="sv", + variant_level=1, + ), + "SupportedFeatures": dbus.Array( + [ + "CanSetTxPower", + "HardwareOffload", + ], + variant_level=1, + ), + } + adapter.AddProperties(LE_ADVERTISING_MANAGER_IFACE, advertising_manager_properties) + adapter.AddMethods( + LE_ADVERTISING_MANAGER_IFACE, + [ + ("RegisterAdvertisement", "oa{sv}", "", RegisterAdvertisement), + ("UnregisterAdvertisement", "o", "", UnregisterAdvertisement), + ], + ) + + # Track advertisements per adapter + adapter.advertisements = [] + + # Advertisement Monitor Manager + if bluez.enable_monitor_api: + advertisement_monitor_manager_properties = { + "SupportedMonitorTypes": dbus.Array(["or_patterns"], variant_level=1), + } + adapter.AddProperties(ADVERTISEMENT_MONITOR_MANAGER_IFACE, advertisement_monitor_manager_properties) + adapter.AddMethods( + ADVERTISEMENT_MONITOR_MANAGER_IFACE, + [ + ("RegisterMonitor", "o", "", RegisterMonitor), + ("UnregisterMonitor", "o", "", UnregisterMonitor), + ], + ) + + # Track advertisement monitors per adapter + adapter.monitors = [] + manager = mockobject.objects["/"] manager.EmitSignal( OBJECT_MANAGER_IFACE, @@ -652,3 +727,137 @@ [], ], ) + + +def RegisterAdvertisement(manager, adv_path, options): # pylint: disable=unused-argument + if adv_path in manager.advertisements: + raise dbus.exceptions.DBusException("Already registered: " + adv_path, name="org.bluez.Error.AlreadyExists") + + if len(manager.advertisements) >= MAX_ADVERTISEMENT_INSTANCES: + raise dbus.exceptions.DBusException( + f"Maximum number of advertisements reached: {MAX_ADVERTISEMENT_INSTANCES}", + name="org.bluez.Error.NotPermitted", + ) + + manager.advertisements.append(adv_path) + + manager.UpdateProperties( + LE_ADVERTISING_MANAGER_IFACE, + { + "ActiveInstances": dbus.Byte(len(manager.advertisements)), + "SupportedInstances": dbus.Byte(MAX_ADVERTISEMENT_INSTANCES - len(manager.advertisements)), + }, + ) + + +def UnregisterAdvertisement(manager, adv_path): + try: + manager.advertisements.remove(adv_path) + except ValueError: + raise dbus.exceptions.DBusException( + "Unknown advertisement: " + adv_path, name="org.bluez.Error.DoesNotExist" + ) from None + + manager.UpdateProperties( + LE_ADVERTISING_MANAGER_IFACE, + { + "ActiveInstances": dbus.Byte(len(manager.advertisements)), + "SupportedInstances": dbus.Byte(MAX_ADVERTISEMENT_INSTANCES - len(manager.advertisements)), + }, + ) + + +@dbus.service.method(BLUEZ_MOCK_IFACE, in_signature="s", out_signature="s") +def AddAdvertisement(self, adv_name): + """Convenience method to add an Advertisement object + + Creates a simple broadcast advertisement with some manufacturer data. + + Returns the new object path. + """ + path = "/org/dbusmock/bluez/advertisement/" + adv_name + + adv_properties = { + "Type": dbus.String("broadcast", variant_level=1), + "ManufacturerData": dbus.Dictionary( + # 0xFFFF is the Bluetooth Company Identifier reserved for internal use and testing. + {dbus.UInt16(0xFFFF): dbus.Array([0x00, 0x01], variant_level=2)}, + signature="qv", + variant_level=1, + ), + "Includes": dbus.Array(["local-name"], variant_level=1), + } + + self.AddObject( + path, + LE_ADVERTISEMENT_IFACE, + adv_properties, + [ + ("Release", "", "", ""), + ], + ) + + return path + + +@dbus.service.method(BLUEZ_MOCK_IFACE, in_signature="s", out_signature="s") +def AddMonitor(self, monitor_name): + """Convenience method to add an Advertisement Monitor + + Returns the new object path. + """ + path = "/org/dbusmock/bluez/monitor/" + monitor_name + + monitor_properties = { + "Type": dbus.String("or_patterns", variant_level=1), + # Example pattern that could be used to scan for an advertisement created by AddAdvertisement() + "Patterns": dbus.Struct( + ( + # Start position: 0 + dbus.Byte(0), + # AD data type: Manufacturer data + dbus.Byte(0xFF), + # Vaue of the pattern: 0xFFFF (company identifier), followed by 0x01 + dbus.Array( + [ + dbus.UInt16(0xFFFF), + dbus.Byte(0x01), + ] + ), + ), + signature="yyay", + variant_level=2, + ), + } + + self.AddObject( + path, + ADVERTISEMENT_MONITOR_IFACE, + monitor_properties, + [ + ("Release", "", "", ""), + ("Activate", "", "", ""), + ("DeviceFound", "o", "", ""), + ("DeviceLost", "o", "", ""), + ], + ) + + return path + + +def RegisterMonitor(manager, monitor_path): + if monitor_path in manager.monitors: + raise dbus.exceptions.DBusException( + "Already registered: " + monitor_path, name="org.bluez.Error.AlreadyExists" + ) + + manager.monitors.append(monitor_path) + + +def UnregisterMonitor(manager, monitor_path): + try: + manager.monitors.remove(monitor_path) + except ValueError: + raise dbus.exceptions.DBusException( + "Unknown monitor: " + monitor_path, name="org.bluez.Error.DoesNotExist" + ) from None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/templates/gnome_screensaver.py new/python-dbusmock-0.32.1/dbusmock/templates/gnome_screensaver.py --- old/python-dbusmock-0.31.1/dbusmock/templates/gnome_screensaver.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/templates/gnome_screensaver.py 2024-07-14 09:17:09.000000000 +0200 @@ -28,8 +28,12 @@ [ ("GetActive", "", "b", "ret = self.is_active"), ("GetActiveTime", "", "u", "ret = 1"), - # fmt: off - ("SetActive", "b", "", 'self.is_active = args[0]; self.EmitSignal("", "ActiveChanged", "b", [self.is_active])'), + ( + "SetActive", + "b", + "", + 'self.is_active = args[0]; self.EmitSignal("", "ActiveChanged", "b", [self.is_active])', + ), ("Lock", "", "", "time.sleep(1); self.SetActive(True)"), ("ShowMessage", "sss", "", ""), ("SimulateUserActivity", "", "", ""), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/templates/modemmanager.py new/python-dbusmock-0.32.1/dbusmock/templates/modemmanager.py --- old/python-dbusmock-0.31.1/dbusmock/templates/modemmanager.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/templates/modemmanager.py 2024-07-14 09:17:09.000000000 +0200 @@ -0,0 +1,209 @@ +"""ModemManager mock template + +This creates the expected methods and properties of the main +ModemManager object, but no devices. You can specify any property +such as DaemonVersion in "parameters". +""" + +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text +# of the license. + +__author__ = "Guido Günther" +__copyright__ = "2024 The Phosh Developers" + +import dbus + +from dbusmock import MOCK_IFACE, OBJECT_MANAGER_IFACE, mockobject + +BUS_NAME = "org.freedesktop.ModemManager1" +MAIN_OBJ = "/org/freedesktop/ModemManager1" +MAIN_IFACE = "org.freedesktop.ModemManager1" +SYSTEM_BUS = True +IS_OBJECT_MANAGER = True +MODEM_IFACE = "org.freedesktop.ModemManager1.Modem" +MODEM_3GPP_IFACE = "org.freedesktop.ModemManager1.Modem.Modem3gpp" +MODEM_VOICE_IFACE = "org.freedesktop.ModemManager1.Modem.Voice" +SIM_IFACE = "org.freedesktop.ModemManager1.Sim" + + +class MMModemMode: + """ + See + https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/ModemManager-Flags-and-Enumerations.html#MMModemMode + """ + + MODE_NONE = 0 + MODE_CS = 1 << 0 + MODE_2G = 1 << 1 + MODE_3G = 1 << 2 + MODE_4G = 1 << 3 + MODE_5G = 1 << 4 + + +class MMModemState: + """ + See + https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/ModemManager-Flags-and-Enumerations.html#MMModemState + """ + + STATE_FAILED = -1 + STATE_UNKNOWN = 0 + STATE_INITIALIZING = 1 + STATE_LOCKED = 2 + STATE_DISABLED = 3 + STATE_DISABLING = 4 + STATE_ENABLING = 5 + STATE_ENABLED = 6 + STATE_SEARCHING = 7 + STATE_REGISTERED = 8 + STATE_DISCONNECTING = 9 + STATE_CONNECTING = 10 + STATE_CONNECTED = 11 + + +class MMModemPowerState: + """ + See + https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/ModemManager-Flags-and-Enumerations.html#MMModemPowerState + """ + + POWER_STATE_UNKNOWN = 0 + POWER_STATE_OFF = 1 + POWER_STATE_LOW = 2 + POWER_STATE_ON = 3 + + +class MMModemAccesssTechnology: + """ + See + https://www.freedesktop.org/software/ModemManager/doc/latest/ModemManager/ModemManager-Flags-and-Enumerations.html#MMModemAccessTechnology + """ + + ACCESS_TECHNOLOGY_UNKNOWN = 0 + ACCESS_TECHNOLOGY_POTS = 1 << 0 + ACCESS_TECHNOLOGY_GSM = 1 << 1 + ACCESS_TECHNOLOGY_GSM_COMPACT = 1 << 2 + ACCESS_TECHNOLOGY_GPRS = 1 << 3 + ACCESS_TECHNOLOGY_EDGE = 1 << 4 + ACCESS_TECHNOLOGY_UMTS = 1 << 5 + ACCESS_TECHNOLOGY_HSDPA = 1 << 6 + ACCESS_TECHNOLOGY_HSUPA = 1 << 7 + ACCESS_TECHNOLOGY_HSPA = 1 << 8 + ACCESS_TECHNOLOGY_HSPA_PLUS = 1 << 9 + ACCESS_TECHNOLOGY_1XRTT = 1 << 10 + ACCESS_TECHNOLOGY_EVDO0 = 1 << 11 + ACCESS_TECHNOLOGY_EVDOA = 1 << 12 + ACCESS_TECHNOLOGY_EVDOB = 1 << 13 + ACCESS_TECHNOLOGY_LTE = 1 << 14 + ACCESS_TECHNOLOGY_5GNR = 1 << 15 + ACCESS_TECHNOLOGY_LTE_CAT_M = 1 << 16 + ACCESS_TECHNOLOGY_LTE_NB_IOT = 1 << 17 + + +def load(mock, parameters): + methods = [ + ("ScanDevices", "", "", ""), + ] + + props = dbus.Dictionary( + { + "Version": parameters.get("DaemonVersion", "1.22"), + }, + signature="sv", + ) + + mock.AddMethods(MAIN_IFACE, methods) + mock.AddProperties(MAIN_IFACE, props) + + +@dbus.service.method(MOCK_IFACE, in_signature="", out_signature="ss") +def AddSimpleModem(self): + """Convenience method to add a simple Modem object + + Please note that this does not set any global properties. + + Returns the new object path. + """ + modem_path = "/org/freedesktop/ModemManager1/Modems/8" + sim_path = "/org/freedesktop/ModemManager1/SIM/2" + manager = mockobject.objects[MAIN_OBJ] + + modem_props = { + "State": dbus.Int32(MMModemState.STATE_ENABLED), + "Model": dbus.String("E1750"), + "Revision": dbus.String("11.126.08.01.00"), + "AccessTechnologies": dbus.UInt32(MMModemAccesssTechnology.ACCESS_TECHNOLOGY_LTE), + "PowerState": dbus.UInt32(MMModemPowerState.POWER_STATE_ON), + "UnlockRequired": dbus.UInt32(0), + "UnlockRetries": dbus.Dictionary([], signature="uu"), + "CurrentModes": dbus.Struct( + (dbus.UInt32(MMModemMode.MODE_4G), dbus.UInt32(MMModemMode.MODE_4G)), signature="(uu)" + ), + "SignalQuality": dbus.Struct( + (dbus.UInt32(70), dbus.Boolean(True)), + ), + "Sim": dbus.ObjectPath(sim_path), + "SupportedModes": [ + (dbus.UInt32(MMModemMode.MODE_4G), dbus.UInt32(MMModemMode.MODE_4G)), + (dbus.UInt32(MMModemMode.MODE_3G | MMModemMode.MODE_2G), dbus.UInt32(MMModemMode.MODE_3G)), + ], + "SupportedBands": [dbus.UInt32(0)], + } + self.AddObject(modem_path, MODEM_IFACE, modem_props, []) + + modem_3gpp_props = { + "Imei": dbus.String("doesnotmatter", variant_level=1), + "OperatorName": dbus.String("TheOperator"), + "Pco": dbus.Array([], signature="(ubay)"), + } + modem = mockobject.objects[modem_path] + modem.AddProperties(MODEM_3GPP_IFACE, modem_3gpp_props) + + modem_voice_props = { + "Calls": dbus.Array([], signature="o"), + "EmergencyOnly": False, + } + + modem.call_waiting = False + modem_voice_methods = [ + ("CallWaitingQuery", "", "b", "ret = self.call_waiting"), + ("CallWaitingSetup", "b", "", "self.call_waiting = args[0]"), + ] + modem = mockobject.objects[modem_path] + modem.AddProperties(MODEM_VOICE_IFACE, modem_voice_props) + modem.AddMethods(MODEM_VOICE_IFACE, modem_voice_methods) + + manager.EmitSignal( + OBJECT_MANAGER_IFACE, + "InterfacesAdded", + "oa{sa{sv}}", + [ + dbus.ObjectPath(modem_path), + { + MODEM_IFACE: modem_props, + MODEM_3GPP_IFACE: modem_3gpp_props, + MODEM_VOICE_IFACE: modem_voice_props, + }, + ], + ) + + sim_props = { + "Active": dbus.Boolean(True), + "Imsi": dbus.String("doesnotmatter"), + "PreferredNetworks": dbus.Array([], signature="(su)"), + } + self.AddObject(sim_path, SIM_IFACE, sim_props, []) + manager.EmitSignal( + OBJECT_MANAGER_IFACE, + "InterfacesAdded", + "oa{sa{sv}}", + [ + dbus.ObjectPath(sim_path), + {SIM_IFACE: sim_props}, + ], + ) + + return (modem_path, sim_path) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/dbusmock/templates/networkmanager.py new/python-dbusmock-0.32.1/dbusmock/templates/networkmanager.py --- old/python-dbusmock-0.31.1/dbusmock/templates/networkmanager.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/dbusmock/templates/networkmanager.py 2024-07-14 09:17:09.000000000 +0200 @@ -42,7 +42,7 @@ # these really want to be dataclasses, but need to drop support for Python 3.6 for that -class NMState: # pylint: disable=too-few-public-methods +class NMState: """Global state As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMState @@ -58,7 +58,7 @@ NM_STATE_CONNECTED_GLOBAL = 70 -class NMConnectivityState: # pylint: disable=too-few-public-methods +class NMConnectivityState: """Connectvity state As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMConnectivityState @@ -71,7 +71,7 @@ NM_CONNECTIVITY_FULL = 4 -class NMActiveConnectionState: # pylint: disable=too-few-public-methods +class NMActiveConnectionState: """Active connection state As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMActiveConnectionState @@ -84,7 +84,7 @@ NM_ACTIVE_CONNECTION_STATE_DEACTIVATED = 4 -class InfrastructureMode: # pylint: disable=too-few-public-methods +class InfrastructureMode: """Infrastructure mode As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NM80211Mode @@ -103,7 +103,7 @@ } -class DeviceState: # pylint: disable=too-few-public-methods +class DeviceState: """Device states As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NMDeviceState @@ -124,7 +124,7 @@ FAILED = 120 -class NM80211ApSecurityFlags: # pylint: disable=too-few-public-methods +class NM80211ApSecurityFlags: """Security flags As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NM80211ApSecurityFlags @@ -147,7 +147,7 @@ } -class NM80211ApFlags: # pylint: disable=too-few-public-methods +class NM80211ApFlags: """Device flags As per https://developer.gnome.org/NetworkManager/unstable/nm-dbus-types.html#NM80211ApFlags diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/packaging/python-dbusmock.spec new/python-dbusmock-0.32.1/packaging/python-dbusmock.spec --- old/python-dbusmock-0.31.1/packaging/python-dbusmock.spec 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/packaging/python-dbusmock.spec 2024-07-14 09:17:09.000000000 +0200 @@ -34,7 +34,7 @@ %description -n python3-dbusmock %_description %prep -%autosetup -n %{name}-%{version} -S git +%autosetup -n %{name}-%{version} rm -rf python-%{modname}.egg-info diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/packit.yaml new/python-dbusmock-0.32.1/packit.yaml --- old/python-dbusmock-0.31.1/packit.yaml 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/packit.yaml 2024-07-14 09:17:09.000000000 +0200 @@ -23,15 +23,17 @@ trigger: pull_request targets: - fedora-all - - centos-stream-8-x86_64 - centos-stream-9-x86_64 + # FIXME: broken + # - centos-stream-10-x86_64 - job: tests trigger: pull_request targets: - fedora-all - - centos-stream-8-x86_64 - centos-stream-9-x86_64 + # FIXME: broken rpm build above + # - centos-stream-10-x86_64 - job: propose_downstream trigger: release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/python_dbusmock.egg-info/PKG-INFO new/python-dbusmock-0.32.1/python_dbusmock.egg-info/PKG-INFO --- old/python-dbusmock-0.31.1/python_dbusmock.egg-info/PKG-INFO 2024-02-23 14:06:27.000000000 +0100 +++ new/python-dbusmock-0.32.1/python_dbusmock.egg-info/PKG-INFO 2024-07-14 09:17:21.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: python-dbusmock -Version: 0.31.1 +Version: 0.32.1 Summary: Mock D-Bus objects Home-page: https://github.com/martinpitt/python-dbusmock Author: Martin Pitt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/python_dbusmock.egg-info/SOURCES.txt new/python-dbusmock-0.32.1/python_dbusmock.egg-info/SOURCES.txt --- old/python-dbusmock-0.31.1/python_dbusmock.egg-info/SOURCES.txt 2024-02-23 14:06:27.000000000 +0100 +++ new/python-dbusmock-0.32.1/python_dbusmock.egg-info/SOURCES.txt 2024-07-14 09:17:21.000000000 +0200 @@ -26,6 +26,7 @@ dbusmock/templates/iio-sensors-proxy.py dbusmock/templates/logind.py dbusmock/templates/low_memory_monitor.py +dbusmock/templates/modemmanager.py dbusmock/templates/networkmanager.py dbusmock/templates/notification_daemon.py dbusmock/templates/ofono.py @@ -62,6 +63,7 @@ tests/test_iio_sensors_proxy.py tests/test_logind.py tests/test_low_memory_monitor.py +tests/test_modemmanager.py tests/test_networkmanager.py tests/test_notification_daemon.py tests/test_ofono.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/run-centos new/python-dbusmock-0.32.1/tests/run-centos --- old/python-dbusmock-0.31.1/tests/run-centos 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/run-centos 2024-07-14 09:17:09.000000000 +0200 @@ -2,11 +2,14 @@ set -eux # install build dependencies dnf -y install python3-setuptools python3 python3-gobject-base \ - python3-dbus python3-pytest dbus-x11 util-linux \ + python3-dbus dbus-x11 util-linux \ upower NetworkManager bluez libnotify polkit if ! grep -q :el /etc/os-release; then - dnf -y install power-profiles-daemon iio-sensor-proxy + dnf -y install power-profiles-daemon iio-sensor-proxy python3-pytest +else + dnf -y install python3-pip + pip install pytest fi if [ "$SKIP_STATIC_CHECKS" != "1" ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/run-debian new/python-dbusmock-0.32.1/tests/run-debian --- old/python-dbusmock-0.31.1/tests/run-debian 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/run-debian 2024-07-14 09:17:09.000000000 +0200 @@ -14,7 +14,8 @@ eatmydata apt-get install --no-install-recommends -y git \ python3-all python3-setuptools python3-setuptools-scm python3-build python3-venv \ python3-dbus python3-pytest python3-gi gir1.2-glib-2.0 \ - dbus libnotify-bin upower network-manager bluez ofono ofono-scripts power-profiles-daemon + dbus libnotify-bin upower network-manager bluez ofono ofono-scripts power-profiles-daemon \ + modemmanager # systemd's tools otherwise fail on "not been booted with systemd" mkdir -p /run/systemd/system @@ -39,16 +40,14 @@ # test sdist with direct setuptools ./setup.py sdist -tar --wildcards --strip-components=1 -xvf dist/python-dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' +tar --wildcards --strip-components=1 -xvf dist/python[_-]dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' grep "^Version: \${my_version}" PKG-INFO grep "^## Purpose" PKG-INFO git clean -ffdx -# test sdist with PyPA build; note https://bugs.debian.org/1009916 -if dpkg --compare-versions \$(dpkg-query -f '\${Version}' --show python3-build) '>=' 0.7.0-3; then - python3 -m build --sdist - tar --wildcards --strip-components=1 -xvf dist/python-dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' - grep "^Version: \${my_version}" PKG-INFO - grep "^## Purpose" PKG-INFO -fi +# test sdist with PyPA build +python3 -m build --sdist +tar --wildcards --strip-components=1 -xvf dist/python_dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' +grep "^Version: \${my_version}" PKG-INFO +grep "^## Purpose" PKG-INFO EOF diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/run-fedora new/python-dbusmock-0.32.1/tests/run-fedora --- old/python-dbusmock-0.31.1/tests/run-fedora 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/run-fedora 2024-07-14 09:17:09.000000000 +0200 @@ -2,11 +2,14 @@ set -eux # install build dependencies dnf -y install python3-setuptools python3 python3-gobject-base \ - python3-dbus python3-pytest dbus-x11 util-linux \ + python3-dbus dbus-x11 util-linux \ upower NetworkManager bluez libnotify polkit if ! grep -q :el /etc/os-release; then - dnf -y install power-profiles-daemon iio-sensor-proxy + dnf -y install power-profiles-daemon iio-sensor-proxy python3-pytest +else + dnf -y install python3-pip + pip install pytest fi if [ "$SKIP_STATIC_CHECKS" != "1" ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/run-ubuntu new/python-dbusmock-0.32.1/tests/run-ubuntu --- old/python-dbusmock-0.31.1/tests/run-ubuntu 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/run-ubuntu 2024-07-14 09:17:09.000000000 +0200 @@ -14,7 +14,8 @@ eatmydata apt-get install --no-install-recommends -y git \ python3-all python3-setuptools python3-setuptools-scm python3-build python3-venv \ python3-dbus python3-pytest python3-gi gir1.2-glib-2.0 \ - dbus libnotify-bin upower network-manager bluez ofono ofono-scripts power-profiles-daemon + dbus libnotify-bin upower network-manager bluez ofono ofono-scripts power-profiles-daemon \ + modemmanager # systemd's tools otherwise fail on "not been booted with systemd" mkdir -p /run/systemd/system @@ -39,16 +40,14 @@ # test sdist with direct setuptools ./setup.py sdist -tar --wildcards --strip-components=1 -xvf dist/python-dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' +tar --wildcards --strip-components=1 -xvf dist/python[_-]dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' grep "^Version: \${my_version}" PKG-INFO grep "^## Purpose" PKG-INFO git clean -ffdx -# test sdist with PyPA build; note https://bugs.debian.org/1009916 -if dpkg --compare-versions \$(dpkg-query -f '\${Version}' --show python3-build) '>=' 0.7.0-3; then - python3 -m build --sdist - tar --wildcards --strip-components=1 -xvf dist/python-dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' - grep "^Version: \${my_version}" PKG-INFO - grep "^## Purpose" PKG-INFO -fi +# test sdist with PyPA build +python3 -m build --sdist +tar --wildcards --strip-components=1 -xvf dist/python_dbusmock-\${my_version}*.tar.gz '*/PKG-INFO' +grep "^Version: \${my_version}" PKG-INFO +grep "^## Purpose" PKG-INFO EOF diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/test_bluez5.py new/python-dbusmock-0.32.1/tests/test_bluez5.py --- old/python-dbusmock-0.31.1/tests/test_bluez5.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/test_bluez5.py 2024-07-14 09:17:09.000000000 +0200 @@ -25,6 +25,7 @@ from gi.repository import GLib import dbusmock +from packaging.version import Version tracemalloc.start(25) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) @@ -89,6 +90,10 @@ cls.dbus_con = cls.get_dbus(True) (cls.p_mock, cls.obj_bluez) = cls.spawn_server_template("bluez5", {}, stdout=subprocess.PIPE) + out = _run_bluetoothctl("version") + version = next(line.split(" ")[-1] for line in out if line.startswith("Version")) + cls.bluez5_version = Version(version) + def setUp(self): self.obj_bluez.Reset() self.dbusmock = dbus.Interface(self.obj_bluez, dbusmock.MOCK_IFACE) @@ -128,6 +133,43 @@ self.assertIn("Discoverable: no", out) self.assertIn("Pairable: yes", out) self.assertIn("Discovering: no", out) + self.assertIn("Roles: central", out) + self.assertIn("Roles: peripheral", out) + + # Advertising Manager + self.assertIn("Advertising Features:", out) + self.assertIn("ActiveInstances: 0x00 (0)", out) + self.assertIn("SupportedInstances: 0x05 (5)", out) + self.assertIn("SupportedIncludes: tx-power", out) + self.assertIn("SupportedIncludes: appearance", out) + self.assertIn("SupportedIncludes: local-name", out) + self.assertIn("SupportedSecondaryChannels: 1M", out) + self.assertIn("SupportedSecondaryChannels: 2M", out) + + # SupportedFeatures was added to the API with BlueZ 5.57 + if self.bluez5_version >= Version("5.57"): + self.assertIn("SupportedFeatures: CanSetTxPower", out) + self.assertIn("SupportedFeatures: HardwareOffload", out) + + # Capabilities key-value format was changed in BlueZ 5.70 + if self.bluez5_version <= Version("5.70"): + capabilities = [ + ["SupportedCapabilities Key: MinTxPower", "SupportedCapabilities Value: -34"], + ["SupportedCapabilities Key: MaxTxPower", "SupportedCapabilities Value: 7"], + ["SupportedCapabilities Key: MaxAdvLen", "SupportedCapabilities Value: 0xfb (251)"], + ["SupportedCapabilities Key: MaxScnRspLen", "SupportedCapabilities Value: 0xfb (251)"], + ] + for capability in capabilities: + self.assertTrue(all(cap in out for cap in capability), f"Expected ${capability} in: ${out}") + else: + self.assertIn("SupportedCapabilities.MinTxPower: 0xffffffde (-34)", out) + self.assertIn("SupportedCapabilities.MaxTxPower: 0x0007 (7)", out) + self.assertIn("SupportedCapabilities.MaxAdvLen: 0xfb (251)", out) + self.assertIn("SupportedCapabilities.MaxScnRspLen: 0xfb (251)", out) + + # Advertisement Monitor + self.assertIn("Advertisement Monitor Features:", out) + self.assertIn("SupportedMonitorTypes: or_patterns", out) def test_no_devices(self): # Add an adapter. @@ -187,6 +229,283 @@ self.assertIn("Device " + address, out) self.assertIn("Paired: yes", out) + def test_add_advertisement(self): + # When an advertisement is added + adv_path = self.dbusmock_bluez.AddAdvertisement("bc001") + # Then the path is returned + self.assertEqual(adv_path, "/org/dbusmock/bluez/advertisement/bc001") + # And the object is exported on the bus + adv = self.dbus_con.get_object("org.bluez", adv_path) + adv_type = adv.Get("org.bluez.LEAdvertisement1", "Type", dbus_interface="org.freedesktop.DBus.Properties") + # And has the correct properties + self.assertEqual(adv_type, "broadcast") + + def test_register_advertisement(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_manager = dbus.Interface(adapter, "org.bluez.LEAdvertisingManager1") + props = dbus.Interface(adapter, "org.freedesktop.DBus.Properties") + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + + # And no active instances + self.assertEqual(active_instances, 0) + self.assertEqual(supported_instances, 5) + + # When an advertisement is registered + # Then no error is raised + adv_manager.RegisterAdvertisement("/adv0", {}) + + # And active instances is incremented + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + self.assertEqual(active_instances, 1) + # And supported instances is decremented + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + self.assertEqual(supported_instances, 4) + + def test_register_advertisement_duplicate(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_manager = dbus.Interface(adapter, "org.bluez.LEAdvertisingManager1") + props = dbus.Interface(adapter, "org.freedesktop.DBus.Properties") + + # When an advertisement is registered twice + adv_manager.RegisterAdvertisement("/adv0", {}) + + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, "Already registered") as ctx: + adv_manager.RegisterAdvertisement("/adv0", {}) + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.AlreadyExists") + + # And active instances is not incremented + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + self.assertEqual(active_instances, 1) + # And supported instances is not decremented + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + self.assertEqual(supported_instances, 4) + + def test_register_advertisement_max_instances(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_manager = dbus.Interface(adapter, "org.bluez.LEAdvertisingManager1") + props = dbus.Interface(adapter, "org.freedesktop.DBus.Properties") + max_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + + # When more advertisements are registered than supported + for i in range(max_instances): + adv_manager.RegisterAdvertisement(f"/adv{i}", {}) + + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, "Maximum number of advertisements reached") as ctx: + adv_manager.RegisterAdvertisement(f"/adv{int(max_instances)}", {}) + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.NotPermitted") + + # And active instances is equal to the number of supported instances + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + self.assertEqual(active_instances, max_instances) + # And supported instances is now zero + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + self.assertEqual(supported_instances, 0) + + def test_unregister_advertisement(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_manager = dbus.Interface(adapter, "org.bluez.LEAdvertisingManager1") + props = dbus.Interface(adapter, "org.freedesktop.DBus.Properties") + + # And a registered advertisement + adv_manager.RegisterAdvertisement("/adv0", {}) + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + self.assertEqual(active_instances, 1) + self.assertEqual(supported_instances, 4) + + # When the advertisement is unregistered + # Then no error is raised + adv_manager.UnregisterAdvertisement("/adv0") + # And active instances is decremented + active_instances = props.Get(adv_manager.dbus_interface, "ActiveInstances") + self.assertEqual(active_instances, 0) + # And supported instances is incremented + supported_instances = props.Get(adv_manager.dbus_interface, "SupportedInstances") + self.assertEqual(supported_instances, 5) + + def test_unregister_advertisement_unknown(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_manager = dbus.Interface(adapter, "org.bluez.LEAdvertisingManager1") + + # When an advertisement is unregistered without registering it first + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, "Unknown advertisement") as ctx: + adv_manager.UnregisterAdvertisement("/adv0") + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.DoesNotExist") + + def test_add_monitor(self): + # When an advertisement monitor is added + adv_path = self.dbusmock_bluez.AddMonitor("mon001") + # Then the path is returned + self.assertEqual(adv_path, "/org/dbusmock/bluez/monitor/mon001") + # And the object is exported on the bus + adv = self.dbus_con.get_object("org.bluez", adv_path) + adv_type = adv.Get( + "org.bluez.AdvertisementMonitor1", "Type", dbus_interface="org.freedesktop.DBus.Properties" + ) + # And has the correct properties + self.assertEqual(adv_type, "or_patterns") + + def test_register_monitor(self): + # Given an adapter with the AdvertisementMonitorManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_monitor_manager = dbus.Interface(adapter, "org.bluez.AdvertisementMonitorManager1") + + # When an advertisement monitor is registered + # Then no error is raised + adv_monitor_manager.RegisterMonitor("/monitor0") + + def test_register_monitor_duplicate(self): + # Given an adapter with the AdvertisementMonitorManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_monitor_manager = dbus.Interface(adapter, "org.bluez.AdvertisementMonitorManager1") + + # When an advertisement monitor is registered twice + adv_monitor_manager.RegisterMonitor("/monitor0") + + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, "Already registered") as ctx: + adv_monitor_manager.RegisterMonitor("/monitor0") + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.AlreadyExists") + + def test_unregister_monitor(self): + # Given an adapter with the AdvertisementMonitorManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_monitor_manager = dbus.Interface(adapter, "org.bluez.AdvertisementMonitorManager1") + + # And a registered advertisement monitor + adv_monitor_manager.RegisterMonitor("/monitor0") + # When the advertisement monitor is unregistered + # Then no error is raised + adv_monitor_manager.UnregisterMonitor("/monitor0") + + def test_unregister_monitor_unknown(self): + # Given an adapter with the AdvertisementMonitorManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + adv_monitor_manager = dbus.Interface(adapter, "org.bluez.AdvertisementMonitorManager1") + + # When an advertisement monitor is unregistered without registering it first + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, "Unknown monitor") as ctx: + adv_monitor_manager.UnregisterMonitor("/monitor0") + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.DoesNotExist") + + def test_advertise(self): + # Given an adapter with the LEAdvertisingManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + + # When an advertisement is started via bluetoothctl + _run_bluetoothctl("advertise broadcast") + + # Then the RegisterAdvertisement method was called + mock_calls = adapter.GetMethodCalls("RegisterAdvertisement", dbus_interface="org.freedesktop.DBus.Mock") + self.assertEqual(len(mock_calls), 1) + path, *_ = mock_calls[0][1] + self.assertEqual(path, "/org/bluez/advertising") + + def test_monitor(self): + # Given an adapter with the AdvertisementMonitorManager1 interface + path = self.dbusmock_bluez.AddAdapter("hci0", "my-computer") + adapter = self.dbus_con.get_object("org.bluez", path) + + # When an advertisement monitor is configured via bluetoothctl + out = _run_bluetoothctl("monitor.add-or-pattern 0 255 0x01") + + # Then bluetoothctl reports success + self.assertIn("Advertisement Monitor 0 added", out) + + # And the RegisterMonitor method was called + mock_calls = adapter.GetMethodCalls("RegisterMonitor", dbus_interface="org.freedesktop.DBus.Mock") + self.assertEqual(len(mock_calls), 1) + path, *_ = mock_calls[0][1] + self.assertEqual(path, "/") + + def test_register_agent(self): + # Given BlueZ with the AgentManager1 interface + bluez = self.dbus_con.get_object("org.bluez", "/org/bluez") + agent_manager = dbus.Interface(bluez, "org.bluez.AgentManager1") + agent_path = "/org/dbusmock/bluezagent" + + # When an agent with the default capabiities is registered + # Then no error is raised + agent_manager.RegisterAgent(agent_path, "") + + def test_register_agent_duplicate(self): + # Given BlueZ with the AgentManager1 interface + bluez = self.dbus_con.get_object("org.bluez", "/org/bluez") + agent_manager = dbus.Interface(bluez, "org.bluez.AgentManager1") + agent_path = "/org/dbusmock/bluezagent" + + # When an agent is registered twice + agent_manager.RegisterAgent(agent_path, "") + + # Then an error is raised + with self.assertRaisesRegex( + dbus.exceptions.DBusException, f"Another agent is already registered {agent_path}" + ) as ctx: + agent_manager.RegisterAgent(agent_path, "") + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.AlreadyExists") + + def test_unregister_agent(self): + # Given BlueZ with the AgentManager1 interface + bluez = self.dbus_con.get_object("org.bluez", "/org/bluez") + agent_manager = dbus.Interface(bluez, "org.bluez.AgentManager1") + agent_path = "/org/dbusmock/bluezagent" + + # And a registered agent + agent_manager.RegisterAgent(agent_path, "") + # When the agent is unregistered + # Then no error is raised + agent_manager.UnregisterAgent(agent_path) + + def test_unregister_agent_unknown(self): + # Given BlueZ with the AgentManager1 interface + bluez = self.dbus_con.get_object("org.bluez", "/org/bluez") + agent_manager = dbus.Interface(bluez, "org.bluez.AgentManager1") + agent_path = "/org/dbusmock/bluezagent" + + # When an agent is unregistered without registering it first + # Then an error is raised + with self.assertRaisesRegex(dbus.exceptions.DBusException, f"Agent not registered {agent_path}") as ctx: + agent_manager.UnregisterAgent(agent_path) + self.assertEqual(ctx.exception.get_dbus_name(), "org.bluez.Error.DoesNotExist") + + def test_agent(self): + # Given BlueZ with the AgentManager1 interface + bluez = self.dbus_con.get_object("org.bluez", "/org/bluez") + + # When bluetoothctl is started + out = _run_bluetoothctl("list") + + # Then it reports that the agent was registered + if self.bluez5_version >= Version("5.57"): + self.assertIn("Agent registered", out) + + # And the RegisterAgent method was called + mock_calls = bluez.GetMethodCalls("RegisterAgent", dbus_interface="org.freedesktop.DBus.Mock") + self.assertEqual(len(mock_calls), 1) + path, capabilities = mock_calls[0][1] + self.assertEqual(path, "/org/bluez/agent") + self.assertEqual(capabilities, "") + @unittest.skipUnless(have_pbap_client, "pbap-client not installed (copy it from bluez/test)") class TestBlueZObex(dbusmock.DBusTestCase): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/test_code.py new/python-dbusmock-0.32.1/tests/test_code.py --- old/python-dbusmock-0.31.1/tests/test_code.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/test_code.py 2024-07-14 09:17:09.000000000 +0200 @@ -35,6 +35,7 @@ "--score=n", "--disable=missing-function-docstring,R0801", "--disable=too-many-arguments,too-many-instance-attributes", + "--disable=too-few-public-methods", "dbusmock/templates/", ] ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/test_modemmanager.py new/python-dbusmock-0.32.1/tests/test_modemmanager.py --- old/python-dbusmock-0.31.1/tests/test_modemmanager.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/test_modemmanager.py 2024-07-14 09:17:09.000000000 +0200 @@ -0,0 +1,144 @@ +""" Tests for accounts service """ + +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text +# of the license. + +__author__ = "Guido Günther" +__copyright__ = """ +(c) 2024 The Phosh Developers +""" + +import shutil +import subprocess +import sys +import unittest + +import dbus +import dbus.mainloop.glib + +import dbusmock + +dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + +have_mmcli = shutil.which("mmcli") + + +class TestModemManagerBase(dbusmock.DBusTestCase): + """Test mocking ModemManager""" + + dbus_interface = "" + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.start_system_bus() + cls.dbus_con = cls.get_dbus(True) + + def setUp(self): + super().setUp() + (self.p_mock, self.p_obj) = self.spawn_server_template("modemmanager", {}, stdout=subprocess.PIPE) + + def tearDown(self): + if self.p_mock: + self.p_mock.stdout.close() + self.p_mock.terminate() + self.p_mock.wait() + + super().tearDown() + + def get_property(self, name): + return self.p_obj.Get(self.dbus_interface, name, dbus_interface=dbus.PROPERTIES_IFACE) + + +@unittest.skipUnless(have_mmcli, "mmcli utility not available") +class TestModemManagerMmcliBase(TestModemManagerBase): + """Base ModemManager interface tests using mmcli""" + + ret = None + + def run_mmcli(self, args): + self.assertIsNone(self.ret) + self.ret = subprocess.run( # pylint: disable=subprocess-run-check + ["mmcli", *args], capture_output=True, text=True + ) + + def assertOutputEquals(self, expected_lines): + self.assertIsNotNone(self.ret) + lines = self.ret.stdout.split("\n") + self.assertEqual(len(lines), len(expected_lines)) + for expected, line in zip(expected_lines, lines): + self.assertEqual(expected, line) + + def assertOutputContainsLine(self, expected_line, ret=0): + self.assertEqual(self.ret.returncode, ret) + self.assertIn(expected_line, self.ret.stdout) + + +class TestModemManagerModemMmcli(TestModemManagerMmcliBase): + """main ModemManager interface tests using mmcli""" + + def test_no_modems(self): + self.run_mmcli(["-m", "any"]) + self.assertEqual(self.ret.returncode, 1) + self.assertIn("error: couldn't find modem", self.ret.stderr) + + def test_modem(self): + self.p_obj.AddSimpleModem() + self.run_mmcli(["-m", "any"]) + self.assertOutputEquals( + [ + " -----------------------------", + " General | path: /org/freedesktop/ModemManager1/Modems/8", + " -----------------------------", + " Hardware | model: E1750", + " | firmware revision: 11.126.08.01.00", + " -----------------------------", + " Status | state: enabled", + " | power state: on", + " | access tech: lte", + " | signal quality: 70% (recent)", + " -----------------------------", + " Modes | supported: allowed: 4g; preferred: 4g", + " | allowed: 2g, 3g; preferred: 3g", + " | current: allowed: 4g; preferred: 4g", + " -----------------------------", + " 3GPP | imei: doesnotmatter", + " | operator name: TheOperator", + " | registration: idle", + " -----------------------------", + " SIM | primary sim path: /org/freedesktop/ModemManager1/SIM/2", + "", + ] + ) + + def test_sim(self): + self.p_obj.AddSimpleModem() + self.run_mmcli(["-i", "any"]) + self.assertOutputEquals( + [ + " --------------------", + " General | path: /org/freedesktop/ModemManager1/SIM/2", + " --------------------", + " Properties | active: yes", + " | imsi: doesnotmatter", + "", + ] + ) + + def test_voice_call_list(self): + self.p_obj.AddSimpleModem() + self.run_mmcli(["-m", "any", "--voice-list-calls"]) + self.assertOutputContainsLine("No calls were found\n") + + def test_voice_status(self): + self.p_obj.AddSimpleModem() + self.run_mmcli(["-m", "any", "--voice-status"]) + self.assertOutputContainsLine("emergency only: no\n") + + +if __name__ == "__main__": + # avoid writing to stderr + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-dbusmock-0.31.1/tests/test_power_profiles_daemon.py new/python-dbusmock-0.32.1/tests/test_power_profiles_daemon.py --- old/python-dbusmock-0.31.1/tests/test_power_profiles_daemon.py 2024-02-23 14:06:17.000000000 +0100 +++ new/python-dbusmock-0.32.1/tests/test_power_profiles_daemon.py 2024-07-14 09:17:09.000000000 +0200 @@ -12,6 +12,7 @@ import fcntl import os +import re import shutil import subprocess import sys @@ -40,9 +41,8 @@ def setUp(self): # depending on the installed client version, we need to pick the right template try: - version = subprocess.run( - ["powerprofilesctl", "version"], capture_output=True, text=True, check=True - ).stdout + out = subprocess.run(["powerprofilesctl", "version"], capture_output=True, text=True, check=True).stdout + version = re.search(r"[0-9.]+", out).group(0) version = ".".join(version.strip().split(".")[:2]) template = "power_profiles_daemon" if float(version) < 0.2 else "upower_power_profiles_daemon" except subprocess.CalledProcessError as e: