Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add assertEventually helper #82

Open
hadess opened this issue Aug 11, 2021 · 2 comments
Open

Add assertEventually helper #82

hadess opened this issue Aug 11, 2021 · 2 comments

Comments

@hadess
Copy link
Contributor

hadess commented Aug 11, 2021

As used and implemented in upower.

As python-dbusmock uses the GLib mainloop in a number of places, it might be useful to add this helper to python-dbusmock.

gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 11, 2021
assertEventually is a helper used in a number of projects that use
dbusmock.

See martinpitt/python-dbusmock#82
gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 11, 2021
assertEventually is a helper used in a number of projects that use
dbusmock.

See martinpitt/python-dbusmock#82
@martinpitt
Copy link
Owner

That seems fine to me. I just really wonder how you use that in upower, I left a question there.

FTR, I'm on PTO until Aug 25 with no access to computers, so this will take a while.

gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 12, 2021
assertEventually is a helper used in a number of projects that use
dbusmock.

See martinpitt/python-dbusmock#82
gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Aug 12, 2021
assertEventually is a helper used in a number of projects that use
dbusmock.

See martinpitt/python-dbusmock#82
@martinpitt
Copy link
Owner

martinpitt commented Sep 9, 2021

I tried this patch:

diff --git dbusmock/testcase.py dbusmock/testcase.py
index 6fb81d6..9814b8e 100644
--- dbusmock/testcase.py
+++ dbusmock/testcase.py
@@ -21,6 +21,8 @@ from typing import Tuple, Dict, Any
 
 import dbus
 
+from gi.repository import GLib
+
 from dbusmock.mockobject import MOCK_IFACE, OBJECT_MANAGER_IFACE, load_module
 
 
@@ -254,3 +256,20 @@ class DBusTestCase(unittest.TestCase):
                         dbus_interface=MOCK_IFACE)
 
         return (daemon, obj)
+
+    def assertEventually(self, condition, message=None, timeout=50):
+        '''Assert that condition function eventually returns True
+
+        Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+        printed on failure. GLib main loop is iterated while waiting.
+        '''
+        context = GLib.MainContext.default()
+        while timeout >= 0:
+            while context.iteration(False):
+                pass
+            if condition():
+                break
+            timeout -= 1
+            time.sleep(0.1)
+        else:
+            self.fail(message or 'timed out waiting for ' + str(condition))
diff --git tests/test_iio_sensors_proxy.py tests/test_iio_sensors_proxy.py
index 481ad58..2025720 100644
--- tests/test_iio_sensors_proxy.py
+++ tests/test_iio_sensors_proxy.py
@@ -62,9 +62,9 @@ class TestIIOSensorsProxyBase(dbusmock.DBusTestCase):
     def set_internal_property(self, name, value):
         return self.p_obj.SetInternalProperty(self.dbus_interface, name, value)
 
-    def wait_for_properties_changed(self, max_wait=2000):
+    # max_wait is timeout in deciseconds
+    def wait_for_properties_changed(self, max_wait=20):
         changed_properties = []
-        timeout_id = 0
 
         def on_properties_changed(interface, properties, _invalidated):
             nonlocal changed_properties
@@ -72,23 +72,12 @@ class TestIIOSensorsProxyBase(dbusmock.DBusTestCase):
             if interface == self.dbus_interface:
                 changed_properties = properties.keys()
 
-        def on_timeout():
-            nonlocal timeout_id
-
-            timeout_id = 0
-
-        loop = GLib.MainLoop()
-        timeout_id = GLib.timeout_add(max_wait, on_timeout)
+        # loop = GLib.MainLoop()
         match = self.p_obj.connect_to_signal('PropertiesChanged',
                                              on_properties_changed,
                                              dbus.PROPERTIES_IFACE)
 
-        while not changed_properties and timeout_id != 0:
-            loop.get_context().iteration(True)
-
-        if timeout_id:
-            GLib.source_remove(timeout_id)
-
+        self.assertEventually(lambda: changed_properties, timeout=max_wait)
         match.remove()
 
         return changed_properties
@@ -140,7 +129,7 @@ class TestIIOSensorsProxy(TestIIOSensorsProxyBase):
         self.set_internal_property('HasAccelerometer', True)
         self.assertTrue(self.get_property('HasAccelerometer'))
         self.set_internal_property('AccelerometerOrientation', 'normal')
-        self.assertFalse(self.wait_for_properties_changed(max_wait=500))
+        self.assertFalse(self.wait_for_properties_changed(max_wait=5))
         self.assertEqual(self.get_property('AccelerometerOrientation'),
                          'normal')
 
@@ -189,7 +178,7 @@ class TestIIOSensorsProxy(TestIIOSensorsProxyBase):
         self.set_internal_property('HasAmbientLight', True)
         self.assertTrue(self.get_property('HasAmbientLight'))
         self.set_internal_property('LightLevelUnit', 'vendor')
-        self.assertFalse(self.wait_for_properties_changed(max_wait=500))
+        self.assertFalse(self.wait_for_properties_changed(max_wait=5))
         self.assertEqual(self.get_property('LightLevelUnit'), 'vendor')
 
     def test_proximity_none(self):
@@ -230,7 +219,7 @@ class TestIIOSensorsProxy(TestIIOSensorsProxyBase):
         self.set_internal_property('HasProximity', True)
         self.assertTrue(self.get_property('HasProximity'))
         self.set_internal_property('ProximityNear', True)
-        self.assertFalse(self.wait_for_properties_changed(max_wait=500))
+        self.assertFalse(self.wait_for_properties_changed(max_wait=5))
         self.assertTrue(self.get_property('ProximityNear'))
 
 
@@ -277,7 +266,7 @@ class TestIIOSensorsProxyCompass(TestIIOSensorsProxyBase):
         self.set_internal_property('HasCompass', True)
         self.assertTrue(self.get_property('HasCompass'))
         self.set_internal_property('CompassHeading', 85)
-        self.assertFalse(self.wait_for_properties_changed(max_wait=500))
+        self.assertFalse(self.wait_for_properties_changed(max_wait=5))
         self.assertEqual(self.get_property('CompassHeading'), 85)

 

but it doesn't work:

# PYTHONPATH=. python3 tests/test_iio_sensors_proxy.py TestIIOSensorsProxy.test_accelerometer_unclaimed_properties_changes
test_accelerometer_unclaimed_properties_changes (__main__.TestIIOSensorsProxy) ... FAIL

======================================================================
FAIL: test_accelerometer_unclaimed_properties_changes (__main__.TestIIOSensorsProxy)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/source/tests/test_iio_sensors_proxy.py", line 132, in test_accelerometer_unclaimed_properties_changes
    self.assertFalse(self.wait_for_properties_changed(max_wait=5))
  File "/source/tests/test_iio_sensors_proxy.py", line 80, in wait_for_properties_changed
    self.assertEventually(lambda: changed_properties)
  File "/source/dbusmock/testcase.py", line 275, in assertEventually
    self.fail(message or 'timed out waiting for ' + str(condition))
AssertionError: timed out waiting for <function TestIIOSensorsProxyBase.wait_for_properties_changed.<locals>.<lambda> at 0x7f06099725f0>

It's also a wee bit weird, as this is adding GLib dependency/importing to the otherwise rather generic testcase.py (but dbusmock depends on GLib anyway, so I don't mind that much).

So this needs more debugging.

gnomesysadmins pushed a commit to GNOME/glib that referenced this issue Jan 27, 2022
assertEventually is a helper used in a number of projects that use
dbusmock.

See martinpitt/python-dbusmock#82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants