Merge lp:~rainct/zeitgeist/922620 into lp:~zeitgeist/zeitgeist/bluebird

Proposed by Siegfried Gevatter
Status: Merged
Merged at revision: 386
Proposed branch: lp:~rainct/zeitgeist/922620
Merge into: lp:~zeitgeist/zeitgeist/bluebird
Diff against target: 279 lines (+94/-28)
4 files modified
python/client.py (+33/-21)
test/dbus/blacklist-test.py (+18/-5)
test/dbus/monitor-test.py (+29/-0)
test/dbus/testutils.py (+14/-2)
To merge this branch: bzr merge lp:~rainct/zeitgeist/922620
Reviewer Review Type Date Requested Status
Zeitgeist Framework Team Pending
Review via email: mp+91920@code.launchpad.net
To post a comment you must log in.
lp:~rainct/zeitgeist/922620 updated
388. By Siegfried Gevatter

Add test case for monitor re-connection

389. By Siegfried Gevatter

Make bus initialization lazy so tests connect to the correct D-Bus instance

390. By Siegfried Gevatter

testutils.py: randomize DISPLAY so more than one test can run simultaneously

Revision history for this message
Seif Lotfy (seif) wrote :
Download full text (10.0 KiB)

Ok I had to learn this the hard way since you said it is just going to be
more...
Anyhow looks fine for me

On Tue, Feb 7, 2012 at 10:12 PM, Siegfried Gevatter <email address hidden>wrote:

> Siegfried Gevatter has proposed merging lp:~rainct/zeitgeist/922620 into
> lp:zeitgeist.
>
> Requested reviews:
> Zeitgeist Framework Team (zeitgeist)
> Related bugs:
> Bug #922620 in Zeitgeist Framework: "Fix failing test cases:
> testBlacklistSignals and testDataSourceSignals"
> https://bugs.launchpad.net/zeitgeist/+bug/922620
>
> For more details, see:
> https://code.launchpad.net/~rainct/zeitgeist/922620/+merge/91920
> --
> https://code.launchpad.net/~rainct/zeitgeist/922620/+merge/91920
> Your team Zeitgeist Framework Team is requested to review the proposed
> merge of lp:~rainct/zeitgeist/922620 into lp:zeitgeist.
>
> === modified file 'python/client.py'
> --- python/client.py 2011-10-29 13:31:12 +0000
> +++ python/client.py 2012-02-07 21:11:18 +0000
> @@ -40,6 +40,15 @@
>
> log = logging.getLogger("zeitgeist.client")
>
> +# This is here so testutils.py can override it with a private bus
> connection
> +global session_bus
> +session_bus = dbus.SessionBus()
> +def get_bus():
> + return session_bus
> +def _set_bus(bus):
> + global session_bus
> + session_bus = bus
> +
> class _DBusInterface(object):
> """Wrapper around dbus.Interface adding convenience methods."""
>
> @@ -47,7 +56,6 @@
> # that here because otherwise all instances would share their state.
> _disconnect_callbacks = None
> _reconnect_callbacks = None
> - _generic_callbacks = None
>
> @staticmethod
> def get_members(introspection_xml):
> @@ -69,8 +77,9 @@
> def reconnect(self):
> if not self._reconnect_when_needed:
> return
> - self.__proxy = dbus.SessionBus().get_object(
> - self.__iface.requested_bus_name,
> self.__object_path)
> + self.__proxy = get_bus().get_object(
> + self.__iface.requested_bus_name,
> self.__object_path,
> + follow_name_owner_changes=True)
> self.__iface = dbus.Interface(self.__proxy,
> self.__interface_name)
> self._load_introspection_data()
>
> @@ -131,8 +140,7 @@
> self.reconnect()
> if signal not in self.__signals:
> raise TypeError("Unknown signal name: %s" % signal)
> - self._generic_callbacks.add((signal, callback))
> - self.__proxy.connect_to_signal(
> + return self.__proxy.connect_to_signal(
> signal,
> callback,
> dbus_interface=self.__interface_name,
> @@ -169,7 +177,6 @@
>
> self._disconnect_callbacks = set()
> self._reconnect_callbacks = set()
> - self._generic_callbacks = set()
>
> # Listen to (dis)connection notifications, for connect_exit
> and connect_join
> def name_owner_changed(connection_name):
> @@ -181,15 +188,9 @@
> retu...

lp:~rainct/zeitgeist/922620 updated
391. By Siegfried Gevatter

Fix monitors being installed twice; python-dbus always gives us a name
owner changed notification, so we want to ignore this first one.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'python/client.py'
--- python/client.py 2011-10-29 13:31:12 +0000
+++ python/client.py 2012-02-07 22:51:18 +0000
@@ -40,6 +40,19 @@
4040
41log = logging.getLogger("zeitgeist.client")41log = logging.getLogger("zeitgeist.client")
4242
43# This is here so testutils.py can override it with a private bus connection.
44# Init needs to be lazy so tests will use the private D-Bus instance.
45global session_bus
46session_bus = None
47def get_bus():
48 global session_bus
49 if session_bus is None:
50 session_bus = dbus.SessionBus()
51 return session_bus
52def _set_bus(bus):
53 global session_bus
54 session_bus = bus
55
43class _DBusInterface(object):56class _DBusInterface(object):
44 """Wrapper around dbus.Interface adding convenience methods."""57 """Wrapper around dbus.Interface adding convenience methods."""
4558
@@ -47,7 +60,6 @@
47 # that here because otherwise all instances would share their state.60 # that here because otherwise all instances would share their state.
48 _disconnect_callbacks = None61 _disconnect_callbacks = None
49 _reconnect_callbacks = None62 _reconnect_callbacks = None
50 _generic_callbacks = None
5163
52 @staticmethod64 @staticmethod
53 def get_members(introspection_xml):65 def get_members(introspection_xml):
@@ -69,8 +81,9 @@
69 def reconnect(self):81 def reconnect(self):
70 if not self._reconnect_when_needed:82 if not self._reconnect_when_needed:
71 return83 return
72 self.__proxy = dbus.SessionBus().get_object(84 self.__proxy = get_bus().get_object(
73 self.__iface.requested_bus_name, self.__object_path)85 self.__iface.requested_bus_name, self.__object_path,
86 follow_name_owner_changes=True)
74 self.__iface = dbus.Interface(self.__proxy, self.__interface_name)87 self.__iface = dbus.Interface(self.__proxy, self.__interface_name)
75 self._load_introspection_data()88 self._load_introspection_data()
7689
@@ -131,8 +144,7 @@
131 self.reconnect()144 self.reconnect()
132 if signal not in self.__signals:145 if signal not in self.__signals:
133 raise TypeError("Unknown signal name: %s" % signal)146 raise TypeError("Unknown signal name: %s" % signal)
134 self._generic_callbacks.add((signal, callback))147 return self.__proxy.connect_to_signal(
135 self.__proxy.connect_to_signal(
136 signal,148 signal,
137 callback,149 callback,
138 dbus_interface=self.__interface_name,150 dbus_interface=self.__interface_name,
@@ -167,29 +179,28 @@
167 self._reconnect_when_needed = reconnect179 self._reconnect_when_needed = reconnect
168 self._load_introspection_data()180 self._load_introspection_data()
169 181
182 self._first_connection = True
170 self._disconnect_callbacks = set()183 self._disconnect_callbacks = set()
171 self._reconnect_callbacks = set()184 self._reconnect_callbacks = set()
172 self._generic_callbacks = set()
173 185
174 # Listen to (dis)connection notifications, for connect_exit and connect_join186 # Listen to (dis)connection notifications, for connect_exit and connect_join
175 def name_owner_changed(connection_name):187 def name_owner_changed(connection_name):
176 if connection_name == "":188 if connection_name == "":
177 callbacks = self._disconnect_callbacks
178 self.__methods = self.__signals = None189 self.__methods = self.__signals = None
190 for callback in self._disconnect_callbacks:
191 callback()
192 elif self._first_connection:
193 # python-dbus guarantees that it'll call NameOwnerChanged at startup
194 # (even if the service was already running). When that happens, we
195 # don't want to connect the signals a second time.
196 self._first_connection = False
179 else:197 else:
180 if not self._reconnect_when_needed:198 if not self._reconnect_when_needed:
181 return199 return
182 self.reconnect()200 self.reconnect()
183 callbacks = self._reconnect_callbacks201 for callback in self._reconnect_callbacks:
184 for signal, callback in self._generic_callbacks:202 callback()
185 try:203 get_bus().watch_name_owner(self.__iface.requested_bus_name,
186 self.connect(signal, callback)
187 except TypeError:
188 log.exception("Failed to reconnect to signal \"%s\" "
189 "after engine disconnection." % signal)
190 for callback in callbacks:
191 callback()
192 dbus.SessionBus().watch_name_owner(self.__iface.requested_bus_name,
193 name_owner_changed)204 name_owner_changed)
194205
195class ZeitgeistDBusInterface(object):206class ZeitgeistDBusInterface(object):
@@ -233,7 +244,8 @@
233 if not name in cls.__shared_state["extension_interfaces"]:244 if not name in cls.__shared_state["extension_interfaces"]:
234 interface_name = "org.gnome.zeitgeist.%s" % name245 interface_name = "org.gnome.zeitgeist.%s" % name
235 object_path = "/org/gnome/zeitgeist/%s" % path246 object_path = "/org/gnome/zeitgeist/%s" % path
236 proxy = dbus.SessionBus().get_object(busname, object_path)247 proxy = get_bus().get_object(busname, object_path,
248 follow_name_owner_changes=True)
237 iface = _DBusInterface(proxy, interface_name, object_path)249 iface = _DBusInterface(proxy, interface_name, object_path)
238 iface.BUS_NAME = busname250 iface.BUS_NAME = busname
239 iface.INTERFACE_NAME = interface_name251 iface.INTERFACE_NAME = interface_name
@@ -244,8 +256,8 @@
244 def __init__(self, reconnect=True):256 def __init__(self, reconnect=True):
245 if not "dbus_interface" in self.__shared_state:257 if not "dbus_interface" in self.__shared_state:
246 try:258 try:
247 proxy = dbus.SessionBus().get_object(self.BUS_NAME,259 proxy = get_bus().get_object(self.BUS_NAME,
248 self.OBJECT_PATH)260 self.OBJECT_PATH, follow_name_owner_changes=True)
249 except dbus.exceptions.DBusException, e:261 except dbus.exceptions.DBusException, e:
250 if e.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown":262 if e.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown":
251 raise RuntimeError(263 raise RuntimeError(
@@ -292,7 +304,7 @@
292 self._path = monitor_path304 self._path = monitor_path
293 self._insert_callback = insert_callback305 self._insert_callback = insert_callback
294 self._delete_callback = delete_callback306 self._delete_callback = delete_callback
295 dbus.service.Object.__init__(self, dbus.SessionBus(), monitor_path)307 dbus.service.Object.__init__(self, get_bus(), monitor_path)
296 308
297 def get_path (self): return self._path309 def get_path (self): return self._path
298 path = property(get_path,310 path = property(get_path,
299311
=== modified file 'test/dbus/blacklist-test.py'
--- test/dbus/blacklist-test.py 2011-09-07 20:48:27 +0000
+++ test/dbus/blacklist-test.py 2012-02-07 22:51:18 +0000
@@ -110,11 +110,13 @@
110 newAllTemplates = blacklist.GetTemplates()110 newAllTemplates = blacklist.GetTemplates()
111 self.assertEquals(len(newAllTemplates), 0)111 self.assertEquals(len(newAllTemplates), 0)
112112
113 def testBlacklistSignals(self):113 def testBlacklistSignals(self, mainloop=None, connect_signals=True):
114 self.blacklist = self._get_blacklist_iface()114 self.blacklist = self._get_blacklist_iface()
115 mainloop = self.create_mainloop()115 if mainloop is None:
116 mainloop = self.create_mainloop()
116117
117 template1 = Event.new_for_values(118 template1 = Event.new_for_values(
119 timestamp=0,
118 interpretation=Interpretation.ACCESS_EVENT,120 interpretation=Interpretation.ACCESS_EVENT,
119 subject_uri="http://nothingtoseehere.gov")121 subject_uri="http://nothingtoseehere.gov")
120122
@@ -124,7 +126,6 @@
124 @asyncTestMethod(mainloop)126 @asyncTestMethod(mainloop)
125 def cb_added(template_id, event_template):127 def cb_added(template_id, event_template):
126 global hit128 global hit
127 print "*** cb_added with hit", hit
128 self.assertEquals(hit, 0)129 self.assertEquals(hit, 0)
129 hit = 1130 hit = 1
130 self.assertEquals(template_id, "TestTemplate")131 self.assertEquals(template_id, "TestTemplate")
@@ -140,8 +141,9 @@
140 mainloop.quit()141 mainloop.quit()
141142
142 # Connect to signals143 # Connect to signals
143 self.blacklist.connect('TemplateAdded', cb_added)144 if connect_signals:
144 self.blacklist.connect('TemplateRemoved', cb_removed)145 self.blacklist.connect('TemplateAdded', cb_added)
146 self.blacklist.connect('TemplateRemoved', cb_removed)
145147
146 def launch_tests():148 def launch_tests():
147 self.blacklist.AddTemplate("TestTemplate", template1)149 self.blacklist.AddTemplate("TestTemplate", template1)
@@ -150,5 +152,16 @@
150152
151 mainloop.run()153 mainloop.run()
152154
155 def testBlacklistSignalWithReconnection(self):
156 mainloop = self.create_mainloop()
157 self.testBlacklistSignals(mainloop)
158
159 # Restart the Zeitgeist daemon...
160 self.kill_daemon()
161 self.spawn_daemon()
162
163 # ... and try again without re-connecting to the signals
164 self.testBlacklistSignals(mainloop, connect_signals=False)
165
153if __name__ == "__main__":166if __name__ == "__main__":
154 unittest.main()167 unittest.main()
155168
=== modified file 'test/dbus/monitor-test.py'
--- test/dbus/monitor-test.py 2011-09-07 20:48:27 +0000
+++ test/dbus/monitor-test.py 2012-02-07 22:51:18 +0000
@@ -286,5 +286,34 @@
286 self.assertEquals(1, len(result))286 self.assertEquals(1, len(result))
287 self.assertEquals(1, result.pop())287 self.assertEquals(1, result.pop())
288288
289 def testMonitorReconnection(self):
290 result = []
291 mainloop = self.create_mainloop()
292 events = parse_events("test/data/three_events.js")
293
294 @asyncTestMethod(mainloop)
295 def notify_insert_handler(time_range, events):
296 result.extend(events)
297 mainloop.quit()
298
299 @asyncTestMethod(mainloop)
300 def notify_delete_handler(time_range, event_ids):
301 mainloop.quit()
302 self.fail("Unexpected delete notification")
303
304 self.client.install_monitor(TimeRange.always(), [],
305 notify_insert_handler, notify_delete_handler)
306
307 # Restart the Zeitgeist daemon to test automagic monitor re-connection
308 self.kill_daemon()
309 self.spawn_daemon()
310
311 # Insert events in idle loop to give the reconnection logic enough time
312 gobject.idle_add(lambda *args: self.client.insert_events(events))
313
314 mainloop.run()
315
316 self.assertEquals(3, len(result))
317
289if __name__ == "__main__":318if __name__ == "__main__":
290 unittest.main()319 unittest.main()
291320
=== modified file 'test/dbus/testutils.py'
--- test/dbus/testutils.py 2012-02-07 17:49:49 +0000
+++ test/dbus/testutils.py 2012-02-07 22:51:18 +0000
@@ -21,12 +21,14 @@
21# along with this program. If not, see <http://www.gnu.org/licenses/>.21# along with this program. If not, see <http://www.gnu.org/licenses/>.
2222
23import unittest23import unittest
24import dbus
24import os25import os
25import time26import time
26import sys27import sys
27import signal28import signal
28import tempfile29import tempfile
29import shutil30import shutil
31import random
30from subprocess import Popen, PIPE32from subprocess import Popen, PIPE
3133
32# DBus setup34# DBus setup
@@ -36,7 +38,8 @@
3638
37# Import local Zeitgeist modules39# Import local Zeitgeist modules
38sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))40sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
39from zeitgeist.client import ZeitgeistDBusInterface, ZeitgeistClient41from zeitgeist.client import ZeitgeistDBusInterface, ZeitgeistClient, \
42 get_bus, _set_bus
40from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \43from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \
41 TimeRange, NULL_EVENT44 TimeRange, NULL_EVENT
4245
@@ -175,11 +178,18 @@
175 178
176 # hack to clear the state of the interface179 # hack to clear the state of the interface
177 ZeitgeistDBusInterface._ZeitgeistDBusInterface__shared_state = {}180 ZeitgeistDBusInterface._ZeitgeistDBusInterface__shared_state = {}
181
182 # Replace the bus connection with a private one for each test case,
183 # so that they don't share signals or other state
184 _set_bus(dbus.SessionBus(private=True))
185 get_bus().set_exit_on_disconnect(False)
186
178 self.client = ZeitgeistClient()187 self.client = ZeitgeistClient()
179 188
180 def tearDown(self):189 def tearDown(self):
181 assert self.daemon is not None190 assert self.daemon is not None
182 assert self.client is not None191 assert self.client is not None
192 get_bus().close()
183 self.kill_daemon()193 self.kill_daemon()
184 if 'ZEITGEIST_TESTS_KEEP_TMP' in os.environ:194 if 'ZEITGEIST_TESTS_KEEP_TMP' in os.environ:
185 print '\n\nAll temporary files have been preserved in %s\n' \195 print '\n\nAll temporary files have been preserved in %s\n' \
@@ -389,7 +399,9 @@
389 self.assertEqual(ev1, ev2)399 self.assertEqual(ev1, ev2)
390400
391class DBusPrivateMessageBus(object):401class DBusPrivateMessageBus(object):
392 DISPLAY = ":27"402 # Choose a random number so it's possible to have more than
403 # one test running at once.
404 DISPLAY = ":%d" % random.randint(20, 100)
393405
394 def _run(self):406 def _run(self):
395 os.environ.update({"DISPLAY": self.DISPLAY})407 os.environ.update({"DISPLAY": self.DISPLAY})

Subscribers

People subscribed via source and target branches