diff --git a/README.md b/README.md index 2bdb485..7bd15d4 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,20 @@ 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. +Suppose you want to write tests for a desktop environment's power management: +You want to verify that after the configured idle time the program suspends the +machine. So your program calls `org.freedesktop.login1.Manager.Suspend()` on +the system D-Bus. + +Now, your test suite should not really talk to the actual system D-Bus and +the real systemd; 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 running systemd 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 @@ -47,11 +47,12 @@ convenience D-Bus launch API that way. ## Simple example using Python's unittest -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: +Picking up the above example about mocking systemd-logind's `Suspend()` +method, this is how you would set up a mock logind in your test case: ```python import subprocess +import unittest import dbus @@ -65,29 +66,32 @@ class TestMyProgram(dbusmock.DBusTestCase): 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', + self.p_mock = self.spawn_server('org.freedesktop.login1', + '/org/freedesktop/login1', + 'org.freedesktop.login1.Manager', system_bus=True, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) - # 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'), + # Get a proxy for the logind object's Mock interface + self.dbus_logind_mock = dbus.Interface(self.dbus_con.get_object( + 'org.freedesktop.login1', '/org/freedesktop/login1'), 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() + self.dbus_logind_mock.AddMethod('', 'Suspend', 'b', '', '') def test_suspend_on_idle(self): # run your program in a way that should trigger one suspend call + # represented here as direct D-Bus call + subprocess.check_call( + ["busctl", "call", "org.freedesktop.login1", + "/org/freedesktop/login1", "org.freedesktop.login1.Manager", + "Suspend", "b", "false"]) # now check the log that we got one Suspend() call - self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend$') + self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend False$') ``` Let's walk through: @@ -103,7 +107,7 @@ Let's walk through: 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` + `/org/freedesktop/login1` object with an `org.freedesktop.login1` D-Bus interface on the system bus. We capture its stdout to be able to verify that methods were called. @@ -113,18 +117,21 @@ Let's walk through: 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 + We use `addCleanup()` to register cleanup handlers that will + stop our mock D-Bus server after each test. This ensures each + test case has a fresh and clean logind mock instance. 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. + your program in a way that should trigger one suspend call. For this + example this is represented by doing just a direct D-Bus call using + `busctl`. + + That `Suspend()` call is now being served by our mock instead of the real + logind, 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 using pytest @@ -132,73 +139,68 @@ The same functionality as above but instead using the pytest fixture provided by this package. ```python +# Enable dbusmock's pytest fixtures (can also go in conftest.py) +pytest_plugins = "dbusmock.pytest_fixtures" + import subprocess import dbus -import pytest import dbusmock -@pytest.fixture -def upower_mock(dbusmock_system): - p_mock = dbusmock_system.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 - dbus_upower_mock = dbus.Interface(dbusmock_system.get_dbus(True).get_object( - 'org.freedesktop.UPower', - '/org/freedesktop/UPower' - ), dbusmock.MOCK_IFACE) - dbus_upower_mock.AddMethod('', 'Suspend', '', '', '') - - yield p_mock - - p_mock.stdout.close() - p_mock.terminate() - p_mock.wait() - - -def test_suspend_on_idle(upower_mock): - # run your program in a way that should trigger one suspend call - - # now check the log that we got one Suspend() call - assert upower_mock.stdout.readline() == b'^[0-9.]+ Suspend$' +def test_suspend_on_idle(dbusmock_system): + # Spawn the mock D-Bus server for logind on the system bus + with dbusmock.SpawnedMock.spawn_for_name( + 'org.freedesktop.login1', + '/org/freedesktop/login1', + 'org.freedesktop.login1.Manager', + dbusmock.BusType.SYSTEM, + stdout=subprocess.PIPE) as p_mock: + + # Get a proxy for the logind object's Mock interface + obj_logind = p_mock.obj + obj_logind.AddMethod('', 'Suspend', 'b', '', '', interface_name=dbusmock.MOCK_IFACE) + + # Run your program in a way that should trigger one suspend call + # represented here as direct D-Bus call + subprocess.check_call( + ["busctl", "call", "org.freedesktop.login1", + "/org/freedesktop/login1", "org.freedesktop.login1.Manager", + "Suspend", "b", "false"]) + + # Check the log that we got one Suspend() call + assert b'Suspend False\n' in p_mock.stdout.readline() ``` Let's walk through: +- We enable dbusmock's pytest fixtures with `pytest_plugins = "dbusmock.pytest_fixtures"`. + This makes fixtures like `dbusmock_system` and `dbusmock_session` available to your + tests. In a real project, you would typically put this line in your `conftest.py` + instead of in each test file. + - We import the `dbusmock_system` fixture from dbusmock which provides us - with a system bus started for our test case wherever the - `dbusmock_system` argument is used by a test case and/or a pytest - fixture. - -- The `upower_mock` fixture 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. - - This mock server process is yielded to the test function that uses - the `upower_mock` fixture - once the test is complete the process is - terminated again. - -- `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. + with a system bus started for our test case. Even though we don't use it + directly in this simple example, it ensures the test environment is set up. + +- `test_suspend_on_idle()` is the actual test. It uses + `SpawnedMock.spawn_for_name()` to spawn the mock D-Bus server process for + `/org/freedesktop/login1` object with `org.freedesktop.login1.Manager` + interface. We capture its stdout to verify that methods were called. + + We then call `org.freedesktop.DBus.Mock.AddMethod()` to add a `Suspend()` + method to our new logind mock object to the default D-Bus interface. This + will not do anything (except log its call to stdout). It takes one boolean + input argument, returns nothing, and does not run any custom code. + + Exactly like in the unittest example above, we then run our program in a way that + should trigger one suspend call. For this example this is again represented + by doing just a direct D-Bus call using `busctl`. The log of the call gets + asserted. + + The context manager automatically terminates the mock server process after + the test completes. ## Simple example from shell diff --git a/dbusmock/__init__.py b/dbusmock/__init__.py index ee5bc8a..3ec4b00 100644 --- a/dbusmock/__init__.py +++ b/dbusmock/__init__.py @@ -1,10 +1,6 @@ """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. +# SPDX-License-Identifier: LGPL-3.0-or-later from dbusmock.mockobject import MOCK_IFACE, OBJECT_MANAGER_IFACE, DBusMockObject, get_object, get_objects from dbusmock.testcase import BusType, DBusTestCase, PrivateDBus, SpawnedMock diff --git a/dbusmock/__main__.py b/dbusmock/__main__.py index a21c78f..8c04c5a 100644 --- a/dbusmock/__main__.py +++ b/dbusmock/__main__.py @@ -1,10 +1,6 @@ """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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/dbusmock/mockobject.py b/dbusmock/mockobject.py index 14f40a4..1a66cde 100644 --- a/dbusmock/mockobject.py +++ b/dbusmock/mockobject.py @@ -1,10 +1,6 @@ """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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/dbusmock/pytest_fixtures.py b/dbusmock/pytest_fixtures.py index d3e70a4..a6c508f 100644 --- a/dbusmock/pytest_fixtures.py +++ b/dbusmock/pytest_fixtures.py @@ -1,10 +1,6 @@ """pytest fixtures for DBusMock""" -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = "(c) 2023 Martin Pitt " diff --git a/dbusmock/templates/__init__.py b/dbusmock/templates/__init__.py index ea9212d..159cbae 100644 --- a/dbusmock/templates/__init__.py +++ b/dbusmock/templates/__init__.py @@ -1,7 +1,3 @@ """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. +# SPDX-License-Identifier: LGPL-3.0-or-later diff --git a/dbusmock/templates/bluez5-obex.py b/dbusmock/templates/bluez5-obex.py index d6192ec..e14c70f 100644 --- a/dbusmock/templates/bluez5-obex.py +++ b/dbusmock/templates/bluez5-obex.py @@ -7,11 +7,7 @@ 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Philip Withnall" __copyright__ = """ diff --git a/dbusmock/templates/bluez5.py b/dbusmock/templates/bluez5.py index a1ef46d..c27ce6a 100644 --- a/dbusmock/templates/bluez5.py +++ b/dbusmock/templates/bluez5.py @@ -7,11 +7,7 @@ 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Philip Withnall" __copyright__ = """ diff --git a/dbusmock/templates/gnome_screensaver.py b/dbusmock/templates/gnome_screensaver.py index 143df57..772f19a 100644 --- a/dbusmock/templates/gnome_screensaver.py +++ b/dbusmock/templates/gnome_screensaver.py @@ -4,11 +4,7 @@ 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ diff --git a/dbusmock/templates/gsd_rfkill.py b/dbusmock/templates/gsd_rfkill.py index a4cea27..588f14d 100644 --- a/dbusmock/templates/gsd_rfkill.py +++ b/dbusmock/templates/gsd_rfkill.py @@ -5,11 +5,7 @@ "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Guido Günther" __copyright__ = "2024 The Phosh Developers" diff --git a/dbusmock/templates/logind.py b/dbusmock/templates/logind.py index 6440c3a..22def4d 100644 --- a/dbusmock/templates/logind.py +++ b/dbusmock/templates/logind.py @@ -5,11 +5,7 @@ like "CanSuspend" or the return value of Inhibit() in "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -62,6 +58,7 @@ def load(mock, parameters): ("GetUser", "u", "o", 'ret = "/org/freedesktop/login1/user/" + args[0]'), ("KillUser", "us", "", ""), ("TerminateUser", "u", "", ""), + ("SetWallMessage", "sb", "", ""), ], ) diff --git a/dbusmock/templates/low_memory_monitor.py b/dbusmock/templates/low_memory_monitor.py index c29e5e9..081fd85 100644 --- a/dbusmock/templates/low_memory_monitor.py +++ b/dbusmock/templates/low_memory_monitor.py @@ -6,11 +6,7 @@ This provides only the 2.0 D-Bus API of low-memory-monitor. """ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ diff --git a/dbusmock/templates/modemmanager.py b/dbusmock/templates/modemmanager.py index c363c2a..e4754b7 100644 --- a/dbusmock/templates/modemmanager.py +++ b/dbusmock/templates/modemmanager.py @@ -5,11 +5,7 @@ such as DaemonVersion in "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Guido Günther" __copyright__ = "2024 The Phosh Developers" diff --git a/dbusmock/templates/networkmanager.py b/dbusmock/templates/networkmanager.py index f9dab3e..318e4aa 100644 --- a/dbusmock/templates/networkmanager.py +++ b/dbusmock/templates/networkmanager.py @@ -6,11 +6,7 @@ "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Iftikhar Ahmad" __copyright__ = """ diff --git a/dbusmock/templates/notification_daemon.py b/dbusmock/templates/notification_daemon.py index 7ac602c..fa106d4 100644 --- a/dbusmock/templates/notification_daemon.py +++ b/dbusmock/templates/notification_daemon.py @@ -5,11 +5,7 @@ "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/dbusmock/templates/ofono.py b/dbusmock/templates/ofono.py index c88cd28..074102a 100644 --- a/dbusmock/templates/ofono.py +++ b/dbusmock/templates/ofono.py @@ -1,10 +1,6 @@ """ofonod 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/dbusmock/templates/polkitd.py b/dbusmock/templates/polkitd.py index c8c6575..2bd8b58 100644 --- a/dbusmock/templates/polkitd.py +++ b/dbusmock/templates/polkitd.py @@ -6,11 +6,7 @@ which actions are allowed. """ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -71,6 +67,11 @@ def RegisterAuthenticationAgent(_self, _subject, _locale, _object_path): pass +@dbus.service.method(MAIN_IFACE, in_signature="(sa{sv})ssa{sv}") +def RegisterAuthenticationAgentWithOptions(_self, _subject, _locale, _object_path, _options): + pass + + @dbus.service.method(MOCK_IFACE, in_signature="b", out_signature="") def AllowUnknown(self, default): """Control whether unknown actions are allowed diff --git a/dbusmock/templates/power_profiles_daemon.py b/dbusmock/templates/power_profiles_daemon.py index 5986cdb..df54b5e 100644 --- a/dbusmock/templates/power_profiles_daemon.py +++ b/dbusmock/templates/power_profiles_daemon.py @@ -8,11 +8,7 @@ bus name/object path, it is provided in upower_power_profiles_daemon.py """ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ diff --git a/dbusmock/templates/systemd.py b/dbusmock/templates/systemd.py index f1fe508..6c4f639 100644 --- a/dbusmock/templates/systemd.py +++ b/dbusmock/templates/systemd.py @@ -1,10 +1,6 @@ """systemd 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Jonas Ådahl" __copyright__ = """ diff --git a/dbusmock/templates/timedated.py b/dbusmock/templates/timedated.py index 6520974..24d667e 100644 --- a/dbusmock/templates/timedated.py +++ b/dbusmock/templates/timedated.py @@ -5,11 +5,7 @@ "Timezone" or "NTP" in "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Iain Lane" __copyright__ = """ diff --git a/dbusmock/templates/upower.py b/dbusmock/templates/upower.py index 3d649e6..6958edd 100644 --- a/dbusmock/templates/upower.py +++ b/dbusmock/templates/upower.py @@ -8,11 +8,7 @@ This provides the 1.0 D-Bus API of upower. """ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/dbusmock/templates/upower_power_profiles_daemon.py b/dbusmock/templates/upower_power_profiles_daemon.py index 2c945eb..25f0ba4 100644 --- a/dbusmock/templates/upower_power_profiles_daemon.py +++ b/dbusmock/templates/upower_power_profiles_daemon.py @@ -6,11 +6,7 @@ This provides the D-Bus API as of version 0.20. """ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ diff --git a/dbusmock/templates/urfkill.py b/dbusmock/templates/urfkill.py index 7566961..3dce2b2 100644 --- a/dbusmock/templates/urfkill.py +++ b/dbusmock/templates/urfkill.py @@ -5,11 +5,7 @@ such as urfkill in "parameters". """ -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU Lesser General Public License as published by the Free -# Software Foundation; either version 3 of the License, or (at your option) any -# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text -# of the license. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Jussi Pakkanen" __copyright__ = """ diff --git a/dbusmock/testcase.py b/dbusmock/testcase.py index 97a73e7..ed92689 100644 --- a/dbusmock/testcase.py +++ b/dbusmock/testcase.py @@ -1,10 +1,6 @@ """unittest.TestCase convenience methods for DBusMocks""" -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/tests/test_api.py b/tests/test_api.py index 334d99a..b3ca843 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -49,6 +45,8 @@ def setUp(self): self.p_mock = self.spawn_server( "org.freedesktop.Test", "/", "org.freedesktop.Test.Main", stdout=self.mock_log ) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) self.obj_test = self.dbus_con.get_object("org.freedesktop.Test", "/") self.dbus_test = dbus.Interface(self.obj_test, "org.freedesktop.Test.Main") @@ -58,12 +56,6 @@ def setUp(self): def assertLog(self, regex): self.assertRegex(Path(self.mock_log.name).read_bytes(), regex) - def tearDown(self): - if self.p_mock.stdout: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_noarg_noret(self): """no arguments, no return value""" diff --git a/tests/test_api_pytest.py b/tests/test_api_pytest.py index d232470..854814f 100644 --- a/tests/test_api_pytest.py +++ b/tests/test_api_pytest.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/tests/test_bluez5.py b/tests/test_bluez5.py index 17c1359..4bcc36c 100644 --- a/tests/test_bluez5.py +++ b/tests/test_bluez5.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Philip Withnall" __copyright__ = """ @@ -99,6 +95,9 @@ def setUpClass(cls): cls.start_system_bus() cls.dbus_con = cls.get_dbus(True) (cls.p_mock, cls.obj_bluez) = cls.spawn_server_template("bluez5", {}, stdout=subprocess.PIPE) + cls.addClassCleanup(cls.p_mock.wait) + cls.addClassCleanup(cls.p_mock.terminate) + cls.addClassCleanup(cls.p_mock.stdout.close) out = _run_bluetoothctl("version") version = next(line.split(" ")[-1] for line in out if line.startswith("Version")) @@ -581,22 +580,19 @@ def setUpClass(cls): def setUp(self): # bluetoothd (self.p_mock, self.obj_bluez) = self.spawn_server_template("bluez5", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) self.dbusmock_bluez = dbus.Interface(self.obj_bluez, "org.bluez.Mock") # obexd (self.p_mock_obex, self.obj_obex) = self.spawn_server_template("bluez5-obex", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock_obex.wait) + self.addCleanup(self.p_mock_obex.terminate) + self.addCleanup(self.p_mock_obex.stdout.close) self.dbusmock = dbus.Interface(self.obj_obex, dbusmock.MOCK_IFACE) self.dbusmock_obex = dbus.Interface(self.obj_obex, "org.bluez.obex.Mock") - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - - self.p_mock_obex.stdout.close() - self.p_mock_obex.terminate() - self.p_mock_obex.wait() - def test_everything(self): # Set up an adapter and device. adapter_name = "hci0" diff --git a/tests/test_cli.py b/tests/test_cli.py index eaabef8..746eca8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -31,6 +27,8 @@ class TestCLI(dbusmock.DBusTestCase): """Test running dbusmock from the command line""" + p_mock = None + @classmethod def setUpClass(cls): cls.start_system_bus() @@ -38,24 +36,14 @@ def setUpClass(cls): cls.system_con = cls.get_dbus(True) cls.session_con = cls.get_dbus() - def setUp(self): - self.p_mock = None - - def tearDown(self): - if self.p_mock: - if self.p_mock.stdout: - self.p_mock.stdout.close() - if self.p_mock.stderr: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - self.p_mock = None - def start_mock(self, args, wait_name, wait_path, wait_system=False): # pylint: disable=consider-using-with self.p_mock = subprocess.Popen( [sys.executable, "-m", "dbusmock", *args], stdout=subprocess.PIPE, universal_newlines=True ) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) self.wait_for_bus_object(wait_name, wait_path, wait_system) def start_mock_process(self, args): diff --git a/tests/test_code.py b/tests/test_code.py index c5ccace..a1a801a 100644 --- a/tests/test_code.py +++ b/tests/test_code.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ diff --git a/tests/test_gnome_screensaver.py b/tests/test_gnome_screensaver.py index 62d7e72..e54e101 100644 --- a/tests/test_gnome_screensaver.py +++ b/tests/test_gnome_screensaver.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -29,15 +25,13 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.obj_ss) = self.spawn_server_template("gnome_screensaver", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_default_state(self): """Not locked by default""" diff --git a/tests/test_gsd_rfkill.py b/tests/test_gsd_rfkill.py index 3c07173..875c44d 100644 --- a/tests/test_gsd_rfkill.py +++ b/tests/test_gsd_rfkill.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Guido Günther" __copyright__ = "2024 The Phosh Developers" @@ -28,15 +24,13 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.p_obj) = self.spawn_server_template("gsd_rfkill", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_mainobject(self): propiface = dbus.Interface(self.p_obj, dbus.PROPERTIES_IFACE) diff --git a/tests/test_logind.py b/tests/test_logind.py index 8ca2b66..5be9001 100644 --- a/tests/test_logind.py +++ b/tests/test_logind.py @@ -1,15 +1,13 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ (c) 2013 Canonical Ltd. -(c) 2017 - 2022 Martin Pitt +(c) 2017 - 2025 Martin Pitt """ +import fcntl +import os import re import shutil import subprocess @@ -41,16 +39,15 @@ def setUpClass(cls): cls.version = re.search(r"(\d+)", out.splitlines()[0]).group(1) def setUp(self): - self.p_mock = None + (self.p_mock, self.obj_logind) = self.spawn_server_template("logind", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) - def tearDown(self): - if self.p_mock: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() + flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) + fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) def test_empty(self): - (self.p_mock, _) = self.spawn_server_template("logind", {}, stdout=subprocess.PIPE) cmd = ["loginctl"] if self.version >= "209": cmd.append("--no-legend") @@ -64,9 +61,7 @@ def test_empty(self): self.assertEqual(out, "") def test_session(self): - (self.p_mock, obj_logind) = self.spawn_server_template("logind", {}, stdout=subprocess.PIPE) - - obj_logind.AddSession("c1", "seat0", 500, "joe", True) + self.obj_logind.AddSession("c1", "seat0", 500, "joe", True) out = subprocess.check_output(["loginctl", "list-seats"], text=True) self.assertRegex(out, r"(^|\n)seat0\s+") @@ -112,16 +107,13 @@ def test_session(self): self.assertRegex(out, "LockedHint=yes") def test_properties(self): - (self.p_mock, obj_logind) = self.spawn_server_template("logind", {}, stdout=subprocess.PIPE) - props = obj_logind.GetAll("org.freedesktop.login1.Manager", interface=dbus.PROPERTIES_IFACE) + props = self.obj_logind.GetAll("org.freedesktop.login1.Manager", interface=dbus.PROPERTIES_IFACE) self.assertEqual(props["PreparingForSleep"], False) self.assertEqual(props["IdleSinceHint"], 0) def test_inhibit(self): - (self.p_mock, obj_logind) = self.spawn_server_template("logind", {}, stdout=subprocess.PIPE) - # what, who, why, mode - fd = obj_logind.Inhibit("suspend", "testcode", "purpose", "delay") + fd = self.obj_logind.Inhibit("suspend", "testcode", "purpose", "delay") # Our inhibitor is held out = subprocess.check_output(["systemd-inhibit"], text=True) @@ -136,6 +128,17 @@ def test_inhibit(self): out = subprocess.check_output(["systemd-inhibit"], text=True) self.assertRegex(out, "No inhibitors|0 inhibitors listed") + def test_suspend(self): + (p_mock_polkit, _obj_polkitd) = self.spawn_server_template("polkitd", {}, stdout=subprocess.DEVNULL) + self.addCleanup(p_mock_polkit.wait) + self.addCleanup(p_mock_polkit.terminate) + + subprocess.check_call(["systemctl", "suspend"]) + + log = self.p_mock.stdout.read().decode() + self.assertIn('SetWallMessage "" True', log) + self.assertIn("Suspend True", log) + if __name__ == "__main__": # avoid writing to stderr diff --git a/tests/test_low_memory_monitor.py b/tests/test_low_memory_monitor.py index 980ddbe..91df9f1 100644 --- a/tests/test_low_memory_monitor.py +++ b/tests/test_low_memory_monitor.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ @@ -34,17 +30,15 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.obj_lmm) = self.spawn_server_template("low_memory_monitor", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) self.last_warning = -1 self.dbusmock = dbus.Interface(self.obj_lmm, dbusmock.MOCK_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_low_memory_warning_signal(self): """LowMemoryWarning signal""" diff --git a/tests/test_modemmanager.py b/tests/test_modemmanager.py index 8b3ee20..dc5d03b 100644 --- a/tests/test_modemmanager.py +++ b/tests/test_modemmanager.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Guido Günther" __copyright__ = """ @@ -42,14 +38,9 @@ def setUpClass(cls): def setUp(self): super().setUp() (self.p_mock, self.p_obj) = self.spawn_server_template("modemmanager", {}, stdout=subprocess.PIPE) - - def tearDown(self): - if self.p_mock: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - - super().tearDown() + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) def get_property(self, name): return self.p_obj.Get(self.dbus_interface, name, dbus_interface=dbus.PROPERTIES_IFACE) diff --git a/tests/test_networkmanager.py b/tests/test_networkmanager.py index 40a7384..d8472fd 100644 --- a/tests/test_networkmanager.py +++ b/tests/test_networkmanager.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Iftikhar Ahmad" __copyright__ = """ @@ -70,14 +66,12 @@ def setUp(self): (self.p_mock, self.obj_networkmanager) = self.spawn_server_template( "networkmanager", {"NetworkingEnabled": True, "WwanEnabled": False}, stdout=subprocess.PIPE ) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) self.dbusmock = dbus.Interface(self.obj_networkmanager, dbusmock.MOCK_IFACE) self.settings = dbus.Interface(self.dbus_con.get_object(MANAGER_IFACE, SETTINGS_OBJ), SETTINGS_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def read_general(self): return subprocess.check_output(["nmcli", "--nocheck", "general"], env=self.lang_env, text=True) diff --git a/tests/test_notification_daemon.py b/tests/test_notification_daemon.py index edbd425..ac95eca 100644 --- a/tests/test_notification_daemon.py +++ b/tests/test_notification_daemon.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -39,15 +35,13 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.obj_daemon) = self.spawn_server_template("notification_daemon", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_no_options(self): """notify-send with no options""" diff --git a/tests/test_ofono.py b/tests/test_ofono.py index ac30cb8..2bfaedc 100644 --- a/tests/test_ofono.py +++ b/tests/test_ofono.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -34,6 +30,9 @@ def setUpClass(cls): cls.start_system_bus() cls.dbus_con = cls.get_dbus(True) (cls.p_mock, cls.obj_ofono) = cls.spawn_server_template("ofono", {}, stdout=subprocess.PIPE) + cls.addClassCleanup(cls.p_mock.wait) + cls.addClassCleanup(cls.p_mock.terminate) + cls.addClassCleanup(cls.p_mock.stdout.close) def setUp(self): self.obj_ofono.Reset() diff --git a/tests/test_polkitd.py b/tests/test_polkitd.py index 2f14abc..5b67992 100644 --- a/tests/test_polkitd.py +++ b/tests/test_polkitd.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -35,13 +31,11 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.obj_polkitd) = self.spawn_server_template("polkitd", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) self.dbusmock = dbus.Interface(self.obj_polkitd, dbusmock.MOCK_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_default(self): self.check_action("org.freedesktop.test.frobnicate", False) diff --git a/tests/test_power_profiles_daemon.py b/tests/test_power_profiles_daemon.py index 23a383f..974ee41 100644 --- a/tests/test_power_profiles_daemon.py +++ b/tests/test_power_profiles_daemon.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Bastien Nocera" __copyright__ = """ @@ -51,16 +47,14 @@ def setUp(self): template = "upower_power_profiles_daemon" (self.p_mock, self.obj_ppd) = self.spawn_server_template(template, {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) self.dbusmock = dbus.Interface(self.obj_ppd, dbusmock.MOCK_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_list_profiles(self): """List Profiles and check active profile""" diff --git a/tests/test_readme_examples.py b/tests/test_readme_examples.py new file mode 100644 index 0000000..7d0e042 --- /dev/null +++ b/tests/test_readme_examples.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: LGPL-3.0-or-later + +"""Test that code examples in README.md actually work""" + +# pylint does not understand pytest fixtures.. +# pylint: disable=redefined-outer-name + +__author__ = "Martin Pitt" +__copyright__ = """ +(c) 2026 Martin Pitt +""" + +import re +import subprocess +import sys +from pathlib import Path + +import pytest + + +@pytest.fixture(scope="module") +def readme_blocks(): + """Extract Python code blocks from README.md""" + readme_path = Path(__file__).parent.parent / "README.md" + return re.findall(r"```python\n(.*?)\n```", readme_path.read_text(), re.DOTALL) + + +def test_examples_exist(readme_blocks): + """Verify that we found some Python code blocks""" + assert len(readme_blocks) > 0 + + +def test_readme_examples(readme_blocks, tmp_path): + """Test all README examples by running them through pytest""" + for i, code_block in enumerate(readme_blocks): + test_file = tmp_path / f"test_readme_example_{i}.py" + test_file.write_text(code_block) + + subprocess.run( + [sys.executable, "-m", "pytest", str(test_file), "-v"], + check=True, + ) diff --git a/tests/test_systemd.py b/tests/test_systemd.py index 6ee0ab2..5bcc8b0 100644 --- a/tests/test_systemd.py +++ b/tests/test_systemd.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Jonas Ådahl" __copyright__ = """ @@ -33,15 +29,6 @@ def setUpClass(cls): cls.session_bus = cls.get_dbus(False) cls.system_bus = cls.get_dbus(True) - def setUp(self): - self.p_mock = None - - def tearDown(self): - if self.p_mock: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def _assert_unit_property(self, unit_obj, name, expect): value = unit_obj.Get("org.freedesktop.systemd1.Unit", name) self.assertEqual(str(value), expect) @@ -49,7 +36,10 @@ def _assert_unit_property(self, unit_obj, name, expect): def _test_base(self, bus, system_bus=True): dummy_service = "dummy-dbusmock.service" - (self.p_mock, obj_systemd) = self.spawn_server_template("systemd", {}, subprocess.PIPE, system_bus=system_bus) + (p_mock, obj_systemd) = self.spawn_server_template("systemd", {}, subprocess.PIPE, system_bus=system_bus) + self.addCleanup(p_mock.wait) + self.addCleanup(p_mock.terminate) + self.addCleanup(p_mock.stdout.close) systemd_mock = dbus.Interface(obj_systemd, dbusmock.MOCK_IFACE) systemd_mock.AddMockUnit(dummy_service) @@ -92,11 +82,6 @@ def wait_for_job(path): wait_for_job(job_path) self._assert_unit_property(unit_obj, "ActiveState", "inactive") - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - self.p_mock = None - def test_user(self): self._test_base(self.session_bus, system_bus=False) diff --git a/tests/test_timedated.py b/tests/test_timedated.py index e05cd94..00facd8 100644 --- a/tests/test_timedated.py +++ b/tests/test_timedated.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Iain Lane" __copyright__ = """ @@ -36,14 +32,11 @@ def setUpClass(cls): def setUp(self): (self.p_mock, _) = self.spawn_server_template("timedated", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) self.obj_timedated = self.dbus_con.get_object("org.freedesktop.timedate1", "/org/freedesktop/timedate1") - def tearDown(self): - if self.p_mock: - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def run_timedatectl(self): return subprocess.check_output(["timedatectl"], text=True) diff --git a/tests/test_upower.py b/tests/test_upower.py index 24abd8c..5b20c8e 100644 --- a/tests/test_upower.py +++ b/tests/test_upower.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Martin Pitt" __copyright__ = """ @@ -49,16 +45,14 @@ def setUp(self): }, stdout=subprocess.PIPE, ) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) self.dbusmock = dbus.Interface(self.obj_upower, dbusmock.MOCK_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_no_devices(self): out = subprocess.check_output(["upower", "--dump"], text=True) self.assertIn("/DisplayDevice\n", out) diff --git a/tests/test_urfkill.py b/tests/test_urfkill.py index fe2d125..fdbf3ff 100644 --- a/tests/test_urfkill.py +++ b/tests/test_urfkill.py @@ -1,8 +1,4 @@ -# 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. +# SPDX-License-Identifier: LGPL-3.0-or-later __author__ = "Jussi Pakkanen" __copyright__ = """ @@ -38,16 +34,14 @@ def setUpClass(cls): def setUp(self): (self.p_mock, self.obj_urfkill) = self.spawn_server_template("urfkill", {}, stdout=subprocess.PIPE) + self.addCleanup(self.p_mock.wait) + self.addCleanup(self.p_mock.terminate) + self.addCleanup(self.p_mock.stdout.close) # set log to nonblocking flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) self.dbusmock = dbus.Interface(self.obj_urfkill, dbusmock.MOCK_IFACE) - def tearDown(self): - self.p_mock.stdout.close() - self.p_mock.terminate() - self.p_mock.wait() - def test_mainobject(self): (remote_object, iface) = _get_urfkill_objects() self.assertFalse(iface.IsFlightMode())