././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 011452 x ustar 00 0000000 0000000 28 mtime=1649137868.5411122
python-dbusmock-0.27.5/ 0000755 0001751 0000171 00000000000 00000000000 015533 5 ustar 00runner docker 0000000 0000000 ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/COPYING 0000644 0001751 0000171 00000016743 00000000000 016601 0 ustar 00runner docker 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/MANIFEST.in 0000644 0001751 0000171 00000000061 00000000000 017266 0 ustar 00runner docker 0000000 0000000 include tests/*.py
include COPYING*
include NEWS
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/NEWS 0000644 0001751 0000171 00000050013 00000000000 016231 0 ustar 00runner docker 0000000 0000000 ## [0.27.5] - 2022-04-05
- bluez and accountsservice templates: Drop default arguments from D-Bus methods (thanks Simon McVittie)
## [0.27.4] - 2022-04-04
- Fix D-Bus signature detection regression from 0.27.0 (thanks Peter Hutterer) (#118)
## [0.27.3] - 2022-03-22
- packit: Fix file name to sync
## [0.27.2] - 2022-03-22
- packit: Really fix Fedora dist-git syncing
## [0.27.1] - 2022-03-22
- packit: Fix Fedora dist-git syncing
## [0.27.0] - 2022-03-22
- Do not register standard session service directories, add API to enable selected services (thanks Benjamin Berg)
- Log static method calls from templates (thanks Peter Hutterer)
## [0.26.1] - 2022-02-25
- Fix README content type to Markdown, to fix releasing to PyPi
## [0.26.0] - 2022-02-25
- logind template: Add locking API (thanks Andy Holmes)
- bluez5 template: Add RemoveDevice() and RemoveAdapterWithDevices() methods,
fix properties (thanks Bastien Nocera)
- Documentation improvements, particularly wrt. raising errors
## [0.25.0] - 2021-12-25
- bluez template: Implement adapter discovery, connect, disconnect, and removal
(thanks Bastien Nocera)
- Fix changing array properties (thanks Jonas Ådahl)
- Fix CLI upower tests (thanks Marco Trevisan)
- Add testing and Fedora updating through packit
## [0.24.1] - 2021-10-27
- Do not register standard D-Bus service directories (Thanks Benjamin Berg)
- templates: Add IIO Sensors Proxy support (Thanks Marco Trevisan)
- Fix importlib module import (Thanks Marco Trevisan)
- Clean up code for most recent pylint version
## [0.24.0] - 2021-08-28
- Add Add power-profiles-daemon template (Thanks Bastien Nocera)
- logind: Implement Inhibit and ListInhibitors (Thanks to Benjamin Berg)
- Fix new complaints from pylint 2.9
## [0.23.1] - 2021-06-15
- Fix tests for Python 3.10
## [0.23.0] - 2021-03-24
- DBusMockObject: Add UpdateProperties() method (Thanks to Jonas Ådahl)
- DBusTestCase: Add bus override argument to spawn_server_template, to use
templates on either system or session bus; add corresponding --session CLI
option
- bluez template: Implement Pair() method on the Device interface and the
AgentManager1 interface (Thanks to Bastien Nocera)
- polkit template: Implement RegisterAuthenticationAgent() (Thanks to Jonas Ådahl)
- Add accountsservice template (Thanks to Marco Trevisan)
## [0.22.0] - 2021-01-02
- NetworkManager template: Fix connecting to wifi
- NetworkManager template: Add Reload() method
- tests: Replace nose test runner with standard unittest
- setup.py: Drop deprecated `test_suite`, run tests through
`python3 -m unittest` directly
## [0.21.0] - 2021-01-01
- Add type annotations to the whole API
- Drop obsolete ConsoleKit and bluez4 templates/tests
- upower template: Drop support for 0.9 API
## [0.20.0] - 2020-12-19
- NetworkManager template: Handle NetworkingEnable
- NetworkManager template: AddConnectionUnsaved
- Drop support for Python 2
## [0.19] - 2020-01-09
- NetworkManager template: Add "StateReason" property and active connection ID
- Add low-memory-monitor template
## [0.18.3] - 2019-09-08
- Fix timeouts for loaded machines and parallel tests
- Fix tests for Python 3.8
## [0.18.2] - 2019-02-23
- test: Adjust for changed version output format in systemd 241
## [0.18.1] - 2018-11-11
- test: Fix failures with systemd 239 in chroots
## [0.18] - 2018-07-01
- logind template: Add support for suspend-then-hibernate
- NetworkManager template: Add GetConnectionByUuid method
- bluez template: Add PairDevice() 'class_' parameter
- Fix logging of unicode strings in Python 2
- Adjust logind and timedated tests to systemd 239 (Debian #902602)
## [0.17.2] - 2018-03-01
- NetworkManager template: Add GetDeviceByIpIface().
- Move release tarballs from Launchpad to
.
remains as usual.
## [0.17.1] - 2018-02-22
- Fix NetworkManager tests due to name changes from 802-11-wireless to wifi.
## [0.17] - 2017-11-07
- Call dbus-daemon directly instead of dbus-launch. (Debian #836053)
- Fix DBusTestCase.stop_dbus() to actually enforce a timeout. Thanks to Renat
Galimov!
- Fix test_timedated for changed timedatectl output format in systemd 235.
## [0.16.9] - 2017-06-19
- NetworkManager template: Fix type of 'State' property in AddActiveConnection()
- Fix BlueZ tests to work with Python 2 again.
## [0.16.8] - 2017-06-12
- bluez5 template tests: Fix failure of test_no_adapters with BlueZ 5.45.
(LP: #1696480)
- tests: Move from pep8 to pycodestyle for static code tests.
- NetworkManager: Add ObjectManager, to work with NM ≥ 1.6.
## [0.16.7] - 2016-09-12
- bluez5 template tests: Fix failure on "Waiting to connect to bluetoothd"
messages.
## [0.16.6] - 2016-06-19
- upower template tests: Fix version comparison.
## [0.16.5] - 2016-06-19
- Ofono template: generate unique ICCIDs (CardIdentifier).
## [0.16.4] - 2016-06-07
- Ofono template: Add missing properties to SimManager interface.
## [0.16.3] - 2015-12-14
- NetworkManager template test: Make the test run standalone. Thanks Pete
Woods.
## [0.16.2] - 2015-12-09
- NetworkManager template: Fix connection settings Updated signal emitted by
wrong object.
- NetworkManager template: Handle empty device at connection activation.
- NetworkManager template: Implement secrets management in settings.
## [0.16.1] - 2015-10-22
- NetworkManager template: Fix indexing bug in SettingsAddConnection. Thanks
Pete Woods.
## [0.16] - 2015-10-08
- NetworkManager template: Generate a new unused name in connection activation
instead of just using the access point name. Thanks Pete Woods for the
original patch!
- Allow the passing of template parameters via the command-line as JSON
strings. Thanks Pete Woods.
## [0.15.3] - 2015-09-16
- NetworkManager template: Add missing properties to ethernet device and
active connection. Thanks Pete Woods.
- Quiesce irrelevant PEP-8 errors with pep8 1.6.
## [0.15.2] - 2015-06-11
- test_ofono: Test fields which don't get obfuscated with Ubuntu's latest
ofono (See LP #1459983). Thanks Iain Lane.
- timedated template: Add NTPSynchronized property and set it in SetNTP(), to
also work with systemd 220.
## [0.15.1] - 2015-05-12
- SECURITY FIX: When loading a template from an arbitrary file through the
AddTemplate() D-Bus method call or DBusTestCase.spawn_server_template()
Python method, don't create or use Python's *.pyc cached files. By tricking
a user into loading a template from a world-writable directory like /tmp, an
attacker could run arbitrary code with the user's privileges by putting a
crafted .pyc file into that directory. Note that this is highly unlikely to
actually appear in practice as custom dbusmock templates are usually shipped
in project directories, not directly in world-writable directories.
Thanks to Simon McVittie for discovering this!
(LP: #1453815, CVE-2015-1326)
## [0.15] - 2015-05-08
- NetworkManager template: Restore nm-specific PropertiesChanged signal
- NetworkManager template: Add DeactivateConnection(),
Settings.AddConnection(), Settings.Connection.Update(), and
Settings.Connection.Delete() methods. Also allow Connections with
autoconnect, added using AddConnection, to be automatically connected by the
first found device, roughly like NetworkManager itself does. Thanks Jonas
Grønås Drange!
- NetworkManager template: Fix broken exception in AddWiFiConnection.
- NetworkManager template: Set RsnFlags to have the same value as WpaFlags.
Thanks Pete Woods!
## [0.14] - 2015-03-30
- Move project hosting to github, update README.rst.
- urfkill template: Return boolean from block() method, as the original
urfkill does. Thanks Jonas Grønås Drange!
- Correctly instantiate DBusExceptions so that they get a proper name and
message (issue #3)
- ofono template: Fix SubscriberIdentity property type
- Emit PropertiesChanged signal when Set()ing properties.
- urfkill template: Return boolean from Block() and FlightMode() methods
- ofono template: Add ConnectionManager interface.
- NetworkManager template: Much more complete support for mocking access
points and connections.
## [0.13] - 2015-02-27
- Add urfkill template. Thanks Jussi Pakkanen!
## [0.12] - 2015-01-17
- upower template: Add SetDeviceProperties() convenience method for changing
upower device properties. Thanks Charles Kerr!
## [0.11.4] - 2014-09-22
- upower template: Go back to using type 's' for Device* signal arguments for
upower 0.9. The older library does not get along with 'o'. (Regression in
0.11.2)
## [0.11.3] - 2014-09-19
- Fix test suite crash if loginctl is not installed.
## [0.11.2] - 2014-09-19
- upower template: Fix type of Device* signal arguments to be 'o', not 's'.
Thanks Iain Lane.
- ofono template: Add org.ofono.SimManager interface. Thanks Jonas Grønås
Drange.
- bluez5 template: Fix the type of the 'Transferred' property. Thanks Philip
Withnall.
- networkmanager template: Fix the "FAILED" state value to be 120, not 12.
Thanks Jonas Grønås Drange.
- bluez5 tests: Accept devices in state "not available" (or other states) as
well.
- timedated and logind tests: Adjust to also accept output format of
systemd 215.
## [0.11.1] - 2014-08-08
- Rename bluez test classes to TestBlueZ4 and TestBlueZ5, to tell them apart
in the output.
- logind template: Fix type of IdleSinceHint property, and add
IdleSinceHintMonotonic and IdleActionUSec properties. (LP: #1348437)
- bluez4 template: Fix settings properties in StartDiscovery/StopDiscovery.
Thanks to Mathieu Trudel-Lapierre.
- NetworkManager template: Add "Devices" and "AccessPoints" properties of
NetworkManager 0.9.10. (LP: #1328579)
- NetworkManager template: Fix the types of the AccessPoint properties, and
add some more properties.
- Adjust NetworkManager template tests for changed strings in NM 0.9.10.
## [0.11] - 2014-07-24
- ofono: Fix GetOperators() to only apply to its own modem, not all modems.
Thanks to Jonas Grønås Drange.
- Add template for BlueZ 4. Thanks to Mathieu Trudel-Lapierre!
## [0.10.3] - 2014-07-16
- Fix upower tests to work for upower 0.99 in environments without a system
D-Bus.
## [0.10.2] - 2014-07-16
- ofono: Make Scan() do the same as GetOperators(). Thanks Iain Lane.
- README.rst: Clarify that the "True" argument to get_dbus() means the system
bus.
- Fix code to be compliant with pep8 1.5.
- Fix TestCLI.test_template_system test with upower 0.99. (LP: #1330037)
- ofono template: Support adding a second modem with AddModem().
(LP: #1340590)
## [0.10.1] - 2014-01-30
- Move code from bzr to git, adjust README.rst, do-release, and other files
accordingly.
- timedated template: Emit PropertiesChanged when setting properties. Thanks
Iain Lane.
## [0.10] - 2013-12-18
- Add dynamic properties to introspection XML, to make mocked properties work
with Qt's property support, d-feet, and other tools. Thanks Iain Lane!
- Fix frequent KeyError() when calling static methods from a template.
Regression from 0.9.
- Support having the same method name on different D-Bus interfaces.
- Add ofono template with support for the Manager, VoiceCallManager, and
NetworkRegistration/NetworkOperator interfaces.
- Add template for systemd's timedated. Thanks Iain Lane!
## [0.9.2] - 2013-12-13
- upower template: Emit DeviceAdded when adding new a new AC adapter or
battery. Thanks Iain Lane!
- Fix ResourceWarnings in test suite.
## [0.9.1] - 2013-12-10
- Fix UnicodeDecodeError in NEWS parsing when trying to build with a C locale.
Thanks Dmitry Shachnev.
## [0.9] - 2013-11-29
- Make static template methods appear in introspection. Thanks Philip
Whitnall! (LP: #1250096)
- Add support for the D-Bus ObjectManager interface. This can now be enabled
in templates (IS_OBJECT_MANAGER = True) or the CLI (--is-object-manager/-m).
Thanks Philip Whitnall!
- Add Reset() mock interface method to reset that object’s state (including
removing all its sub-objects) as if the object or template had been
destroyed and re-created. This is intended for use at the end of test cases
to reset state before the next test case is run, as an alternative to
killing python-dbusmock and re-starting it. Thanks Philip Whitnall!
- logind template: Fix return value of CanSuspend() and related methods,
calling them previously caused a crash.
- Don't close the log file multiple times if it is shared between objects.
Thanks Philip Whitnall!
- Log calls to Get(), GetAll(), and Set().
- Add templates for BlueZ 5 and BlueZ-OBEX. These templates are moderately
well featured, though currently targeted exclusively at testing OBEX vCard
transfers from phones to computers. Thanks Philip Whitnall!
## [0.8.1] - 2013-11-11
- Fix test failure if the "upower" tool is not installed.
- Fix bad upower test which assumed a locale with a comma decimal separator.
## [0.8] - 2013-11-08
- upower template: Change default daemon version to "0.9", and fix tests to
work with both upower 0.9 and 1.0 client tool.
- upower template: Provide 1.0 API if DaemonVersion property/template
parameter gets set to >= "0.99". (LP: #1245955)
- upower template: Add SetupDisplayDevice() method on the mock interface to
conveniently configure all defined properties of the DisplayDevice. Only
available when using the 1.0 API. (LP: #1245955)
## [0.7.2] - 2013-08-30
- Add optional "timeout" argument to DBusTestCase.wait_for_bus_object().
(LP: #1218318)
- DBusTestCase.start_system_bus(): Make the fake bus look more like a real
system bus by specifying a configuration file with type "system".
## [0.7.1] - 2013-08-02
- Handle the "Disconnected" signal only if it comes from the D-Bus object, to
avoid accidentally reacting to other signals (like from BlueZ). Thanks
Lucas De Marchi.
## [0.7] - 2013-07-30
- Accept *.py files for the--template command line option, similar to
AddTemplate(). Thanks Emanuele Aina.
- Pass log file to objects created with AddObject(). Thanks Emanuele Aina.
- NetworkManager template: Add new method AddWiFiConnection(), to simulate a
connection associated to a previously added device (with AddWiFiDevice()).
Thanks Pete Woods.
## [0.6.3] - 2013-06-13
- Drop "can-suspend" and "can-hibernate" checks from upower template test.
upower 1.0 deprecates this functionality, and defaults to not building it.
## [0.6.2] - 2013-06-13
- Fix test_api.TestSubclass test to work without an existing session D-Bus.
## [0.6.1] - 2013-06-13
- Add dbusmock.__version__ attribute, as per PEP-0396.
- Fix not being able to inherit from DBusMockObject. Thanks Lucas De Marchi!
- Allow subclassed DBusMockObject constructors to specify props arguments as
None.
- Fix failing notification-daemon tests for too old libnotify. (LP: #1190208)
- notification_daemon template: Generate new IDs for Notify() calls with an
input ID of 0. (LP: #1190209 part 1)
- notification_daemon template: Send NotificationClosed signal in
CloseNotification() method for valid IDs. (LP: #1190209 part 2)
## [0.6] - 2013-03-20
- Emit MethodCalled() signal on the DBusMock interface, as an alternative way
of verifying method calls. Thanks Lars Uebernickel.
- DBusMockObject.AddTemplate() and DBusTestCase.spawn_server_template() can
now load local templates by specifying a path to a *.py file as template
name. Thanks Lucas De Marchi.
- Quit mock process if the D-Bus it connected to goes down. (LP: #1156561)
- Support Get() and GetAll() with empty interface names, default to main
interface in this case.
- Add template for systemd's logind.
## [0.5] - 2013-02-03
- upower template: Change LidIsClosed property default value to False.
- Add polkitd template. (LP: #1112551)
## [0.4.0] - 2013-01-21
- Add GetCalls(), GetMethodCalls() and ClearCalls() methods on the mock D-Bus
interface to query the call log, for cases where parsing stdout is
inconvenient. Thanks to Robert Bruce Park for the patch! (LP: #1099483)
- Document how to keep internal state in AddMethod().
- Add template for gnome-screensaver. Thanks to Bastien Nocera!
- Fix logging of signal arguments to have the same format as method call
arguments.
## [0.3.1] - 2013-01-07
- upower template: Set Energy and EnergyFull properties.
## [0.3] - 2012-12-19
- In the logging of mock method calls, log the arguments as well.
- Fix race condition in waiting for mock to get online on the bus, by avoiding
triggering D-Bus service activation with system-installed services.
- Add "notification_daemon" mock template.
## [0.2.2] - 2012-11-27
- tests: Suppress "nmcli and NetworkManager versions don't match" warning.
- networkmanager template: Add DeviceState enum for easier specification of
states. Thanks Alberto Ruiz.
- Fix deprecation warnings with PyGObject 3.7.x.
## [0.2.1] - 2012-11-15
- Fix tests to skip instead of fail if NetworkManager or upower are not
installed.
## [0.2.0] - 2012-11-15
- Turn dbusmock from a module into a package. This is transparent for API
users, but necessary for adding future subpackages and also makes the code
more maintainable.
- Run pyflakes and pep8 during test suite, if available.
- Add support for templates: You can now call AddTemplate() on the
org.freedesktop.DBus.Mock interface to load a template into the mock, or in
Python, start a server process with loading a template with
DBusTestCase.spawn_server_template(). Templates set up the common structure
of these services (their main objects, properties, and methods) so that you
do not need to carry around this common code, and only need to set up the
particular properties and specific D-Bus objects that you need. These
templates can be parameterized for common customizations, and they can
provide additional convenience methods on the org.freedesktop.DBus.Mock
interface to provide more abstract functionality like "add a battery".
- Add a first simple "upower" template with convenience methods to add AC and
battery objects, and change tests/test_upower.py to use it.
- Add a first "networkmanager" template with convenience methods to add
Ethernet/WiFi devices and access points. Thanks Iftikhar Ahmad!
- Add symbol dbusmock.MOCK_IFACE for 'org.freedesktop.DBus.Mock'.
- Add test cases for command line invocation (python3-m dbusmock ...).
## [0.1.3] - 2012-11-03
- Ship NEWS in release tarballs.
## [0.1.2] - 2012-10-10
- dbusmock.py, EmitSignal(): Convert arguments to the right data types
according to the signature.
- dbusmock.py, method calls: Convert arguments to the right data types
according to the signature.
- tests/test_api.py: Check proper handling of signature vs. argument list
length and/or type mismatch. (LP: #1064836)
- tests/test_upower.py: Add test for handling "DeviceChanged" signal.
- setup.py: Get version from NEWS file.
## [0.1.1] - 2012-10-04
- setup.py: Use README.rst as long description.
- setup.py: Add download URL.
- tests/test_consolekit.py: Skip test if ck-list-sessions is not installed.
- setup.py: Import "multiprocessing" to work around "'NoneType' object
is not callable" error when running "setup.py test" with python 2.7.
## [0.1] - 2012-10-04
- tests/test_api.py: Add tests for adding existing objects.
- dbusmock.py: Also put first (main) object into the global objects map.
- dbusmock.py: Document global objects map in AddMethod().
- tests/test_upower.py: Silence "No ... property" warnings; the test does not
create them all.
- dbusmock.py: Fix stopping of local D-Bus daemons for test subclasses.
- dbusmock.py, stop_dbus(): Wait for local D-Bus to be killed, and avoid
getting SIGTERMed ourselves.
- dbusmock.py: Add AddProperties() method to conveniently add several
properties to one interface at once. Update upower test case to use this.
- dbusmock.py: Add EmitSignal() method to emit an arbitrary signal on any
interface.
- Make code compatible with Python 2.7 as well. (LP: #1060278)
## [0.0.3] - 2012-10-01
- tests/test_api.py: Add tests for GetAll()
- wait_for_bus_object(): Poll for Introspect() instead of GetAll(), as some
services such as gnome-session don't implement GetAll() properly.
- Rename "dbus_mock" module to "dbusmock", to be more consistent with the
project name and Python module name conventions.
- Support adding properties to different interfaces.
- Support adding methods to different interfaces.
## [0.0.2] - 2012-10-01
- setup.py: Add categories.
## [0.0.1] - 2012-09-28
Initial release.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 011452 x ustar 00 0000000 0000000 28 mtime=1649137868.5411122
python-dbusmock-0.27.5/PKG-INFO 0000644 0001751 0000171 00000034514 00000000000 016637 0 ustar 00runner docker 0000000 0000000 Metadata-Version: 2.1
Name: python-dbusmock
Version: 0.27.5
Summary: Mock D-Bus objects
Home-page: https://github.com/martinpitt/python-dbusmock
Author: Martin Pitt
Author-email: martin.pitt@ubuntu.com
License: LGPL 3+
Download-URL: https://pypi.python.org/pypi/python-dbusmock/
Description: python-dbusmock
===============
## Purpose
With this program/Python library you can easily create mock objects on
D-Bus. This is useful for writing tests for software which talks to
D-Bus services such as upower, systemd, logind, gnome-session or others,
and it is hard (or impossible without root privileges) to set the state
of the real services to what you expect in your tests.
Suppose you want to write tests for gnome-settings-daemon's power
plugin, or another program that talks to upower. You want to verify that
after the configured idle time the program suspends the machine. So your
program calls `org.freedesktop.UPower.Suspend()` on the system D-Bus.
Now, your test suite should not really talk to the actual system D-Bus
and the real upower; a `make check` that suspends your machine will not
be considered very friendly by most people, and if you want to run this
in continuous integration test servers or package build environments,
chances are that your process does not have the privilege to suspend, or
there is no system bus or upower to begin with. Likewise, there is no
way for an user process to forcefully set the system/seat idle flag in
logind, so your tests cannot set up the expected test environment on the
real daemon.
That's where mock objects come into play: They look like the real API
(or at least the parts that you actually need), but they do not actually
do anything (or only some action that you specify yourself). You can
configure their state, behaviour and responses as you like in your test,
without making any assumptions about the real system status.
When using a local system/session bus, you can do unit or integration
testing without needing root privileges or disturbing a running system.
The Python API offers some convenience functions like
`start_session_bus()` and `start_system_bus()` for this, in a
`DBusTestCase` class (subclass of the standard `unittest.TestCase`).
You can use this with any programming language, as you can run the
mocker as a normal program. The actual setup of the mock (adding
objects, methods, properties, and signals) all happen via D-Bus methods
on the `org.freedesktop.DBus.Mock` interface. You just don't have the
convenience D-Bus launch API that way.
## Simple example in Python
Picking up the above example about mocking upower's `Suspend()` method,
this is how you would set up a mock upower in your test case:
```python
import dbus
import dbusmock
class TestMyProgram(dbusmock.DBusTestCase):
@classmethod
def setUpClass(cls):
cls.start_system_bus()
cls.dbus_con = cls.get_dbus(system_bus=True)
def setUp(self):
self.p_mock = self.spawn_server('org.freedesktop.UPower',
'/org/freedesktop/UPower',
'org.freedesktop.UPower',
system_bus=True,
stdout=subprocess.PIPE)
# Get a proxy for the UPower object's Mock interface
self.dbus_upower_mock = dbus.Interface(self.dbus_con.get_object(
'org.freedesktop.UPower', '/org/freedesktop/UPower'),
dbusmock.MOCK_IFACE)
self.dbus_upower_mock.AddMethod('', 'Suspend', '', '', '')
def tearDown(self):
self.p_mock.stdout.close()
self.p_mock.terminate()
self.p_mock.wait()
def test_suspend_on_idle(self):
# run your program in a way that should trigger one suspend call
# now check the log that we got one Suspend() call
self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend$')
```
Let's walk through:
- We derive our tests from `dbusmock.DBusTestCase` instead of
`unittest.TestCase` directly, to make use of the convenience API
to start a local system bus.
- `setUpClass()` starts a local system bus, and makes a connection
to it available to all methods as `dbus_con`. `True` means that we
connect to the system bus, not the session bus. We can use the
same bus for all tests, so doing this once in `setUpClass()`
instead of `setUp()` is enough.
- `setUp()` spawns the mock D-Bus server process for an initial
`/org/freedesktop/UPower` object with an `org.freedesktop.UPower`
D-Bus interface on the system bus. We capture its stdout to be
able to verify that methods were called.
We then call `org.freedesktop.DBus.Mock.AddMethod()` to add a
`Suspend()` method to our new object to the default D-Bus
interface. This will not do anything (except log its call to
stdout). It takes no input arguments, returns nothing, and does
not run any custom code.
- `tearDown()` stops our mock D-Bus server again. We do this so that
each test case has a fresh and clean upower instance, but of
course you can also set up everything in `setUpClass()` if tests
do not interfere with each other on setting up the mock.
- `test_suspend_on_idle()` is the actual test case. It needs to run
your program in a way that should trigger one suspend call. Your
program will try to call `Suspend()`, but as that's now being
served by our mock instead of upower, there will not be any actual
machine suspend. Our mock process will log the method call
together with a time stamp; you can use the latter for doing
timing related tests, but we just ignore it here.
## Simple example from shell
We use the actual session bus for this example. You can use
`dbus-run-session` to start a private one as well if you want, but that
is not part of the actual mocking.
So let's start a mock at the D-Bus name `com.example.Foo` with an
initial "main" object on path /, with the main D-Bus interface
`com.example.Foo.Manager`:
python3 -m dbusmock com.example.Foo / com.example.Foo.Manager
On another terminal, let's first see what it does:
gdbus introspect --session -d com.example.Foo -o /
You'll see that it supports the standard D-Bus `Introspectable` and
`Properties` interfaces, as well as the `org.freedesktop.DBus.Mock`
interface for controlling the mock, but no "real" functionality yet.
So let's add a method:
gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod '' Ping '' '' ''
Now you can see the new method in `introspect`, and call it:
gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Ping
The mock process in the other terminal will log the method call with a
time stamp, and you'll see something like `1348832614.970 Ping`.
Now add another method with two int arguments and a return value and
call it:
gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod \
'' Add 'ii' 'i' 'ret = args[0] + args[1]'
gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Add 2 3
This will print `(5,)` as expected (remember that the return value is
always a tuple), and again the mock process will log the Add method
call.
You can do the same operations in e. g. d-feet or any other D-Bus
language binding.
## Logging
Usually you want to verify which methods have been called on the mock
with which arguments. There are three ways to do that:
- By default, the mock process writes the call log to stdout.
- You can call the mock process with the `-l`/`--logfile` argument,
or specify a log file object in the `spawn_server()` method if you
are using Python.
- You can use the `GetCalls()`, `GetMethodCalls()` and
`ClearCalls()` methods on the `org.freedesktop.DBus.Mock` D-Bus
interface to get an array of tuples describing the calls.
## Templates
Some D-Bus services are commonly used in test suites, such as UPower or
NetworkManager. python-dbusmock provides "templates" which set up the
common structure of these services (their main objects, properties, and
methods) so that you do not need to carry around this common code, and
only need to set up the particular properties and specific D-Bus objects
that you need. These templates can be parameterized for common
customizations, and they can provide additional convenience methods on
the `org.freedesktop.DBus.Mock` interface to provide more abstract
functionality like "add a battery".
For example, for starting a server with the `upower` template in
Python you can run
(self.p_mock, self.obj_upower) = self.spawn_server_template(
'upower', {'OnBattery': True}, stdout=subprocess.PIPE)
or load a template into an already running server with the
`AddTemplate()` method; this is particularly useful if you are not using
Python:
python3 -m dbusmock --system org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower
gdbus call --system -d org.freedesktop.UPower -o /org/freedesktop/UPower -m org.freedesktop.DBus.Mock.AddTemplate 'upower' '{"OnBattery": }'
This creates all expected properties such as `DaemonVersion`, and
changes the default for one of them (`OnBattery`) through the (optional)
parameters dict.
If you do not need to specify parameters, you can do this in a simpler
way with
python3 -m dbusmock --template upower
The template does not create any devices by default. You can add some
with the template's convenience methods like
ac_path = self.dbusmock.AddAC('mock_AC', 'Mock AC')
bt_path = self.dbusmock.AddChargingBattery('mock_BAT', 'Mock Battery', 30.0, 1200)
or calling `AddObject()` yourself with the desired properties, of
course.
Templates commonly implement some non-trivial functionality with actual Python
methods and the standard [dbus-python](https://dbus.freedesktop.org/doc/dbus-python/)
[`@dbus.service.method`](https://dbus.freedesktop.org/doc/dbus-python/dbus.service.html#dbus.service.method)
decorator.
If you want to contribute a template, look at
dbusmock/templates/upower.py for a real-life implementation. You can
copy dbusmock/templates/SKELETON to your new template file name and
replace `CHANGEME` with the actual code/values.
## More Examples
Have a look at the test suite for two real-live use cases:
- `tests/test_upower.py` simulates upowerd, in a more complete way
than in above example and using the `upower` template. It verifies
that `upower --dump` is convinced that it's talking to upower.
- `tests/test_api.py` runs a mock on the session bus and exercises
all available functionality, such as adding additional objects,
properties, multiple methods, input arguments, return values, code
in methods, sending signals, raising exceptions, and introspection.
## Documentation
The `dbusmock` module has extensive documentation built in, which you
can read with e. g. `pydoc3 dbusmock`.
`pydoc3 dbusmock.DBusMockObject` shows the D-Bus API of the mock object,
i. e. methods like `AddObject()`, `AddMethod()` etc. which are used to
set up your mock object.
`pydoc3 dbusmock.DBusTestCase` shows the convenience Python API for
writing test cases with local private session/system buses and launching
the server.
`pydoc3 dbusmock.templates` shows all available templates.
`pydoc3 dbusmock.templates.NAME` shows the documentation and available
parameters for the `NAME` template.
`python3 -m dbusmock --help` shows the arguments and options for running
the mock server as a program.
## Development
python-dbusmock is hosted on https://github.com/martinpitt/python-dbusmock
Run the unit tests with
python3 -m unittest
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Other Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: POSIX :: BSD
Classifier: Operating System :: Unix
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Description-Content-Type: text/markdown
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/README.md 0000644 0001751 0000171 00000026300 00000000000 017013 0 ustar 00runner docker 0000000 0000000 python-dbusmock
===============
## Purpose
With this program/Python library you can easily create mock objects on
D-Bus. This is useful for writing tests for software which talks to
D-Bus services such as upower, systemd, logind, gnome-session or others,
and it is hard (or impossible without root privileges) to set the state
of the real services to what you expect in your tests.
Suppose you want to write tests for gnome-settings-daemon's power
plugin, or another program that talks to upower. You want to verify that
after the configured idle time the program suspends the machine. So your
program calls `org.freedesktop.UPower.Suspend()` on the system D-Bus.
Now, your test suite should not really talk to the actual system D-Bus
and the real upower; a `make check` that suspends your machine will not
be considered very friendly by most people, and if you want to run this
in continuous integration test servers or package build environments,
chances are that your process does not have the privilege to suspend, or
there is no system bus or upower to begin with. Likewise, there is no
way for an user process to forcefully set the system/seat idle flag in
logind, so your tests cannot set up the expected test environment on the
real daemon.
That's where mock objects come into play: They look like the real API
(or at least the parts that you actually need), but they do not actually
do anything (or only some action that you specify yourself). You can
configure their state, behaviour and responses as you like in your test,
without making any assumptions about the real system status.
When using a local system/session bus, you can do unit or integration
testing without needing root privileges or disturbing a running system.
The Python API offers some convenience functions like
`start_session_bus()` and `start_system_bus()` for this, in a
`DBusTestCase` class (subclass of the standard `unittest.TestCase`).
You can use this with any programming language, as you can run the
mocker as a normal program. The actual setup of the mock (adding
objects, methods, properties, and signals) all happen via D-Bus methods
on the `org.freedesktop.DBus.Mock` interface. You just don't have the
convenience D-Bus launch API that way.
## Simple example in Python
Picking up the above example about mocking upower's `Suspend()` method,
this is how you would set up a mock upower in your test case:
```python
import dbus
import dbusmock
class TestMyProgram(dbusmock.DBusTestCase):
@classmethod
def setUpClass(cls):
cls.start_system_bus()
cls.dbus_con = cls.get_dbus(system_bus=True)
def setUp(self):
self.p_mock = self.spawn_server('org.freedesktop.UPower',
'/org/freedesktop/UPower',
'org.freedesktop.UPower',
system_bus=True,
stdout=subprocess.PIPE)
# Get a proxy for the UPower object's Mock interface
self.dbus_upower_mock = dbus.Interface(self.dbus_con.get_object(
'org.freedesktop.UPower', '/org/freedesktop/UPower'),
dbusmock.MOCK_IFACE)
self.dbus_upower_mock.AddMethod('', 'Suspend', '', '', '')
def tearDown(self):
self.p_mock.stdout.close()
self.p_mock.terminate()
self.p_mock.wait()
def test_suspend_on_idle(self):
# run your program in a way that should trigger one suspend call
# now check the log that we got one Suspend() call
self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend$')
```
Let's walk through:
- We derive our tests from `dbusmock.DBusTestCase` instead of
`unittest.TestCase` directly, to make use of the convenience API
to start a local system bus.
- `setUpClass()` starts a local system bus, and makes a connection
to it available to all methods as `dbus_con`. `True` means that we
connect to the system bus, not the session bus. We can use the
same bus for all tests, so doing this once in `setUpClass()`
instead of `setUp()` is enough.
- `setUp()` spawns the mock D-Bus server process for an initial
`/org/freedesktop/UPower` object with an `org.freedesktop.UPower`
D-Bus interface on the system bus. We capture its stdout to be
able to verify that methods were called.
We then call `org.freedesktop.DBus.Mock.AddMethod()` to add a
`Suspend()` method to our new object to the default D-Bus
interface. This will not do anything (except log its call to
stdout). It takes no input arguments, returns nothing, and does
not run any custom code.
- `tearDown()` stops our mock D-Bus server again. We do this so that
each test case has a fresh and clean upower instance, but of
course you can also set up everything in `setUpClass()` if tests
do not interfere with each other on setting up the mock.
- `test_suspend_on_idle()` is the actual test case. It needs to run
your program in a way that should trigger one suspend call. Your
program will try to call `Suspend()`, but as that's now being
served by our mock instead of upower, there will not be any actual
machine suspend. Our mock process will log the method call
together with a time stamp; you can use the latter for doing
timing related tests, but we just ignore it here.
## Simple example from shell
We use the actual session bus for this example. You can use
`dbus-run-session` to start a private one as well if you want, but that
is not part of the actual mocking.
So let's start a mock at the D-Bus name `com.example.Foo` with an
initial "main" object on path /, with the main D-Bus interface
`com.example.Foo.Manager`:
python3 -m dbusmock com.example.Foo / com.example.Foo.Manager
On another terminal, let's first see what it does:
gdbus introspect --session -d com.example.Foo -o /
You'll see that it supports the standard D-Bus `Introspectable` and
`Properties` interfaces, as well as the `org.freedesktop.DBus.Mock`
interface for controlling the mock, but no "real" functionality yet.
So let's add a method:
gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod '' Ping '' '' ''
Now you can see the new method in `introspect`, and call it:
gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Ping
The mock process in the other terminal will log the method call with a
time stamp, and you'll see something like `1348832614.970 Ping`.
Now add another method with two int arguments and a return value and
call it:
gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod \
'' Add 'ii' 'i' 'ret = args[0] + args[1]'
gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Add 2 3
This will print `(5,)` as expected (remember that the return value is
always a tuple), and again the mock process will log the Add method
call.
You can do the same operations in e. g. d-feet or any other D-Bus
language binding.
## Logging
Usually you want to verify which methods have been called on the mock
with which arguments. There are three ways to do that:
- By default, the mock process writes the call log to stdout.
- You can call the mock process with the `-l`/`--logfile` argument,
or specify a log file object in the `spawn_server()` method if you
are using Python.
- You can use the `GetCalls()`, `GetMethodCalls()` and
`ClearCalls()` methods on the `org.freedesktop.DBus.Mock` D-Bus
interface to get an array of tuples describing the calls.
## Templates
Some D-Bus services are commonly used in test suites, such as UPower or
NetworkManager. python-dbusmock provides "templates" which set up the
common structure of these services (their main objects, properties, and
methods) so that you do not need to carry around this common code, and
only need to set up the particular properties and specific D-Bus objects
that you need. These templates can be parameterized for common
customizations, and they can provide additional convenience methods on
the `org.freedesktop.DBus.Mock` interface to provide more abstract
functionality like "add a battery".
For example, for starting a server with the `upower` template in
Python you can run
(self.p_mock, self.obj_upower) = self.spawn_server_template(
'upower', {'OnBattery': True}, stdout=subprocess.PIPE)
or load a template into an already running server with the
`AddTemplate()` method; this is particularly useful if you are not using
Python:
python3 -m dbusmock --system org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower
gdbus call --system -d org.freedesktop.UPower -o /org/freedesktop/UPower -m org.freedesktop.DBus.Mock.AddTemplate 'upower' '{"OnBattery": }'
This creates all expected properties such as `DaemonVersion`, and
changes the default for one of them (`OnBattery`) through the (optional)
parameters dict.
If you do not need to specify parameters, you can do this in a simpler
way with
python3 -m dbusmock --template upower
The template does not create any devices by default. You can add some
with the template's convenience methods like
ac_path = self.dbusmock.AddAC('mock_AC', 'Mock AC')
bt_path = self.dbusmock.AddChargingBattery('mock_BAT', 'Mock Battery', 30.0, 1200)
or calling `AddObject()` yourself with the desired properties, of
course.
Templates commonly implement some non-trivial functionality with actual Python
methods and the standard [dbus-python](https://dbus.freedesktop.org/doc/dbus-python/)
[`@dbus.service.method`](https://dbus.freedesktop.org/doc/dbus-python/dbus.service.html#dbus.service.method)
decorator.
If you want to contribute a template, look at
dbusmock/templates/upower.py for a real-life implementation. You can
copy dbusmock/templates/SKELETON to your new template file name and
replace `CHANGEME` with the actual code/values.
## More Examples
Have a look at the test suite for two real-live use cases:
- `tests/test_upower.py` simulates upowerd, in a more complete way
than in above example and using the `upower` template. It verifies
that `upower --dump` is convinced that it's talking to upower.
- `tests/test_api.py` runs a mock on the session bus and exercises
all available functionality, such as adding additional objects,
properties, multiple methods, input arguments, return values, code
in methods, sending signals, raising exceptions, and introspection.
## Documentation
The `dbusmock` module has extensive documentation built in, which you
can read with e. g. `pydoc3 dbusmock`.
`pydoc3 dbusmock.DBusMockObject` shows the D-Bus API of the mock object,
i. e. methods like `AddObject()`, `AddMethod()` etc. which are used to
set up your mock object.
`pydoc3 dbusmock.DBusTestCase` shows the convenience Python API for
writing test cases with local private session/system buses and launching
the server.
`pydoc3 dbusmock.templates` shows all available templates.
`pydoc3 dbusmock.templates.NAME` shows the documentation and available
parameters for the `NAME` template.
`python3 -m dbusmock --help` shows the arguments and options for running
the mock server as a program.
## Development
python-dbusmock is hosted on https://github.com/martinpitt/python-dbusmock
Run the unit tests with
python3 -m unittest
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 011452 x ustar 00 0000000 0000000 28 mtime=1649137868.5331123
python-dbusmock-0.27.5/dbusmock/ 0000755 0001751 0000171 00000000000 00000000000 017342 5 ustar 00runner docker 0000000 0000000 ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/__init__.py 0000644 0001751 0000171 00000001433 00000000000 021454 0 ustar 00runner docker 0000000 0000000 # coding: UTF-8
'''Mock D-Bus objects for test suites.'''
# 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__ = 'Martin Pitt'
__copyright__ = '(c) 2012 Canonical Ltd.'
__version__ = '0.27.5'
from dbusmock.mockobject import (DBusMockObject, MOCK_IFACE,
OBJECT_MANAGER_IFACE, get_object, get_objects)
from dbusmock.testcase import DBusTestCase
__all__ = ['DBusMockObject', 'MOCK_IFACE', 'OBJECT_MANAGER_IFACE',
'DBusTestCase', 'get_object', 'get_objects']
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/__main__.py 0000644 0001751 0000171 00000011551 00000000000 021437 0 ustar 00runner docker 0000000 0000000 # coding: UTF-8
'''Main entry point for running mock server.'''
# 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__ = 'Martin Pitt'
__copyright__ = '(c) 2012 Canonical Ltd.'
import argparse
import json
import sys
import dbusmock.mockobject
import dbusmock.testcase
def parse_args():
'''Parse command line arguments'''
parser = argparse.ArgumentParser(description='mock D-Bus object')
parser.add_argument('-s', '--system', action='store_true',
help="put object(s) on system bus (default: session bus or template's SYSTEM_BUS flag)")
parser.add_argument('--session', action='store_true',
help="put object(s) on session bus (default without template; overrides template's SYSTEM_BUS flag)")
parser.add_argument('-l', '--logfile', metavar='PATH',
help='path of log file')
parser.add_argument('-t', '--template', metavar='NAME',
help='template to load (instead of specifying name, path, interface)')
parser.add_argument('name', metavar='NAME', nargs='?',
help='D-Bus name to claim (e. g. "com.example.MyService") (if not using -t)')
parser.add_argument('path', metavar='PATH', nargs='?',
help='D-Bus object path for initial/main object (if not using -t)')
parser.add_argument('interface', metavar='INTERFACE', nargs='?',
help='main D-Bus interface name for initial object (if not using -t)')
parser.add_argument('-m', '--is-object-manager', action='store_true',
help='automatically implement the org.freedesktop.DBus.ObjectManager interface')
parser.add_argument('-p', '--parameters',
help='JSON dictionary of parameters to pass to the template')
arguments = parser.parse_args()
if arguments.template:
if arguments.name or arguments.path or arguments.interface:
parser.error('--template and specifying NAME/PATH/INTERFACE are mutually exclusive')
else:
if not arguments.name or not arguments.path or not arguments.interface:
parser.error('Not using a template, you must specify NAME, PATH, and INTERFACE')
if arguments.system and arguments.session:
parser.error('--system and --session are mutually exclusive')
return arguments
if __name__ == '__main__':
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
args = parse_args()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
system_bus = args.system
if args.template:
module = dbusmock.mockobject.load_module(args.template)
args.name = module.BUS_NAME
args.path = module.MAIN_OBJ
if not args.session and not args.system:
system_bus = module.SYSTEM_BUS
if hasattr(module, 'IS_OBJECT_MANAGER'):
args.is_object_manager = module.IS_OBJECT_MANAGER
else:
args.is_object_manager = False
if args.is_object_manager and not hasattr(module, 'MAIN_IFACE'):
args.interface = dbusmock.mockobject.OBJECT_MANAGER_IFACE
else:
args.interface = module.MAIN_IFACE
main_loop = GLib.MainLoop()
bus = dbusmock.testcase.DBusTestCase.get_dbus(system_bus)
# quit mock when the bus is going down
bus.add_signal_receiver(main_loop.quit, signal_name='Disconnected',
path='/org/freedesktop/DBus/Local',
dbus_interface='org.freedesktop.DBus.Local')
bus_name = dbus.service.BusName(args.name,
bus,
allow_replacement=True,
replace_existing=True,
do_not_queue=True)
main_object = dbusmock.mockobject.DBusMockObject(bus_name, args.path,
args.interface, {},
args.logfile,
args.is_object_manager)
parameters = None
if args.parameters:
try:
parameters = json.loads(args.parameters)
except ValueError as detail:
sys.stderr.write(f'Malformed JSON given for parameters: {detail}\n')
sys.exit(2)
if not isinstance(parameters, dict):
sys.stderr.write('JSON parameters must be a dictionary\n')
sys.exit(2)
if args.template:
main_object.AddTemplate(args.template, parameters)
dbusmock.mockobject.objects[args.path] = main_object
main_loop.run()
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/mockobject.py 0000644 0001751 0000171 00000101665 00000000000 022045 0 ustar 00runner docker 0000000 0000000 # coding: UTF-8
'''Mock D-Bus objects for test suites.'''
# 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__ = 'Martin Pitt'
__copyright__ = '(c) 2012 Canonical Ltd.'
import copy
import functools
import importlib
import importlib.util
import os
import sys
import time
import types
from typing import Optional, Dict, Any, List, Tuple, Sequence, KeysView
from xml.etree import ElementTree
import dbus
import dbus.service
# we do not use this ourselves, but mock methods often want to use this
os # pyflakes pylint: disable=pointless-statement
# global path -> DBusMockObject mapping
objects: Dict[str, 'DBusMockObject'] = {}
MOCK_IFACE = 'org.freedesktop.DBus.Mock'
OBJECT_MANAGER_IFACE = 'org.freedesktop.DBus.ObjectManager'
PropsType = Dict[str, Any]
# (in_signature, out_signature, code, dbus_wrapper_fn)
MethodType = Tuple[str, str, str, str]
# (timestamp, method_name, call_args)
CallLogType = Tuple[int, str, Sequence[Any]]
def load_module(name: str):
'''Load a mock template Python module from dbusmock/templates/'''
if os.path.exists(name) and os.path.splitext(name)[1] == '.py':
spec = importlib.util.spec_from_file_location(os.path.splitext(os.path.basename(name))[0], name)
assert spec
mod = importlib.util.module_from_spec(spec)
with open(name, encoding="UTF-8") as f:
exec(f.read(), mod.__dict__, mod.__dict__) # pylint: disable=exec-used
return mod
return importlib.import_module('dbusmock.templates.' + name)
def _format_args(args):
'''Format a D-Bus argument tuple into an appropriate logging string'''
def format_arg(a):
if isinstance(a, dbus.Boolean):
return str(bool(a))
if isinstance(a, (dbus.Byte, int)):
return str(int(a))
if isinstance(a, str):
return '"' + str(a) + '"'
if isinstance(a, list):
return '[' + ', '.join([format_arg(x) for x in a]) + ']'
if isinstance(a, dict):
fmta = '{'
first = True
for k, v in a.items():
if first:
first = False
else:
fmta += ', '
fmta += format_arg(k) + ': ' + format_arg(v)
return fmta + '}'
# fallback
return repr(a)
s = ''
for a in args:
if s:
s += ' '
s += format_arg(a)
if s:
s = ' ' + s
return s
def _wrap_in_dbus_variant(value):
dbus_types = [
dbus.types.ByteArray,
dbus.types.Int16,
dbus.types.ObjectPath,
dbus.types.Struct,
dbus.types.UInt64,
dbus.types.Boolean,
dbus.types.Dictionary,
dbus.types.Int32,
dbus.types.Signature,
dbus.types.UInt16,
dbus.types.UnixFd,
dbus.types.Byte,
dbus.types.Double,
dbus.types.Int64,
dbus.types.String,
dbus.types.UInt32,
]
if isinstance(value, dbus.String):
return dbus.String(str(value), variant_level=1)
if isinstance(value, dbus.types.Array):
return value
if type(value) in dbus_types:
return type(value)(value.conjugate(), variant_level=1)
if isinstance(value, str):
return dbus.String(value, variant_level=1)
raise dbus.exceptions.DBusException(f'could not wrap type {type(value)}')
def _convert_args(signature: str, args: Tuple[Any, ...]) -> List[Any]:
"""
Convert types of arguments according to signature, using
MethodCallMessage.append(); this will also provide type/length
checks, except for the case of an empty signature
"""
try:
if signature == '' and len(args) > 0:
raise TypeError('Fewer items found in D-Bus signature than in Python arguments')
m = dbus.connection.MethodCallMessage('a.b', '/a', 'a.b', 'a')
m.append(signature=signature, *args)
return m.get_args_list()
except Exception as e:
raise dbus.exceptions.DBusException(f'Invalid arguments: {str(e)}',
name='org.freedesktop.DBus.Error.InvalidArgs')
def loggedmethod(self, func):
"""Decorator for a method to end in the call log"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
fname = func.__name__
self_arg, args = args[0], args[1:]
in_signature = getattr(func, '_dbus_in_signature', '')
args = _convert_args(in_signature, args)
self.log(fname + _format_args(args))
self.call_log.append((int(time.time()), fname, args))
self.MethodCalled(fname, args)
return func(*[self_arg, *args], **kwargs)
return wrapper
class DBusMockObject(dbus.service.Object): # pylint: disable=too-many-instance-attributes
'''Mock D-Bus object
This can be configured to have arbitrary methods (including code execution)
and properties via methods on the org.freedesktop.DBus.Mock interface, so
that you can control the mock from any programming language.
Beyond that "remote control" API, this is a standard dbus-python service object, see
.
'''
def __init__(self, bus_name: str, path: str, interface: str, props: PropsType,
logfile: Optional[str] = None, is_object_manager: bool = False) -> None:
'''Create a new DBusMockObject
bus_name: A dbus.service.BusName instance where the object will be put on
path: D-Bus object path
interface: Primary D-Bus interface name of this object (where
properties and methods will be put on)
props: A property_name (string) → property (Variant) map with initial
properties on "interface"
logfile: When given, method calls will be logged into that file name;
if None, logging will be written to stdout. Note that you can
also query the called methods over D-Bus with GetCalls() and
GetMethodCalls().
is_object_manager: If True, the GetManagedObjects method will
automatically be implemented on the object, returning
all objects which have this one’s path as a prefix of
theirs. Note that the InterfacesAdded and
InterfacesRemoved signals will not be automatically
emitted.
'''
dbus.service.Object.__init__(self, bus_name, path)
self.bus_name = bus_name
self.path = path
self.interface = interface
self.is_object_manager = is_object_manager
self.object_manager: Optional[DBusMockObject] = None
self._template: Optional[str] = None
self._template_parameters: Optional[PropsType] = None
# pylint: disable=consider-using-with
self.logfile = open(logfile, 'wb') if logfile else None
self.is_logfile_owner = True
self.call_log: List[CallLogType] = []
if props is None:
props = {}
self._reset(props)
def __del__(self) -> None:
try:
if self.logfile and self.is_logfile_owner:
self.logfile.close()
except AttributeError:
pass
def _set_up_object_manager(self) -> None:
'''Set up this mock object as a D-Bus ObjectManager.'''
if self.path == '/':
cond = 'k != \'/\''
else:
cond = f'k.startswith(\'{self.path}/\')'
self.AddMethod(OBJECT_MANAGER_IFACE,
'GetManagedObjects', '', 'a{oa{sa{sv}}}',
'ret = {dbus.ObjectPath(k): objects[k].props ' +
' for k in objects.keys() if ' + cond + '}')
self.object_manager = self
def _reset(self, props: PropsType) -> None:
# interface -> name -> value
self.props = {self.interface: props}
# interface -> name -> (in_signature, out_signature, code, dbus_wrapper_fn)
self.methods: Dict[str, Dict[str, MethodType]] = {self.interface: {}}
if self.is_object_manager:
self._set_up_object_manager()
@dbus.service.method(dbus.PROPERTIES_IFACE,
in_signature='ss', out_signature='v')
def Get(self, interface_name: str, property_name: str) -> Any:
'''Standard D-Bus API for getting a property value'''
self.log(f'Get {self.path} {interface_name}.{property_name}')
if not interface_name:
interface_name = self.interface
try:
return self.GetAll(interface_name)[property_name]
except KeyError as e:
raise dbus.exceptions.DBusException(
'no such property ' + property_name,
name=self.interface + '.UnknownProperty') from e
@dbus.service.method(dbus.PROPERTIES_IFACE,
in_signature='s', out_signature='a{sv}')
def GetAll(self, interface_name: str, *_, **__) -> PropsType:
'''Standard D-Bus API for getting all property values'''
self.log(f'GetAll {self.path} {interface_name}')
if not interface_name:
interface_name = self.interface
try:
return self.props[interface_name]
except KeyError as e:
raise dbus.exceptions.DBusException(
'no such interface ' + interface_name,
name=self.interface + '.UnknownInterface') from e
@dbus.service.method(dbus.PROPERTIES_IFACE,
in_signature='ssv', out_signature='')
def Set(self, interface_name: str, property_name: str, value: Any, *_, **__) -> None:
'''Standard D-Bus API for setting a property value'''
self.log(f'Set {self.path} {interface_name}.{property_name}{_format_args((value,))}')
try:
iface_props = self.props[interface_name]
except KeyError as e:
raise dbus.exceptions.DBusException(
'no such interface ' + interface_name,
name=self.interface + '.UnknownInterface') from e
if property_name not in iface_props:
raise dbus.exceptions.DBusException(
'no such property ' + property_name,
name=self.interface + '.UnknownProperty')
iface_props[property_name] = value
self.EmitSignal('org.freedesktop.DBus.Properties',
'PropertiesChanged',
'sa{sv}as',
[interface_name,
dbus.Dictionary({property_name: value}, signature='sv'),
dbus.Array([], signature='s')
])
@dbus.service.method(MOCK_IFACE,
in_signature='ssa{sv}a(ssss)',
out_signature='')
def AddObject(self, path: str, interface: str, properties: PropsType, methods: List[MethodType]) -> None:
'''Dynamically add a new D-Bus object to the mock
path: D-Bus object path
interface: Primary D-Bus interface name of this object (where
properties and methods will be put on)
properties: A property_name (string) → value map with initial
properties on "interface"
methods: An array of 4-tuples (name, in_sig, out_sig, code) describing
methods to add to "interface"; see AddMethod() for details of
the tuple values
If this is a D-Bus ObjectManager instance, the InterfacesAdded signal
will *not* be emitted for the object automatically; it must be emitted
manually if desired. This is because AddInterface may be called after
AddObject, but before the InterfacesAdded signal should be emitted.
Example:
dbus_proxy.AddObject('/com/example/Foo/Manager',
'com.example.Foo.Control',
{
'state': dbus.String('online', variant_level=1),
},
[
('Start', '', '', ''),
('EchoInt', 'i', 'i', 'ret = args[0]'),
('GetClients', '', 'ao', 'ret = ["/com/example/Foo/Client1"]'),
])
'''
if path in objects:
raise dbus.exceptions.DBusException(f'object {path} already exists', name='org.freedesktop.DBus.Mock.NameError')
obj = DBusMockObject(self.bus_name,
path,
interface,
properties)
# make sure created objects inherit the log file stream
obj.logfile = self.logfile
obj.object_manager = self.object_manager
obj.is_logfile_owner = False
obj.AddMethods(interface, methods)
objects[path] = obj
@dbus.service.method(MOCK_IFACE,
in_signature='s',
out_signature='')
def RemoveObject(self, path: str) -> None: # pylint: disable=no-self-use
'''Remove a D-Bus object from the mock
As with AddObject, this will *not* emit the InterfacesRemoved signal if
it’s an ObjectManager instance.
'''
try:
objects[path].remove_from_connection()
del objects[path]
except KeyError as e:
raise dbus.exceptions.DBusException(
f'object {path} does not exist',
name='org.freedesktop.DBus.Mock.NameError') from e
@dbus.service.method(MOCK_IFACE,
in_signature='', out_signature='')
def Reset(self) -> None:
'''Reset the mock object state.
Remove all mock objects from the bus and tidy up so the state is as if
python-dbusmock had just been restarted. If the mock object was
originally created with a template (from the command line, the Python
API or by calling AddTemplate over D-Bus), it will be
re-instantiated with that template.
'''
# Clear other existing objects.
for obj_name, obj in objects.items():
if obj_name != self.path:
obj.remove_from_connection()
objects.clear()
# Reinitialise our state. Carefully remove new methods from our dict;
# they don't not actually exist if they are a statically defined
# template function
for method_name in self.methods[self.interface]:
try:
delattr(self.__class__, method_name)
except AttributeError:
pass
self._reset({})
if self._template is not None:
self.AddTemplate(self._template, self._template_parameters)
objects[self.path] = self
@dbus.service.method(MOCK_IFACE,
in_signature='sssss',
out_signature='')
def AddMethod(self, interface, name: str, in_sig: str, out_sig: str, code: str) -> None:
'''Dynamically add a method to this object
interface: D-Bus interface to add this to. For convenience you can
specify '' here to add the method to the object's main
interface (as specified on construction).
name: Name of the method
in_sig: Signature of input arguments; for example "ias" for a method
that takes an int32 and a string array as arguments; see
http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures
out_sig: Signature of output arguments; for example "s" for a method
that returns a string; use '' for methods that do not return
anything.
code: Python 3 code to run in the method call; you have access to the
arguments through the "args" list, and can set the return value
by assigning a value to the "ret" variable. You can also read the
global "objects" variable, which is a dictionary mapping object
paths to DBusMockObject instances.
For keeping state across method calls, you are free to use normal
Python members of the "self" object, which will be persistent for
the whole mock's life time. E. g. you can have a method with
"self.my_state = True", and another method that returns it with
"ret = self.my_state".
Methods can raise exceptions in the usual way, in particular
dbus.exceptions.DBusException:
When specifying '', the method will not do anything (except
logging) and return None.
This is meant for adding a method to a mock at runtime, from any programming language.
You can also use it in templates in the load() function.
For implementing non-trivial and static methods in templates, it is recommended to
implement them in the normal dbus-python way with using the @dbus.service.method
decorator instead.
'''
# pylint: disable=protected-access
if not interface:
interface = self.interface
n_args = len(dbus.Signature(in_sig))
# we need to have separate methods for dbus-python, so clone
# mock_method(); using message_keyword with this dynamic approach fails
# because inspect cannot handle those, so pass on interface and method
# name as first positional arguments
method = lambda self, *args, **kwargs: DBusMockObject.mock_method(
self, interface, name, in_sig, *args, **kwargs)
# we cannot specify in_signature here, as that trips over a consistency
# check in dbus-python; we need to set it manually instead
dbus_method = dbus.service.method(interface,
out_signature=out_sig)(method)
dbus_method.__name__ = str(name)
dbus_method._dbus_in_signature = in_sig
dbus_method._dbus_args = [f'arg{i}' for i in range(1, n_args + 1)]
# for convenience, add mocked methods on the primary interface as
# callable methods
if interface == self.interface:
setattr(self.__class__, name, dbus_method)
self.methods.setdefault(interface, {})[str(name)] = (in_sig, out_sig, code, dbus_method)
@dbus.service.method(MOCK_IFACE,
in_signature='sa(ssss)',
out_signature='')
def AddMethods(self, interface: str, methods: List[MethodType]) -> None:
'''Add several methods to this object
interface: D-Bus interface to add this to. For convenience you can
specify '' here to add the method to the object's main
interface (as specified on construction).
methods: list of 4-tuples (name, in_sig, out_sig, code) describing one
method each. See AddMethod() for details of the tuple values.
'''
for method in methods:
self.AddMethod(interface, *method)
def _set_property(self, interface, name, value):
# copy.copy removes one level of variant-ness, which means that the
# types get exported in introspection data correctly, but we can't do
# this for container types.
if not isinstance(value, (dbus.Dictionary, dbus.Array)):
value = copy.copy(value)
self.props.setdefault(interface, {})[name] = value
@dbus.service.method(MOCK_IFACE,
in_signature='sa{sv}',
out_signature='')
def UpdateProperties(self, interface: str, properties: PropsType) -> None:
'''Update properties on this object and send a PropertiesChanged signal
interface: D-Bus interface to update this to. For convenience you can
specify '' here to add the property to the object's main
interface (as specified on construction).
properties: A property_name (string) → value map
'''
changed_props = {}
for name, value in properties.items():
if not interface:
interface = self.interface
if name not in self.props.get(interface, {}):
raise dbus.exceptions.DBusException(f'property {name} not found', name=interface + '.NoSuchProperty')
self._set_property(interface, name, value)
changed_props[name] = _wrap_in_dbus_variant(value)
self.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
interface, changed_props, []])
@dbus.service.method(MOCK_IFACE,
in_signature='ssv',
out_signature='')
def AddProperty(self, interface: str, name: str, value: Any) -> None:
'''Add property to this object
interface: D-Bus interface to add this to. For convenience you can
specify '' here to add the property to the object's main
interface (as specified on construction).
name: Property name.
value: Property value.
'''
if not interface:
interface = self.interface
if name in self.props.get(interface, {}):
raise dbus.exceptions.DBusException(f'property {name} already exists', name=self.interface + '.PropertyExists')
self._set_property(interface, name, value)
@dbus.service.method(MOCK_IFACE,
in_signature='sa{sv}',
out_signature='')
def AddProperties(self, interface: str, properties: PropsType) -> None:
'''Add several properties to this object
interface: D-Bus interface to add this to. For convenience you can
specify '' here to add the property to the object's main
interface (as specified on construction).
properties: A property_name (string) → value map
'''
for k, v in properties.items():
self.AddProperty(interface, k, v)
@dbus.service.method(MOCK_IFACE,
in_signature='sa{sv}',
out_signature='')
def AddTemplate(self, template: str, parameters: PropsType) -> None:
'''Load a template into the mock.
python-dbusmock ships a set of standard mocks for common system
services such as UPower and NetworkManager. With these the actual tests
become a lot simpler, as they only have to set up the particular
properties for the tests, and not the skeleton of common properties,
interfaces, and methods.
template: Name of the template to load or the full path to a *.py file
for custom templates. See "pydoc dbusmock.templates" for a
list of available templates from python-dbusmock package, and
"pydoc dbusmock.templates.NAME" for documentation about
template NAME.
parameters: A parameter (string) → value (variant) map, for
parameterizing templates. Each template can define their
own, see documentation of that particular template for
details.
'''
try:
module = load_module(template)
except ImportError as e:
raise dbus.exceptions.DBusException(f'Cannot add template {template}: {str(e)}',
name='org.freedesktop.DBus.Mock.TemplateError')
# If the template specifies this is an ObjectManager, set that up
if hasattr(module, 'IS_OBJECT_MANAGER') and module.IS_OBJECT_MANAGER:
self._set_up_object_manager()
# pick out all D-Bus service methods and add them to our interface
for symbol in dir(module):
# pylint: disable=protected-access
fn = getattr(module, symbol)
if ('_dbus_interface' in dir(fn) and ('_dbus_is_signal' not in dir(fn) or not fn._dbus_is_signal)):
fn = loggedmethod(self, fn)
# for dbus-python compatibility, add methods as callables
setattr(self.__class__, symbol, fn)
self.methods.setdefault(fn._dbus_interface, {})[str(symbol)] = (
fn._dbus_in_signature,
fn._dbus_out_signature, '', fn
)
if parameters is None:
parameters = {}
module.load(self, parameters)
# save the given template and parameters for re-instantiation on
# Reset()
self._template = template
self._template_parameters = parameters
@dbus.service.method(MOCK_IFACE,
in_signature='sssav',
out_signature='')
def EmitSignal(self, interface: str, name: str, signature: str, sigargs: Tuple[Any, ...]) -> None:
'''Emit a signal from the object.
interface: D-Bus interface to send the signal from. For convenience you
can specify '' here to add the method to the object's main
interface (as specified on construction).
name: Name of the signal
signature: Signature of input arguments; for example "ias" for a signal
that takes an int32 and a string array as arguments; see
http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures
args: variant array with signal arguments; must match order and type in
"signature"
'''
# pylint: disable=protected-access
if not interface:
interface = self.interface
args = _convert_args(signature, sigargs)
fn = lambda self, *args: self.log(f'emit {self.path} {interface}.{name}{_format_args(args)}')
fn.__name__ = str(name)
dbus_fn = dbus.service.signal(interface)(fn)
dbus_fn._dbus_signature = signature
dbus_fn._dbus_args = [f'arg{i}' for i in range(1, len(args) + 1)]
dbus_fn(self, *args)
@dbus.service.method(MOCK_IFACE,
in_signature='',
out_signature='a(tsav)')
def GetCalls(self) -> List[CallLogType]:
'''List all the logged calls since the last call to ClearCalls().
Return a list of (timestamp, method_name, args_list) tuples.
'''
return self.call_log
@dbus.service.method(MOCK_IFACE,
in_signature='s',
out_signature='a(tav)')
def GetMethodCalls(self, method: str) -> List[Tuple[int, Sequence[Any]]]:
'''List all the logged calls of a particular method.
Return a list of (timestamp, args_list) tuples.
'''
return [(row[0], row[2]) for row in self.call_log if row[1] == method]
@dbus.service.method(MOCK_IFACE,
in_signature='',
out_signature='')
def ClearCalls(self) -> None:
'''Empty the log of mock call signatures.'''
self.call_log = []
@dbus.service.signal(MOCK_IFACE, signature='sav')
def MethodCalled(self, name, args):
'''Signal emitted for every called mock method.
This is emitted for all mock method calls. This can be used to confirm
that a particular method was called with particular arguments, as an
alternative to reading the mock's log or GetCalls().
'''
def object_manager_emit_added(self, path: str) -> None:
'''Emit ObjectManager.InterfacesAdded signal'''
if self.object_manager is not None:
self.object_manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded',
'oa{sa{sv}}', [dbus.ObjectPath(path),
objects[path].props])
def object_manager_emit_removed(self, path: str) -> None:
'''Emit ObjectManager.InterfacesRemoved signal'''
if self.object_manager is not None:
self.object_manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [dbus.ObjectPath(path),
objects[path].props])
def mock_method(self, interface: str, dbus_method: str, in_signature: str, *m_args, **_) -> Any:
'''Master mock method.
This gets "instantiated" in AddMethod(). Execute the code snippet of
the method and return the "ret" variable if it was set.
'''
# print('mock_method', dbus_method, self, in_signature, args, _, file=sys.stderr)
try:
args = _convert_args(in_signature, m_args)
self.log(dbus_method + _format_args(args))
self.call_log.append((int(time.time()), str(dbus_method), args))
self.MethodCalled(dbus_method, args)
# The code may be a Python 3 string to interpret, or may be a function
# object (if AddMethod was called from within Python itself, rather than
# over D-Bus).
code = self.methods[interface][dbus_method][2]
if code and isinstance(code, types.FunctionType):
return code(self, *args)
if code:
loc = locals().copy()
exec(code, globals(), loc) # pylint: disable=exec-used
if 'ret' in loc:
return loc['ret']
except Exception as e:
self.log(dbus_method + ' raised: ' + str(e))
raise e
return None
def log(self, msg: str) -> None:
'''Log a message, prefixed with a timestamp.
If a log file was specified in the constructor, it is written there,
otherwise it goes to stdout.
'''
if self.logfile:
fd = self.logfile.fileno()
else:
fd = sys.stdout.fileno()
os.write(fd, f'{time.time():.3f} {msg}\n'.encode('UTF-8'))
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
in_signature='',
out_signature='s',
path_keyword='object_path',
connection_keyword='connection')
def Introspect(self, object_path: str, connection: dbus.connection.Connection) -> str:
'''Return XML description of this object's interfaces, methods and signals.
This wraps dbus-python's Introspect() method to include the dynamic
methods and properties.
'''
# _dbus_class_table is an indirect private member of dbus.service.Object that pylint fails to see
# pylint: disable=no-member
# temporarily add our dynamic methods
cls = self.__class__.__module__ + '.' + self.__class__.__name__
orig_interfaces = self._dbus_class_table[cls]
mock_interfaces = orig_interfaces.copy()
for iface, methods in self.methods.items():
for method, impl in methods.items():
mock_interfaces.setdefault(iface, {})[method] = impl[3]
self._dbus_class_table[cls] = mock_interfaces
xml = dbus.service.Object.Introspect(self, object_path, connection)
tree = ElementTree.fromstring(xml)
for name, name_props in self.props.items():
# We might have properties for new interfaces we don't know about
# yet. Try to find an existing node named after our
# interface to append to, and create one if we can't.
interface = tree.find(f".//interface[@name='{name}']")
if interface is None:
interface = ElementTree.Element("interface", {"name": name})
tree.append(interface)
for prop, val in name_props.items():
if val is None:
# can't guess type from None, skip
continue
elem = ElementTree.Element("property", {
"name": prop,
# We don't store the signature anywhere, so guess it.
"type": dbus.lowlevel.Message.guess_signature(val),
"access": "readwrite"})
interface.append(elem)
xml = ElementTree.tostring(tree, encoding='utf8', method='xml').decode('utf8')
# restore original class table
self._dbus_class_table[cls] = orig_interfaces
return xml
# Overwrite dbus-python's _method_lookup(), as that offers no way to have the
# same method name on different interfaces
orig_method_lookup = dbus.service._method_lookup # pylint: disable=protected-access
def _dbusmock_method_lookup(obj, method_name, dbus_interface):
try:
m = obj.methods[dbus_interface or obj.interface][method_name]
return (m[3], m[3])
except KeyError:
return orig_method_lookup(obj, method_name, dbus_interface)
dbus.service._method_lookup = _dbusmock_method_lookup # pylint: disable=protected-access
#
# Helper API for templates
#
def get_objects() -> KeysView[str]:
'''Return all existing object paths'''
return objects.keys()
def get_object(path) -> DBusMockObject:
'''Return object for a given object path'''
return objects[path]
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 011452 x ustar 00 0000000 0000000 28 mtime=1649137868.5371122
python-dbusmock-0.27.5/dbusmock/templates/ 0000755 0001751 0000171 00000000000 00000000000 021340 5 ustar 00runner docker 0000000 0000000 ././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/__init__.py 0000644 0001751 0000171 00000000576 00000000000 023461 0 ustar 00runner docker 0000000 0000000 '''Mock templates for common D-Bus services'''
# 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.
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/accounts_service.py 0000644 0001751 0000171 00000031045 00000000000 025254 0 ustar 00runner docker 0000000 0000000 '''Accounts Service D-Bus mock template'''
# 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__ = 'Marco Trevisan'
__email__ = 'marco.trevisan@canonical.com'
__copyright__ = '(c) 2021 Canonical Ltd.'
__license__ = 'LGPL 3+'
import sys
import time
import dbus
from dbusmock import MOCK_IFACE, mockobject
BUS_NAME = 'org.freedesktop.Accounts'
MAIN_OBJ = '/org/freedesktop/Accounts'
MAIN_IFACE = 'org.freedesktop.Accounts'
USER_IFACE = MAIN_IFACE + '.User'
SYSTEM_BUS = True
DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'
def get_user_path(uid):
return f'/org/freedesktop/Accounts/User{uid}'
def load(mock, parameters=None):
parameters = parameters if parameters else {}
mock.mock_users = {}
mock.cached_users = []
mock.automatic_login_users = set()
mock.users_auto_uids = 2000
mock.AddProperties(MAIN_IFACE, mock.GetAll(MAIN_IFACE))
for uid, name in parameters.get('users', {}).items():
mock.AddUser(uid, name)
def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None):
if properties is None:
properties = mock.GetAll(interface)
elif isinstance(properties, str):
properties = [properties]
if isinstance(properties, (list, set)):
properties = {p: mock.Get(interface, p) for p in properties}
elif not isinstance(properties, dict):
raise TypeError('Unsupported properties type')
mock.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', (
interface, properties, []))
@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}a{sv}',
out_signature='o')
def AddUser(self, uid, username, password, overrides, password_policy_overrides):
'''Add user via uid and username and optionally overriding properties
Returns the new object path.
'''
path = get_user_path(uid)
default_props = {
'Uid': dbus.UInt64(uid),
'UserName': username,
'RealName': username[0].upper() + username[1:] + ' Fake',
'AccountType': dbus.Int32(1),
'AutomaticLogin': False,
'BackgroundFile': '',
'Email': f'{username}@python-dbusmock.org',
'FormatsLocale': 'C',
'HomeDirectory': f'/nonexisting/mock-home/{username}',
'IconFile': '',
'InputSources': dbus.Array([], signature='a{ss}'),
'Language': 'C',
'LocalAccount': True,
'Location': '',
'Locked': False,
'LoginFrequency': dbus.UInt64(0),
'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
'LoginTime': dbus.Int64(0),
'PasswordHint': 'Remember it, come on!',
'PasswordMode': 0,
'Session': 'mock-session',
'SessionType': 'wayland',
'Shell': '/usr/bin/zsh',
'SystemAccount': False,
'XHasMessages': False,
'XKeyboardLayouts': dbus.Array([], signature='s'),
'XSession': 'mock-xsession',
}
default_props.update(overrides if overrides else {})
self.AddObject(path, USER_IFACE, default_props, [])
had_users = len(self.mock_users) != 0
had_multiple_users = len(self.mock_users) > 1
user = mockobject.objects[path]
user.password = password
user.properties = default_props
user.pwd_expiration_policy = {
'expiration_time': sys.maxsize,
'last_change_time': int(time.time()),
'min_days_between_changes': 0,
'max_days_between_changes': 0,
'days_to_warn': 0,
'days_after_expiration_until_lock': 0,
}
user.pwd_expiration_policy.update(
password_policy_overrides if password_policy_overrides else {})
self.mock_users[uid] = default_props
self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])
if not had_users:
emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
elif not had_multiple_users and len(self.mock_users) > 1:
emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
return path
@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
def ListMockUsers(self):
""" List the mock users that have been created """
return [get_user_path(uid) for uid in self.mock_users.keys()]
@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
def AddAutoLoginUser(self, username):
""" Enable autologin for an user """
path = self.FindUserByName(username)
self.automatic_login_users.add(path)
user = mockobject.objects[path]
set_user_property(user, 'AutomaticLogin', True)
emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
return path
@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
def RemoveAutoLoginUser(self, username):
""" Disables autologin for an user """
path = self.FindUserByName(username)
self.automatic_login_users.remove(path)
user = mockobject.objects[path]
set_user_property(user, 'AutomaticLogin', False)
emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
return path
@dbus.service.method(MAIN_IFACE, in_signature='ssi', out_signature='o')
def CreateUser(self, name, fullname, account_type):
""" Creates an user using the default API """
try:
self.FindUserByName(name)
found = True
except dbus.exceptions.DBusException:
found = False
if found:
raise dbus.exceptions.DBusException(f'User {name} already exists', name='org.freedesktop.Accounts.Error.Failed')
self.users_auto_uids += 1
return self.AddUser(self.users_auto_uids, name, DEFAULT_USER_PASSWORD, {
'RealName': fullname, 'AccountType': account_type}, {})
@dbus.service.method(MAIN_IFACE, in_signature='xb')
def DeleteUser(self, uid, _remove_files):
""" Removes a created user """
path = self.FindUserById(uid)
had_multiple_users = len(self.mock_users) > 1
self.RemoveObject(path)
self.mock_users.pop(uid)
self.automatic_login_users.discard(path)
self.EmitSignal(MAIN_IFACE, 'UserDeleted', 'o', [path])
if len(self.mock_users) == 0:
emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
elif had_multiple_users and len(self.mock_users) < 2:
emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
def CacheUser(self, username):
""" Cache an user """
path = self.FindUserByName(username)
self.cached_users.append(path)
return path
@dbus.service.method(MAIN_IFACE, in_signature='s')
def UncacheUser(self, username):
""" Removes an user from the cache """
path = self.FindUserByName(username)
self.cached_users.remove(path)
@dbus.service.method(MAIN_IFACE, in_signature='', out_signature='ao')
def ListCachedUsers(self):
""" Lists the cached users """
return self.cached_users
@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
def FindUserById(_self, uid):
""" Finds an user by its user id """
user = mockobject.objects.get(get_user_path(uid), None)
if not user:
raise dbus.exceptions.DBusException(
'No such user exists',
name='org.freedesktop.Accounts.Error.Failed')
return get_user_path(uid)
@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
def FindUserByName(self, username):
""" Finds an user form its name """
try:
[user_id] = [uid for uid, props in self.mock_users.items()
if props['UserName'] == username]
except ValueError as e:
raise dbus.exceptions.DBusException(f'No such user exists: {e}', name='org.freedesktop.Accounts.Error.Failed')
return get_user_path(user_id)
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
out_signature='a{sv}')
def GetAll(self, interface):
""" Implements the GetAll dbus properties interface method.
This allows to override the getters using dynamic values.
"""
if interface == MAIN_IFACE:
return {
'DaemonVersion': 'dbus-mock-0.1',
'HasNoUsers': len(self.mock_users) == 0,
'HasMultipleUsers': len(self.mock_users) > 1,
'AutomaticLoginUsers': dbus.Array(self.automatic_login_users,
signature='o'),
}
if interface == USER_IFACE:
return self.properties
return dbus.Dictionary({}, signature='sv')
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
out_signature='v')
def Get(self, interface, prop):
""" Implements the Get dbus properties interface method.
This allows to override the getters using dynamic values, via GetAll.
"""
return self.GetAll(interface)[prop]
def set_user_property(user, property_name, value):
""" Set an user property and emits the relative signals """
if user.properties[property_name] == value:
return
user.properties[property_name] = value
emit_properties_changed(user, USER_IFACE, property_name)
user.EmitSignal(USER_IFACE, 'Changed', '', [])
@dbus.service.method(USER_IFACE, in_signature='s')
def SetUserName(self, user_name):
set_user_property(self, 'UserName', user_name)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetRealName(self, real_name):
set_user_property(self, 'RealName', real_name)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetEmail(self, email):
set_user_property(self, 'Email', email)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetLanguage(self, language):
set_user_property(self, 'Language', language)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetXSession(self, x_session):
set_user_property(self, 'XSession', x_session)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetSession(self, session):
set_user_property(self, 'Session', session)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetSessionType(self, session_type):
set_user_property(self, 'SessionType', session_type)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetLocation(self, location):
set_user_property(self, 'Location', location)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetHomeDirectory(self, home_directory):
set_user_property(self, 'HomeDirectory', home_directory)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetShell(self, shell):
set_user_property(self, 'Shell', shell)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetIconFile(self, icon_file):
set_user_property(self, 'IconFile', icon_file)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetLocked(self, locked):
set_user_property(self, 'Locked', locked)
@dbus.service.method(USER_IFACE, in_signature='i')
def SetAccountType(self, account_type):
set_user_property(self, 'AccountType', account_type)
@dbus.service.method(USER_IFACE, in_signature='i')
def SetPasswordMode(self, password_mode):
set_user_property(self, 'PasswordMode', password_mode)
@dbus.service.method(USER_IFACE, in_signature='s')
def SetPasswordHint(self, hint):
set_user_property(self, 'PasswordHint', hint)
@dbus.service.method(USER_IFACE, in_signature='ss')
def SetPassword(self, password, hint):
self.password = password
self.SetPasswordHint(hint)
@dbus.service.method(USER_IFACE, in_signature='b')
def SetAutomaticLogin(self, automatic_login):
manager = mockobject.objects[MAIN_OBJ]
if automatic_login:
manager.AddAutoLoginUser(self.properties['UserName'])
else:
manager.RemoveAutoLoginUser(self.properties['UserName'])
@dbus.service.method(MOCK_IFACE, in_signature='xxxxxxx')
def SetUserPasswordExpirationPolicy(self, uid, expiration_time,
last_change_time, min_days_between_changes,
max_days_between_changes, days_to_warn,
days_after_expiration_until_lock):
user = mockobject.objects[self.FindUserById(uid)]
user.pwd_expiration_policy = {
'expiration_time': expiration_time,
'last_change_time': last_change_time,
'min_days_between_changes': min_days_between_changes,
'max_days_between_changes': max_days_between_changes,
'days_to_warn': days_to_warn,
'days_after_expiration_until_lock': days_after_expiration_until_lock,
}
user.EmitSignal(USER_IFACE, 'Changed', '', [])
@dbus.service.method(USER_IFACE, in_signature='', out_signature='xxxxxx')
def GetPasswordExpirationPolicy(self):
return tuple(self.pwd_expiration_policy.values())
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/bluez5-obex.py 0000644 0001751 0000171 00000024715 00000000000 024064 0 ustar 00runner docker 0000000 0000000 # -*- coding: utf-8 -*-
'''obexd mock template
This creates the expected methods and properties of the object manager
org.bluez.obex object (/), the manager object (/org/bluez/obex), but no agents
or clients.
This supports BlueZ 5 only.
'''
# 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__ = 'Philip Withnall'
__copyright__ = '(c) 2013 Collabora Ltd.'
import tempfile
import os
import dbus
from dbusmock import OBJECT_MANAGER_IFACE, mockobject
BUS_NAME = 'org.bluez.obex'
MAIN_OBJ = '/'
SYSTEM_BUS = False
IS_OBJECT_MANAGER = True
OBEX_MOCK_IFACE = 'org.bluez.obex.Mock'
AGENT_MANAGER_IFACE = 'org.bluez.AgentManager1'
CLIENT_IFACE = 'org.bluez.obex.Client1'
SESSION_IFACE = 'org.bluez.obex.Session1'
PHONEBOOK_ACCESS_IFACE = 'org.bluez.obex.PhonebookAccess1'
TRANSFER_IFACE = 'org.bluez.obex.Transfer1'
TRANSFER_MOCK_IFACE = 'org.bluez.obex.transfer1.Mock'
def load(mock, _parameters):
mock.AddObject('/org/bluez/obex', AGENT_MANAGER_IFACE, {}, [
('RegisterAgent', 'os', '', ''),
('UnregisterAgent', 'o', '', ''),
])
obex = mockobject.objects['/org/bluez/obex']
obex.AddMethods(CLIENT_IFACE, [
('CreateSession', 'sa{sv}', 'o', CreateSession),
('RemoveSession', 'o', '', RemoveSession),
])
@dbus.service.method(CLIENT_IFACE,
in_signature='sa{sv}', out_signature='o')
def CreateSession(self, destination, args):
'''OBEX method to create a new transfer session.
The destination must be the address of the destination Bluetooth device.
The given arguments must be a map from well-known keys to values,
containing at least the ‘Target’ key, whose value must be ‘PBAP’ (other
keys and values are accepted by the real daemon, but not by this mock
daemon at the moment). If the target is missing or incorrect, an
Unsupported error is returned on the bus.
Returns the path of a new Session object.
'''
if 'Target' not in args or args['Target'].upper() != 'PBAP':
raise dbus.exceptions.DBusException(
'Non-PBAP targets are not currently supported by this python-dbusmock template.',
name=OBEX_MOCK_IFACE + '.Unsupported')
# Find the first unused session ID.
client_path = '/org/bluez/obex/client'
session_id = 0
while client_path + '/session' + str(session_id) in mockobject.objects:
session_id += 1
path = client_path + '/session' + str(session_id)
properties = {
'Source': dbus.String('FIXME', variant_level=1),
'Destination': dbus.String(destination, variant_level=1),
'Channel': dbus.Byte(0, variant_level=1),
'Target': dbus.String('FIXME', variant_level=1),
'Root': dbus.String('FIXME', variant_level=1),
}
self.AddObject(path,
SESSION_IFACE,
# Properties
properties,
# Methods
[
('GetCapabilities', '', 's', ''), # Currently a no-op
])
session = mockobject.objects[path]
session.AddMethods(PHONEBOOK_ACCESS_IFACE, [
('Select', 'ss', '', ''), # Currently a no-op
# Currently a no-op
('List', 'a{sv}', 'a(ss)', 'ret = dbus.Array(signature="(ss)")'),
# Currently a no-op
('ListFilterFields', '', 'as', 'ret = dbus.Array(signature="(s)")'),
('PullAll', 'sa{sv}', 'sa{sv}', PullAll),
('GetSize', '', 'q', 'ret = 0'),
])
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded',
'oa{sa{sv}}', [
dbus.ObjectPath(path),
{SESSION_IFACE: properties},
])
return path
@dbus.service.method(CLIENT_IFACE,
in_signature='o', out_signature='')
def RemoveSession(self, session_path):
'''OBEX method to remove an existing transfer session.
This takes the path of the transfer Session object and removes it.
'''
manager = mockobject.objects['/']
# Remove all the session's transfers.
transfer_id = 0
while session_path + '/transfer' + str(transfer_id) in mockobject.objects:
transfer_path = session_path + '/transfer' + str(transfer_id)
transfer_id += 1
self.RemoveObject(transfer_path)
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(transfer_path),
[TRANSFER_IFACE],
])
# Remove the session itself.
self.RemoveObject(session_path)
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(session_path),
[SESSION_IFACE, PHONEBOOK_ACCESS_IFACE],
])
@dbus.service.method(PHONEBOOK_ACCESS_IFACE,
in_signature='sa{sv}', out_signature='sa{sv}')
def PullAll(self, target_file, filters):
'''OBEX method to start a pull transfer of a phone book.
This doesn't complete the transfer; code to mock up activating and
completing the transfer must be provided by the test driver, as it’s
too complex and test-specific to put here.
The target_file is the absolute path for a file which will have zero or
more vCards, separated by new-line characters, written to it if the method
is successful (and the transfer is completed). This target_file is actually
emitted in a TransferCreated signal, which is a special part of the mock
interface designed to be handled by the test driver, which should then
populate that file and call UpdateStatus on the Transfer object. The test
driver is responsible for deleting the file once the test is complete.
The filters parameter is a map of filters to be applied to the results
device-side before transmitting them back to the adapter.
Returns a tuple containing the path for a new Transfer D-Bus object
representing the transfer, and a map of the initial properties of that
Transfer object.
'''
# Find the first unused session ID.
session_path = self.path
transfer_id = 0
while session_path + '/transfer' + str(transfer_id) in mockobject.objects:
transfer_id += 1
transfer_path = session_path + '/transfer' + str(transfer_id)
# Create a new temporary file to transfer to.
with tempfile.NamedTemporaryFile(suffix='.vcf',
prefix='tmp-bluez5-obex-PullAll_',
delete=False) as temp_file:
filename = os.path.abspath(temp_file.name)
props = {
'Status': dbus.String('queued', variant_level=1),
'Session': dbus.ObjectPath(session_path,
variant_level=1),
'Name': dbus.String(target_file, variant_level=1),
'Filename': dbus.String(filename, variant_level=1),
'Transferred': dbus.UInt64(0, variant_level=1),
}
self.AddObject(transfer_path,
TRANSFER_IFACE,
# Properties
props,
# Methods
[
('Cancel', '', '', ''), # Currently a no-op
])
transfer = mockobject.objects[transfer_path]
transfer.AddMethods(TRANSFER_MOCK_IFACE, [
('UpdateStatus', 'b', '', UpdateStatus),
])
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded',
'oa{sa{sv}}', [
dbus.ObjectPath(transfer_path),
{TRANSFER_IFACE: props},
])
# Emit a behind-the-scenes signal that a new transfer has been created.
manager.EmitSignal(OBEX_MOCK_IFACE, 'TransferCreated', 'sa{sv}s',
[transfer_path, filters, filename])
return (transfer_path, props)
@dbus.service.signal(OBEX_MOCK_IFACE, signature='sa{sv}s')
def TransferCreated(_self, _path, _filters, _transfer_filename):
'''Mock signal emitted when a new Transfer object is created.
This is not part of the BlueZ OBEX interface; it is purely for use by test
driver code. It is emitted by the PullAll method, and is intended to be
used as a signal to call UpdateStatus on the newly created Transfer
(potentially after a timeout).
The path is of the new Transfer object, and the filters are as provided to
PullAll. The transfer filename is the full path and filename of a newly
created empty temporary file which the test driver should write to.
The test driver should then call UpdateStatus on the Transfer object each
time a write is made to the transfer file. The final call to UpdateStatus
should mark the transfer as complete.
The test driver is responsible for deleting the transfer file once the test
is complete.
FIXME: Ideally the UpdateStatus method would only be used for completion,
and all intermediate updates would be found by watching the size of the
transfer file. However, that means adding a dependency on an inotify
package, which seems a little much.
'''
@dbus.service.method(TRANSFER_MOCK_IFACE,
in_signature='b', out_signature='')
def UpdateStatus(self, is_complete):
'''Mock method to update the transfer status.
If is_complete is False, this marks the transfer is active; otherwise it
marks the transfer as complete. It is an error to call this method after
calling it with is_complete as True.
In both cases, it updates the number of bytes transferred to be the current
size of the transfer file (whose filename was emitted in the
TransferCreated signal).
'''
status = 'complete' if is_complete else 'active'
transferred = os.path.getsize(self.props[TRANSFER_IFACE]['Filename'])
self.props[TRANSFER_IFACE]['Status'] = status
self.props[TRANSFER_IFACE]['Transferred'] = dbus.UInt64(transferred, variant_level=1)
self.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
TRANSFER_IFACE,
{
'Status': dbus.String(status, variant_level=1),
'Transferred': dbus.UInt64(transferred, variant_level=1),
},
[],
])
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/bluez5.py 0000644 0001751 0000171 00000056537 00000000000 023140 0 ustar 00runner docker 0000000 0000000 # -*- coding: utf-8 -*-
'''bluetoothd mock template
This creates the expected methods and properties of the object manager
org.bluez object (/), the manager object (/org/bluez), but no adapters or
devices.
This supports BlueZ 5 only.
'''
# 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__ = 'Philip Withnall'
__copyright__ = '(c) 2013 Collabora Ltd.'
import os
import dbus
from dbusmock import OBJECT_MANAGER_IFACE, mockobject
BUS_NAME = 'org.bluez'
MAIN_OBJ = '/'
SYSTEM_BUS = True
IS_OBJECT_MANAGER = True
BLUEZ_MOCK_IFACE = 'org.bluez.Mock'
AGENT_MANAGER_IFACE = 'org.bluez.AgentManager1'
PROFILE_MANAGER_IFACE = 'org.bluez.ProfileManager1'
ADAPTER_IFACE = 'org.bluez.Adapter1'
MEDIA_IFACE = 'org.bluez.Media1'
NETWORK_SERVER_IFACE = 'org.bluez.Network1'
DEVICE_IFACE = 'org.bluez.Device1'
# The device class of some arbitrary Android phone.
MOCK_PHONE_CLASS = 5898764
@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[str(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', '', RegisterAgent),
('RequestDefaultAgent', 'o', '', RequestDefaultAgent),
('UnregisterAgent', 'o', '', UnregisterAgent),
])
bluez = mockobject.objects['/org/bluez']
bluez.AddMethods(PROFILE_MANAGER_IFACE, [
('RegisterProfile', 'osa{sv}', '', ''),
('UnregisterProfile', 'o', '', ''),
])
bluez.agent_paths = []
bluez.capabilities = {}
bluez.default_agent = None
@dbus.service.method(ADAPTER_IFACE,
in_signature='o', out_signature='')
def RemoveDevice(adapter, path):
adapter.RemoveObject(path)
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(path),
[DEVICE_IFACE],
])
@dbus.service.method(ADAPTER_IFACE,
in_signature='', out_signature='')
def StartDiscovery(adapter):
adapter.props[ADAPTER_IFACE]['Discovering'] = True
# NOTE: discovery filter support is minimal to mock
# the Discoverable discovery filter
if adapter.props[ADAPTER_IFACE]['DiscoveryFilter'] is not None:
adapter.props[ADAPTER_IFACE]['Discoverable'] = True
adapter.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
ADAPTER_IFACE,
{
'Discoverable': dbus.Boolean(adapter.props[ADAPTER_IFACE]['Discoverable'], variant_level=1),
'Discovering': dbus.Boolean(adapter.props[ADAPTER_IFACE]['Discovering'], variant_level=1),
},
[],
])
@dbus.service.method(ADAPTER_IFACE,
in_signature='', out_signature='')
def StopDiscovery(adapter):
adapter.props[ADAPTER_IFACE]['Discovering'] = False
# NOTE: discovery filter support is minimal to mock
# the Discoverable discovery filter
if adapter.props[ADAPTER_IFACE]['DiscoveryFilter'] is not None:
adapter.props[ADAPTER_IFACE]['Discoverable'] = False
adapter.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
ADAPTER_IFACE,
{
'Discoverable': dbus.Boolean(adapter.props[ADAPTER_IFACE]['Discoverable'], variant_level=1),
'Discovering': dbus.Boolean(adapter.props[ADAPTER_IFACE]['Discovering'], variant_level=1),
},
[],
])
@dbus.service.method(ADAPTER_IFACE,
in_signature='a{sv}', out_signature='')
def SetDiscoveryFilter(adapter, discovery_filter):
adapter.props[ADAPTER_IFACE]['DiscoveryFilter'] = discovery_filter
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='ss', out_signature='s')
def AddAdapter(self, device_name, system_name):
'''Convenience method to add a Bluetooth adapter
You have to specify a device name which must be a valid part of an object
path, e. g. "hci0", and an arbitrary system name (pretty hostname).
Returns the new object path.
'''
path = '/org/bluez/' + device_name
address_start = int(device_name[-1])
address = f"{address_start:02d}:{address_start+1:02d}:{address_start+2:02d}:" + \
f"{address_start+3:02d}:{address_start+4:02d}:{address_start+5:02d}"
adapter_properties = {
'UUIDs': dbus.Array([
# Reference:
# http://git.kernel.org/cgit/bluetooth/bluez.git/tree/lib/uuid.h
# PNP
'00001200-0000-1000-8000-00805f9b34fb',
# Generic Access Profile
'00001800-0000-1000-8000-00805f9b34fb',
# Generic Attribute Profile
'00001801-0000-1000-8000-00805f9b34fb',
# Audio/Video Remote Control Profile (remote)
'0000110e-0000-1000-8000-00805f9b34fb',
# Audio/Video Remote Control Profile (target)
'0000110c-0000-1000-8000-00805f9b34fb',
], variant_level=1),
'Discoverable': dbus.Boolean(False, variant_level=1),
'Discovering': dbus.Boolean(False, variant_level=1),
'Pairable': dbus.Boolean(True, variant_level=1),
'Powered': dbus.Boolean(True, variant_level=1),
'Address': dbus.String(address, variant_level=1),
'AddressType': dbus.String('public', variant_level=1),
'Alias': dbus.String(system_name, variant_level=1),
'Modalias': dbus.String('usb:v1D6Bp0245d050A', variant_level=1),
'Name': dbus.String(system_name, variant_level=1),
# Reference:
# http://bluetooth-pentest.narod.ru/software/
# bluetooth_class_of_device-service_generator.html
'Class': dbus.UInt32(268, variant_level=1), # Computer, Laptop
'DiscoverableTimeout': dbus.UInt32(180, variant_level=1),
'PairableTimeout': dbus.UInt32(0, variant_level=1),
}
self.AddObject(path,
ADAPTER_IFACE,
# Properties
adapter_properties,
# Methods
[
('RemoveDevice', 'o', '', RemoveDevice),
('StartDiscovery', '', '', StartDiscovery),
('StopDiscovery', '', '', StopDiscovery),
('SetDiscoveryFilter', 'a{sv}', '', SetDiscoveryFilter),
])
adapter = mockobject.objects[path]
adapter.AddMethods(MEDIA_IFACE, [
('RegisterEndpoint', 'oa{sv}', '', ''),
('UnregisterEndpoint', 'o', '', ''),
])
adapter.AddMethods(NETWORK_SERVER_IFACE, [
('Register', 'ss', '', ''),
('Unregister', 's', '', ''),
])
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded',
'oa{sa{sv}}', [
dbus.ObjectPath(path),
{ADAPTER_IFACE: adapter_properties},
])
return path
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='s')
def RemoveAdapter(self, device_name):
'''Convenience method to remove a Bluetooth adapter
'''
path = '/org/bluez/' + device_name
# We could remove the devices related to the adapters here, but
# when bluez crashes, the InterfacesRemoved aren't necessarily sent
# devices first, so in effect, our laziness is testing an edge case
# in the clients
self.RemoveObject(path)
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(path),
[ADAPTER_IFACE],
])
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='s')
def RemoveAdapterWithDevices(self, device_name):
'''Convenience method to remove a Bluetooth adapter and all
the devices associated to it
'''
adapter_path = '/org/bluez/' + device_name
adapter = mockobject.objects[adapter_path]
manager = mockobject.objects['/']
to_remove = []
for path in mockobject.objects:
if path.startswith(adapter_path + '/'):
to_remove.append(path)
for path in to_remove:
adapter.RemoveObject(path)
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(path),
[DEVICE_IFACE],
])
self.RemoveObject(adapter_path)
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesRemoved',
'oas', [
dbus.ObjectPath(adapter_path),
[ADAPTER_IFACE],
])
@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, MOCK_PHONE_CLASS)
@dbus.service.method(DEVICE_IFACE,
in_signature='', out_signature='')
def Connect(device):
if device.connected:
raise dbus.exceptions.DBusException(
'Already Connected',
name='org.bluez.Error.AlreadyConnected')
device.connected = True
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'Connected': dbus.Boolean(device.connected, variant_level=1),
},
[],
])
@dbus.service.method(DEVICE_IFACE,
in_signature='', out_signature='')
def Disconnect(device):
if not device.connected:
raise dbus.exceptions.DBusException(
'Not Connected',
name='org.bluez.Error.NotConnected')
device.connected = False
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'Connected': dbus.Boolean(device.connected, variant_level=1),
},
[],
])
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='sss', out_signature='s')
def AddDevice(self, adapter_device_name, device_address, alias):
'''Convenience method to add a Bluetooth device
You have to specify a device address which must be a valid Bluetooth
address (e.g. 'AA:BB:CC:DD:EE:FF'). The alias is the human-readable name
for the device (e.g. as set on the device itself), and the adapter device
name is the device_name passed to AddAdapter.
This will create a new, unpaired and unconnected device.
Returns the new object path.
'''
device_name = 'dev_' + device_address.replace(':', '_').upper()
adapter_path = '/org/bluez/' + adapter_device_name
path = adapter_path + '/' + device_name
if adapter_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Adapter {adapter_device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchAdapter')
properties = {
'Address': dbus.String(device_address, variant_level=1),
'AddressType': dbus.String('public', variant_level=1),
'Name': dbus.String(alias, variant_level=1),
'Icon': dbus.String('', variant_level=1),
'Class': dbus.UInt32(0, variant_level=1),
'Appearance': dbus.UInt16(0, variant_level=1),
'UUIDs': dbus.Array([], signature='s', variant_level=1),
'Paired': dbus.Boolean(False, variant_level=1),
'Connected': dbus.Boolean(False, variant_level=1),
'Trusted': dbus.Boolean(False, variant_level=1),
'Blocked': dbus.Boolean(False, variant_level=1),
'WakeAllowed': dbus.Boolean(False, variant_level=1),
'Alias': dbus.String(alias, variant_level=1),
'Adapter': dbus.ObjectPath(adapter_path, variant_level=1),
'LegacyPairing': dbus.Boolean(False, variant_level=1),
'Modalias': dbus.String('', variant_level=1),
'RSSI': dbus.Int16(-79, variant_level=1), # arbitrary
'TxPower': dbus.Int16(0, variant_level=1),
'ManufacturerData': dbus.Array([], signature='a{qv}', variant_level=1),
'ServiceData': dbus.Array([], signature='a{sv}', variant_level=1),
'ServicesResolved': dbus.Boolean(False, variant_level=1),
'AdvertisingFlags': dbus.Array([], signature='ay', variant_level=1),
'AdvertisingData': dbus.Array([], signature='a{yv}', variant_level=1),
}
self.AddObject(path,
DEVICE_IFACE,
# Properties
properties,
# Methods
[
('CancelPairing', '', '', ''),
('Connect', '', '', Connect),
('ConnectProfile', 's', '', ''),
('Disconnect', '', '', Disconnect),
('DisconnectProfile', 's', '', ''),
('Pair', '', '', Pair),
])
device = mockobject.objects[path]
device.paired = False
device.connected = False
manager = mockobject.objects['/']
manager.EmitSignal(OBJECT_MANAGER_IFACE, 'InterfacesAdded',
'oa{sa{sv}}', [
dbus.ObjectPath(path),
{DEVICE_IFACE: properties},
])
return path
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='ssi', out_signature='')
def PairDevice(_self, adapter_device_name, device_address, class_):
'''Convenience method to mark an existing device as paired.
You have to specify a device address which must be a valid Bluetooth
address (e.g. 'AA:BB:CC:DD:EE:FF'). The adapter device name is the
device_name passed to AddAdapter.
This unblocks the device if it was blocked.
If the specified adapter or device don’t exist, a NoSuchAdapter or
NoSuchDevice error will be returned on the bus.
Returns nothing.
'''
device_name = 'dev_' + device_address.replace(':', '_').upper()
adapter_path = '/org/bluez/' + adapter_device_name
device_path = adapter_path + '/' + device_name
if adapter_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Adapter {adapter_device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchAdapter')
if device_path not in mockobject.objects:
raise dbus.exceptions.DBusException(f'Device {device_name} does not exist.', name=BLUEZ_MOCK_IFACE + '.NoSuchDevice')
device = mockobject.objects[device_path]
device.paired = True
# Based off pairing with an Android phone.
uuids = [
'00001105-0000-1000-8000-00805f9b34fb',
'0000110a-0000-1000-8000-00805f9b34fb',
'0000110c-0000-1000-8000-00805f9b34fb',
'00001112-0000-1000-8000-00805f9b34fb',
'00001115-0000-1000-8000-00805f9b34fb',
'00001116-0000-1000-8000-00805f9b34fb',
'0000111f-0000-1000-8000-00805f9b34fb',
'0000112f-0000-1000-8000-00805f9b34fb',
'00001200-0000-1000-8000-00805f9b34fb',
]
device.props[DEVICE_IFACE]['UUIDs'] = dbus.Array(uuids, variant_level=1)
device.props[DEVICE_IFACE]['Paired'] = dbus.Boolean(True, variant_level=1)
device.props[DEVICE_IFACE]['LegacyPairing'] = dbus.Boolean(True,
variant_level=1)
device.props[DEVICE_IFACE]['Blocked'] = dbus.Boolean(False,
variant_level=1)
try:
device.props[DEVICE_IFACE]['Modalias']
except KeyError:
device.AddProperties(DEVICE_IFACE, {
'Modalias': dbus.String('bluetooth:v000Fp1200d1436',
variant_level=1),
'Class': dbus.UInt32(class_, variant_level=1),
'Icon': dbus.String('phone', variant_level=1),
})
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'UUIDs': dbus.Array(uuids, variant_level=1),
'Paired': dbus.Boolean(True, variant_level=1),
'LegacyPairing': dbus.Boolean(True, variant_level=1),
'Blocked': dbus.Boolean(False, variant_level=1),
'Modalias': dbus.String('bluetooth:v000Fp1200d1436',
variant_level=1),
'Class': dbus.UInt32(class_, variant_level=1),
'Icon': dbus.String('phone', variant_level=1),
},
[],
])
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='ss', out_signature='')
def BlockDevice(_self, adapter_device_name, device_address):
'''Convenience method to mark an existing device as blocked.
You have to specify a device address which must be a valid Bluetooth
address (e.g. 'AA:BB:CC:DD:EE:FF'). The adapter device name is the
device_name passed to AddAdapter.
This disconnects the device if it was connected.
If the specified adapter or device don’t exist, a NoSuchAdapter or
NoSuchDevice error will be returned on the bus.
Returns nothing.
'''
device_name = 'dev_' + device_address.replace(':', '_').upper()
adapter_path = '/org/bluez/' + adapter_device_name
device_path = adapter_path + '/' + device_name
if adapter_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Adapter {adapter_device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchAdapter')
if device_path not in mockobject.objects:
raise dbus.exceptions.DBusException(f'Device {device_name} does not exist.', name=BLUEZ_MOCK_IFACE + '.NoSuchDevice')
device = mockobject.objects[device_path]
device.props[DEVICE_IFACE]['Blocked'] = dbus.Boolean(True, variant_level=1)
device.props[DEVICE_IFACE]['Connected'] = dbus.Boolean(False,
variant_level=1)
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'Blocked': dbus.Boolean(True, variant_level=1),
'Connected': dbus.Boolean(False, variant_level=1),
},
[],
])
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='ss', out_signature='')
def ConnectDevice(_self, adapter_device_name, device_address):
'''Convenience method to mark an existing device as connected.
You have to specify a device address which must be a valid Bluetooth
address (e.g. 'AA:BB:CC:DD:EE:FF'). The adapter device name is the
device_name passed to AddAdapter.
This unblocks the device if it was blocked.
If the specified adapter or device don’t exist, a NoSuchAdapter or
NoSuchDevice error will be returned on the bus.
Returns nothing.
'''
device_name = 'dev_' + device_address.replace(':', '_').upper()
adapter_path = '/org/bluez/' + adapter_device_name
device_path = adapter_path + '/' + device_name
if adapter_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Adapter {adapter_device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchAdapter')
if device_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Device {device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchDevice')
device = mockobject.objects[device_path]
device.props[DEVICE_IFACE]['Blocked'] = dbus.Boolean(False,
variant_level=1)
device.props[DEVICE_IFACE]['Connected'] = dbus.Boolean(True,
variant_level=1)
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'Blocked': dbus.Boolean(False, variant_level=1),
'Connected': dbus.Boolean(True, variant_level=1),
},
[],
])
@dbus.service.method(BLUEZ_MOCK_IFACE,
in_signature='ss', out_signature='')
def DisconnectDevice(_self, adapter_device_name, device_address):
'''Convenience method to mark an existing device as disconnected.
You have to specify a device address which must be a valid Bluetooth
address (e.g. 'AA:BB:CC:DD:EE:FF'). The adapter device name is the
device_name passed to AddAdapter.
This does not change the device’s blocked status.
If the specified adapter or device don’t exist, a NoSuchAdapter or
NoSuchDevice error will be returned on the bus.
Returns nothing.
'''
device_name = 'dev_' + device_address.replace(':', '_').upper()
adapter_path = '/org/bluez/' + adapter_device_name
device_path = adapter_path + '/' + device_name
if adapter_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Adapter {adapter_device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchAdapter')
if device_path not in mockobject.objects:
raise dbus.exceptions.DBusException(
f'Device {device_name} does not exist.',
name=BLUEZ_MOCK_IFACE + '.NoSuchDevice')
device = mockobject.objects[device_path]
device.props[DEVICE_IFACE]['Connected'] = dbus.Boolean(False,
variant_level=1)
device.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', [
DEVICE_IFACE,
{
'Connected': dbus.Boolean(False, variant_level=1),
},
[],
])
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/gnome_screensaver.py 0000644 0001751 0000171 00000002253 00000000000 025421 0 ustar 00runner docker 0000000 0000000 '''gnome-shell screensaver mock template
This creates the expected methods and properties of the
org.gnome.ScreenSaver object.
'''
# 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__ = 'Bastien Nocera'
__copyright__ = '(c) 2013 Red Hat Inc.'
BUS_NAME = 'org.gnome.ScreenSaver'
MAIN_OBJ = '/org/gnome/ScreenSaver'
MAIN_IFACE = 'org.gnome.ScreenSaver'
SYSTEM_BUS = False
def load(mock, _parameters):
mock.AddMethods(MAIN_IFACE, [
('GetActive', '', 'b', 'ret = self.is_active'),
('GetActiveTime', '', 'u', 'ret = 1'),
('SetActive', 'b', '', 'self.is_active = args[0]; self.EmitSignal('
'"", "ActiveChanged", "b", [self.is_active])'),
('Lock', '', '', 'time.sleep(1); self.SetActive(True)'),
('ShowMessage', 'sss', '', ''),
('SimulateUserActivity', '', '', ''),
])
# default state
mock.is_active = False
././@PaxHeader 0000000 0000000 0000000 00000000026 00000000000 011453 x ustar 00 0000000 0000000 22 mtime=1649137859.0
python-dbusmock-0.27.5/dbusmock/templates/iio-sensors-proxy.py 0000644 0001751 0000171 00000015176 00000000000 025355 0 ustar 00runner docker 0000000 0000000 '''sensors proxy mock template
'''
# 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__ = 'Marco Trevisan'
__copyright__ = '(c) 2021 Canonical Ltd.'
import re
import dbus
from dbusmock import MOCK_IFACE
BUS_NAME = 'net.hadess.SensorProxy'
MAIN_OBJ = '/net/hadess/SensorProxy'
MAIN_IFACE = 'net.hadess.SensorProxy'
COMPASS_IFACE = 'net.hadess.SensorProxy.Compass'
SYSTEM_BUS = True
CAMEL_TO_SNAKE_CASE_RE = re.compile(r'(?