Make it easier to run mock services in place of real ones
A lot of the code in python-dbusmock assumes that the developer will want to create a fake bus, along with fake services to specifically run a test case.
This makes it difficult to reuse the templates to create replacement for real service, which one would run in place of the real service, for the purpose of testing an interactive UI.
For example, having a run-mock-upower.py with a menu of different scenarios would make it a good replacement for the hard-coded tests rigged into GNOME's Power panel which don't really test the upower communication.
Right now you can do this on the CLI, as described in README:
sudo systemctl stop upower
sudo python3 -m dbusmock -t upower
Then upower --dump shows the mocked devices, and the mock shows the called methods. By calling methods on the Mock interface, you can also change the mock on the fly.
Do you have some ideas/suggestions how to make this more convenient? Merci !
I was actually looking for something which wouldn't require launching the service, waiting for it to become available, attaching to it, and calling out to change the default mocked values separately, all things that the testcase class code does.
The idea being that this (single file python) live test helper would probably stop upower, launch a mock upower, modify the mock upower depending on the use case being tested, and when done stop the mock upower, and relaunch the real one.
The systemctl stop upower is actually not necessary, as dbusmock.py uses allow_replacement=True and replace_existing=True. You can also specify parameters in JSON form with -p. Once stopping the mock, D-Bus activation will just bring back the real upower.service.
So the CLI cares about all the bits in your list. The one thing that it can't do is to tell you when it's ready, as it just runs synchronous. There's two main ways here: (1) it could grow a --background option, to fork itself into the background once the setup is done, and then you kill that pid (but it's a bit fiddly to tell you which pid that is), or it could accept an argv vector after -- and just run that after the setup. This could be something like sudo python3 -m dbusmock -t upower -- bash -i.
Would that work for you? Any other ideas?
The
systemctl stop upoweris actually not necessary, as dbusmock.py usesallow_replacement=Trueandreplace_existing=True. You can also specify parameters in JSON form with-p. Once stopping the mock, D-Bus activation will just bring back the real upower.service.
That works, although passing parameters as JSON is unlikely to be something human-parseable before long.
So the CLI cares about all the bits in your list. The one thing that it can't do is to tell you when it's ready, as it just runs synchronous. There's two main ways here: (1) it could grow a
--backgroundoption, to fork itself into the background once the setup is done, and then you kill that pid (but it's a bit fiddly to tell you which pid that is), or it could accept an argv vector after--and just run that after the setup. This could be something likesudo python3 -m dbusmock -t upower -- bash -i.
I don't actually care about the server being ready per-se, I care about it being available to feed commands.
Would that work for you? Any other ideas?
This is what I'd like to be able to have:
- one command to run the fake upower
- fake upower is interactive, and has a simple menu, eg. something to plug/unplug the power cord, change the battery level
parsing info from template to arguments is duplicated between dbusmock/__main__.py and testcase.spawn_server_template, and calls out deep inside the testcase class to dbusmock.testcase.DBusTestCase.get_dbus() which is a bit weird.
I would expect most of the code below to disappear into function calls.
#!/usr/bin/python3
import dbusmock.mockobject
import dbusmock.testcase
if __name__ == '__main__':
import dbus.service
import dbus.mainloop.glib
from gi.repository import GLib
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
module = dbusmock.mockobject.load_module("upower")
name = module.BUS_NAME
path = module.MAIN_OBJ
system_bus = module.SYSTEM_BUS
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(module.BUS_NAME,
dbusmock.testcase.DBusTestCase.get_dbus(module.BUS_NAME),
allow_replacement=True,
replace_existing=True,
do_not_queue=True)
main_object = dbusmock.mockobject.DBusMockObject(bus_name, module.MAIN_OBJ,
module.MAIN_IFACE, {},
None,
False)
dbusmock.mockobject.objects[module.MAIN_OBJ] = main_object
# FIXME Wait here
# FIXME Setup defaults
# FIXME Setup menu
main_loop.run()