1Metadata-Version: 1.1 2Name: python-dbusmock 3Version: 0.25.0 4Summary: Mock D-Bus objects 5Home-page: https://github.com/martinpitt/python-dbusmock 6Author: Martin Pitt 7Author-email: martin.pitt@ubuntu.com 8License: LGPL 3+ 9Download-URL: https://pypi.python.org/pypi/python-dbusmock/ 10Description: python-dbusmock 11 =============== 12 13 Purpose 14 ------- 15 With this program/Python library you can easily create mock objects on D-Bus. 16 This is useful for writing tests for software which talks to D-Bus services 17 such as upower, systemd, logind, gnome-session or others, and it is hard 18 (or impossible without root privileges) to set the state of the real services 19 to what you expect in your tests. 20 21 Suppose you want to write tests for gnome-settings-daemon's power plugin, or 22 another program that talks to upower. You want to verify that after the 23 configured idle time the program suspends the machine. So your program calls 24 ``org.freedesktop.UPower.Suspend()`` on the system D-Bus. 25 26 Now, your test suite should not really talk to the actual system D-Bus and the 27 real upower; a ``make check`` that suspends your machine will not be considered 28 very friendly by most people, and if you want to run this in continuous 29 integration test servers or package build environments, chances are that your 30 process does not have the privilege to suspend, or there is no system bus or 31 upower to begin with. Likewise, there is no way for an user process to 32 forcefully set the system/seat idle flag in logind, so your 33 tests cannot set up the expected test environment on the real daemon. 34 35 That's where mock objects come into play: They look like the real API (or at 36 least the parts that you actually need), but they do not actually do anything 37 (or only some action that you specify yourself). You can configure their 38 state, behaviour and responses as you like in your test, without making any 39 assumptions about the real system status. 40 41 When using a local system/session bus, you can do unit or integration testing 42 without needing root privileges or disturbing a running system. The Python API 43 offers some convenience functions like ``start_session_bus()`` and 44 ``start_system_bus()`` for this, in a ``DBusTestCase`` class (subclass of the 45 standard ``unittest.TestCase``). 46 47 You can use this with any programming language, as you can run the mocker as a 48 normal program. The actual setup of the mock (adding objects, methods, 49 properties, and signals) all happen via D-Bus methods on the 50 ``org.freedesktop.DBus.Mock`` interface. You just don't have the convenience 51 D-Bus launch API that way. 52 53 54 Simple example in Python 55 ------------------------ 56 Picking up the above example about mocking upower's ``Suspend()`` method, this 57 is how you would set up a mock upower in your test case: 58 59 .. code-block:: python 60 61 import dbus 62 import dbusmock 63 64 class TestMyProgram(dbusmock.DBusTestCase): 65 @classmethod 66 def setUpClass(cls): 67 cls.start_system_bus() 68 cls.dbus_con = cls.get_dbus(system_bus=True) 69 70 def setUp(self): 71 self.p_mock = self.spawn_server('org.freedesktop.UPower', 72 '/org/freedesktop/UPower', 73 'org.freedesktop.UPower', 74 system_bus=True, 75 stdout=subprocess.PIPE) 76 77 # Get a proxy for the UPower object's Mock interface 78 self.dbus_upower_mock = dbus.Interface(self.dbus_con.get_object( 79 'org.freedesktop.UPower', '/org/freedesktop/UPower'), 80 dbusmock.MOCK_IFACE) 81 82 self.dbus_upower_mock.AddMethod('', 'Suspend', '', '', '') 83 84 def tearDown(self): 85 self.p_mock.stdout.close() 86 self.p_mock.terminate() 87 self.p_mock.wait() 88 89 def test_suspend_on_idle(self): 90 # run your program in a way that should trigger one suspend call 91 92 # now check the log that we got one Suspend() call 93 self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend$') 94 95 Let's walk through: 96 97 - We derive our tests from ``dbusmock.DBusTestCase`` instead of 98 ``unittest.TestCase`` directly, to make use of the convenience API to start 99 a local system bus. 100 101 - ``setUpClass()`` starts a local system bus, and makes a connection to it available 102 to all methods as ``dbus_con``. ``True`` means that we connect to the 103 system bus, not the session bus. We can use the same bus for all tests, so 104 doing this once in ``setUpClass()`` instead of ``setUp()`` is enough. 105 106 - ``setUp()`` spawns the mock D-Bus server process for an initial 107 ``/org/freedesktop/UPower`` object with an ``org.freedesktop.UPower`` D-Bus 108 interface on the system bus. We capture its stdout to be able to verify that 109 methods were called. 110 111 We then call ``org.freedesktop.DBus.Mock.AddMethod()`` to add a 112 ``Suspend()`` method to our new object to the default D-Bus interface. This 113 will not do anything (except log its call to stdout). It takes no input 114 arguments, returns nothing, and does not run any custom code. 115 116 - ``tearDown()`` stops our mock D-Bus server again. We do this so that each 117 test case has a fresh and clean upower instance, but of course you can also 118 set up everything in ``setUpClass()`` if tests do not interfere with each 119 other on setting up the mock. 120 121 - ``test_suspend_on_idle()`` is the actual test case. It needs to run your 122 program in a way that should trigger one suspend call. Your program will 123 try to call ``Suspend()``, but as that's now being served by our mock 124 instead of upower, there will not be any actual machine suspend. Our 125 mock process will log the method call together with a time stamp; you can 126 use the latter for doing timing related tests, but we just ignore it here. 127 128 Simple example from shell 129 ------------------------- 130 131 We use the actual session bus for this example. You can use 132 ``dbus-run-session`` to start a private one as well if you want, but that is 133 not part of the actual mocking. 134 135 So let's start a mock at the D-Bus name ``com.example.Foo`` with an initial 136 "main" object on path /, with the main D-Bus interface 137 ``com.example.Foo.Manager``: 138 139 :: 140 141 python3 -m dbusmock com.example.Foo / com.example.Foo.Manager 142 143 On another terminal, let's first see what it does: 144 145 :: 146 147 gdbus introspect --session -d com.example.Foo -o / 148 149 You'll see that it supports the standard D-Bus ``Introspectable`` and 150 ``Properties`` interfaces, as well as the ``org.freedesktop.DBus.Mock`` 151 interface for controlling the mock, but no "real" functionality yet. So let's 152 add a method: 153 154 :: 155 156 gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod '' Ping '' '' '' 157 158 Now you can see the new method in ``introspect``, and call it: 159 160 :: 161 162 gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Ping 163 164 The mock process in the other terminal will log the method call with a time 165 stamp, and you'll see something like ``1348832614.970 Ping``. 166 167 Now add another method with two int arguments and a return value and call it: 168 169 :: 170 171 gdbus call --session -d com.example.Foo -o / -m org.freedesktop.DBus.Mock.AddMethod \ 172 '' Add 'ii' 'i' 'ret = args[0] + args[1]' 173 gdbus call --session -d com.example.Foo -o / -m com.example.Foo.Manager.Add 2 3 174 175 This will print ``(5,)`` as expected (remember that the return value is always 176 a tuple), and again the mock process will log the Add method call. 177 178 You can do the same operations in e. g. d-feet or any other D-Bus language 179 binding. 180 181 Logging 182 ------- 183 Usually you want to verify which methods have been called on the mock with 184 which arguments. There are three ways to do that: 185 186 - By default, the mock process writes the call log to stdout. 187 188 - You can call the mock process with the ``-l``/``--logfile`` argument, or 189 specify a log file object in the ``spawn_server()`` method if you are using 190 Python. 191 192 - You can use the ``GetCalls()``, ``GetMethodCalls()`` and ``ClearCalls()`` 193 methods on the ``org.freedesktop.DBus.Mock`` D-Bus interface to get an array 194 of tuples describing the calls. 195 196 197 Templates 198 --------- 199 Some D-Bus services are commonly used in test suites, such as UPower or 200 NetworkManager. python-dbusmock provides "templates" which set up the common 201 structure of these services (their main objects, properties, and methods) so 202 that you do not need to carry around this common code, and only need to set up 203 the particular properties and specific D-Bus objects that you need. These 204 templates can be parameterized for common customizations, and they can provide 205 additional convenience methods on the ``org.freedesktop.DBus.Mock`` interface 206 to provide more abstract functionality like "add a battery". 207 208 For example, for starting a server with the "upower" template in Python you can 209 run 210 211 :: 212 213 (self.p_mock, self.obj_upower) = self.spawn_server_template( 214 'upower', {'OnBattery': True}, stdout=subprocess.PIPE) 215 216 or load a template into an already running server with the ``AddTemplate()`` 217 method; this is particularly useful if you are not using Python: 218 219 :: 220 221 python3 -m dbusmock --system org.freedesktop.UPower /org/freedesktop/UPower org.freedesktop.UPower 222 223 gdbus call --system -d org.freedesktop.UPower -o /org/freedesktop/UPower -m org.freedesktop.DBus.Mock.AddTemplate 'upower' '{"OnBattery": <true>}' 224 225 This creates all expected properties such as ``DaemonVersion``, and changes the 226 default for one of them (``OnBattery``) through the (optional) parameters dict. 227 228 If you do not need to specify parameters, you can do this in a simpler way with 229 230 :: 231 232 python3 -m dbusmock --template upower 233 234 The template does not create any devices by default. You can add some with 235 the template's convenience methods like 236 237 :: 238 239 ac_path = self.dbusmock.AddAC('mock_AC', 'Mock AC') 240 bt_path = self.dbusmock.AddChargingBattery('mock_BAT', 'Mock Battery', 30.0, 1200) 241 242 or calling ``AddObject()`` yourself with the desired properties, of course. 243 244 If you want to contribute a template, look at dbusmock/templates/upower.py for 245 a real-life implementation. You can copy dbusmock/templates/SKELETON to your 246 new template file name and replace "CHANGEME" with the actual code/values. 247 248 249 More Examples 250 ------------- 251 Have a look at the test suite for two real-live use cases: 252 253 - ``tests/test_upower.py`` simulates upowerd, in a more complete way than in 254 above example and using the ``upower`` template. It verifies that 255 ``upower --dump`` is convinced that it's talking to upower. 256 257 - ``tests/test_api.py`` runs a mock on the session bus and exercises all 258 available functionality, such as adding additional objects, properties, 259 multiple methods, input arguments, return values, code in methods, raising 260 signals, and introspection. 261 262 263 Documentation 264 ------------- 265 The ``dbusmock`` module has extensive documentation built in, which you can 266 read with e. g. ``pydoc3 dbusmock``. 267 268 ``pydoc3 dbusmock.DBusMockObject`` shows the D-Bus API of the mock object, 269 i. e. methods like ``AddObject()``, ``AddMethod()`` etc. which are used to set 270 up your mock object. 271 272 ``pydoc3 dbusmock.DBusTestCase`` shows the convenience Python API for writing 273 test cases with local private session/system buses and launching the server. 274 275 ``pydoc3 dbusmock.templates`` shows all available templates. 276 277 ``pydoc3 dbusmock.templates.NAME`` shows the documentation and available 278 parameters for the ``NAME`` template. 279 280 ``python3 -m dbusmock --help`` shows the arguments and options for running the 281 mock server as a program. 282 283 284 Development 285 ----------- 286 python-dbusmock is hosted on github: 287 288 https://github.com/martinpitt/python-dbusmock 289 290 Run the unit tests with 291 292 python3 -m unittest 293 294Platform: UNKNOWN 295Classifier: Programming Language :: Python 296Classifier: Programming Language :: Python :: 2 297Classifier: Programming Language :: Python :: 3 298Classifier: Development Status :: 3 - Alpha 299Classifier: Environment :: Other Environment 300Classifier: Intended Audience :: Developers 301Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+) 302Classifier: Operating System :: POSIX :: Linux 303Classifier: Operating System :: POSIX :: BSD 304Classifier: Operating System :: Unix 305Classifier: Topic :: Software Development :: Quality Assurance 306Classifier: Topic :: Software Development :: Testing 307Classifier: Topic :: Software Development :: Libraries :: Python Modules 308