Merge lp:~facundo/magicicada-gui/fake-dbus into lp:magicicada-gui

Proposed by Facundo Batista
Status: Merged
Approved by: Natalia Bidart
Approved revision: 37
Merged at revision: 27
Proposed branch: lp:~facundo/magicicada-gui/fake-dbus
Merge into: lp:magicicada-gui
Diff against target: 2583 lines (+1509/-752)
6 files modified
magicicada/dbusiface.py (+288/-0)
magicicada/syncdaemon.py (+104/-233)
magicicada/tests/helpers.py (+49/-0)
magicicada/tests/test_dbusiface.py (+665/-0)
magicicada/tests/test_magicicada.py (+4/-3)
magicicada/tests/test_syncdaemon.py (+399/-516)
To merge this branch: bzr merge lp:~facundo/magicicada-gui/fake-dbus
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+26007@code.launchpad.net

Description of the change

DBus refactoring.

Now all the dbus details are handled in a separate module/class, with its tests.

SyncDaemon now is a lot more simpler.

Zillion of test cases added and refactored.

To post a comment you must log in.
lp:~facundo/magicicada-gui/fake-dbus updated
31. By Facundo Batista

Merged trunk in

32. By Facundo Batista

Changed where I log start

33. By Facundo Batista

Get initial data only when it should

34. By Facundo Batista

One more case

35. By Facundo Batista

Merged lp:~nataliabidart/magicicada/handle-items-none

36. By Facundo Batista

Initial callbacks

37. By Facundo Batista

Yes, we should put docstrings... but not twice!

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Very nice!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'magicicada/dbusiface.py'
2--- magicicada/dbusiface.py 1970-01-01 00:00:00 +0000
3+++ magicicada/dbusiface.py 2010-05-27 20:56:26 +0000
4@@ -0,0 +1,288 @@
5+# dbusiface.py
6+#
7+# Author: Facundo Batista <facundo@taniquetil.com.ar>
8+#
9+# Copyright 2010 Chicharreros
10+#
11+# This program is free software: you can redistribute it and/or modify it
12+# under the terms of the GNU General Public License version 3, as published
13+# by the Free Software Foundation.
14+#
15+# This program is distributed in the hope that it will be useful, but
16+# WITHOUT ANY WARRANTY; without even the implied warranties of
17+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
18+# PURPOSE. See the GNU General Public License for more details.
19+#
20+# You should have received a copy of the GNU General Public License along
21+# with this program. If not, see <http://www.gnu.org/licenses/>.
22+
23+"""The DBus Interface."""
24+
25+import collections
26+import logging
27+import re
28+import sys
29+
30+import dbus
31+from dbus import SessionBus
32+from dbus.mainloop.glib import DBusGMainLoop
33+
34+from ubuntuone.syncdaemon.tools import SyncDaemonTool
35+
36+# log!
37+logger = logging.getLogger('magicicada.dbusiface')
38+handler = logging.StreamHandler(sys.stdout)
39+logger.addHandler(handler)
40+formatter = logging.Formatter("%(asctime)s %(name)s:%(lineno)-4d "
41+ "%(levelname)-8s %(message)s",
42+ '%Y-%m-%d %H:%M:%S')
43+handler.setFormatter(formatter)
44+logger.setLevel(logging.DEBUG)
45+
46+
47+QueueData = collections.namedtuple('QueueData', 'operation path share node')
48+FolderData = collections.namedtuple('FolderData',
49+ 'node path suggested_path subscribed volume')
50+
51+# regular expressions for parsing MetaQueue data
52+RE_OP_LISTDIR = re.compile("(ListDir)\(share_id=(.*?), node_id=(.*?), .*")
53+RE_OP_UNLINK = re.compile("(Unlink)\(share_id=(.*?), node_id=(.*?), .*")
54+RE_OP_MAKEFILE = re.compile(
55+ "(MakeFile)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
56+RE_OP_MAKEDIR = re.compile(
57+ "(MakeDir)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
58+RE_OP_MOVE = re.compile(
59+ "(Move)\(share_id=(.*?), node_id=(.*?), old_parent_id=(.*?), "
60+ "new_parent_id=(.*?), new_name=(.*?)\)")
61+
62+
63+class DBusInterface(object):
64+ """The DBus Interface to Ubuntu One's SyncDaemon."""
65+
66+ def __init__(self, msd):
67+ # magicicada's syncdaemon
68+ self.msd = msd
69+ logger.info("DBus interface starting")
70+
71+ # set up dbus and related stuff
72+ loop = DBusGMainLoop(set_as_default=True)
73+ self._bus = bus = SessionBus(mainloop=loop)
74+ self.sync_daemon_tool = SyncDaemonTool(bus)
75+
76+ # hook up for signals and store info for the shutdown
77+ _signals = [
78+ (self._on_status_changed, 'Status', 'StatusChanged'),
79+ (self._on_content_queue_changed, 'Status', 'ContentQueueChanged'),
80+ (self._on_name_owner_changed, None, 'NameOwnerChanged'),
81+ (self._on_folder_created, 'Folders', 'FolderCreated'),
82+ (self._on_folder_deleted, 'Folders', 'FolderDeleted'),
83+ ]
84+ self._dbus_matches = []
85+ for method, dbus_lastname, signal_name in _signals:
86+ if dbus_lastname is None:
87+ dbus_interface = None
88+ else:
89+ dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname
90+ match = bus.add_signal_receiver(method,
91+ dbus_interface=dbus_interface,
92+ signal_name=signal_name)
93+ self._dbus_matches.append((match, dbus_interface, signal_name))
94+
95+
96+ def shutdown(self):
97+ """Shut down the SyncDaemon."""
98+ logger.info("DBus interface going down")
99+
100+ # remove the signals from DBus
101+ remove = self._bus.remove_signal_receiver
102+ for match, dbus_interface, signal in self._dbus_matches:
103+ remove(match, dbus_interface=dbus_interface, signal_name=signal)
104+
105+ def _process_status(self, state):
106+ """Transform status information."""
107+ name = state['name']
108+ description = state['description']
109+ is_error = bool(state['is_error'])
110+ is_connected = bool(state['is_connected'])
111+ is_online = bool(state['is_online'])
112+ queues = state['queues']
113+ connection = state['connection']
114+ return (name, description, is_error, is_connected,
115+ is_online, queues, connection)
116+
117+ def get_status(self):
118+ """Gets SD status."""
119+ logger.info("Getting status")
120+ d = self.sync_daemon_tool.get_status()
121+ d.addCallback(self._process_status)
122+ return d
123+
124+ def _on_status_changed(self, state):
125+ """Call the SD callback."""
126+ logger.info("Received Status changed")
127+ logger.debug("Status changed data: %r", state)
128+ data = self._process_status(state)
129+ self.msd.on_sd_status_changed(*data)
130+
131+ def _on_content_queue_changed(self, _):
132+ """Call the SD callback."""
133+ logger.info("Received Content Queue changed")
134+ self.msd.on_sd_content_queue_changed()
135+
136+ def _on_name_owner_changed(self, name, oldowner, newowner):
137+ """Receive the NameOwnerChanged signal from DBus."""
138+ if name != 'com.ubuntuone.SyncDaemon':
139+ return
140+
141+ logger.info("Received Name Owner changed")
142+ logger.debug("Name Owner data: %r %r", oldowner, newowner)
143+ old = bool(oldowner)
144+ new = bool(newowner)
145+ if old == new:
146+ logger.error("Name Owner invalid data: Same bool in old and new!")
147+ return
148+ self.msd.on_sd_name_owner_changed(new)
149+
150+ def _on_folder_created(self, _):
151+ """Call the SD callback."""
152+ logger.info("Received Folder created")
153+ self.msd.on_sd_folders_changed()
154+
155+ def _on_folder_deleted(self, _):
156+ """Call the SD callback."""
157+ logger.info("Received Folder deleted")
158+ self.msd.on_sd_folders_changed()
159+
160+ def get_content_queue(self):
161+ """Get the content queue from SDT."""
162+ def process(data):
163+ """Enhance data format."""
164+ logger.info("Processing Content Queue items (%d)", len(data))
165+ all_items = []
166+ for d in data:
167+ logger.debug(" Content Queue data: %r", d)
168+ cq = QueueData(operation=d['operation'], path=d['path'],
169+ node=d['node'], share=d['share'])
170+ all_items.append(cq)
171+ return all_items
172+
173+ logger.info("Getting content queue")
174+ d = self.sync_daemon_tool.waiting_content()
175+ d.addCallback(process)
176+ return d
177+
178+ def _parse_mq(self, data):
179+ """Parse MetaQueue string to extract its data."""
180+ if data in ('AccountInquiry', 'FreeSpaceInquiry', 'GetPublicFiles',
181+ 'ListShares', 'ListVolumes', 'Query'):
182+ return QueueData(operation=data, path=None, node=None, share=None)
183+
184+ m = RE_OP_LISTDIR.match(data)
185+ if m:
186+ op, share, node = m.groups()
187+ path = '?' # we should get the real path, no API now
188+ return QueueData(operation=op, path=path, node=node, share=share)
189+
190+ m = RE_OP_MAKEFILE.match(data)
191+ if m:
192+ op, share, parent, name = m.groups()
193+ path = '/?.../' + name # we should get the real path, no API now
194+ return QueueData(operation=op, path=path, node=None, share=share)
195+
196+ m = RE_OP_MAKEDIR.match(data)
197+ if m:
198+ op, share, parent, name = m.groups()
199+ path = '/?.../' + name # we should get the real path, no API now
200+ return QueueData(operation=op, path=path, node=None, share=share)
201+
202+ m = RE_OP_UNLINK.match(data)
203+ if m:
204+ op, share, node, = m.groups()
205+ path = '?' # we should get the real path, no API now
206+ return QueueData(operation=op, path=path, node=node, share=share)
207+
208+ m = RE_OP_MOVE.match(data)
209+ if m:
210+ op, share, node, old_parent, new_parent, new_name, = m.groups()
211+
212+ # we should get the real info, no API now
213+ old_path = '/?...'
214+ old_name = '?'
215+ new_path = '/?...'
216+ composed_path = "%s/%s -> %s/%s" % (old_path, old_name,
217+ new_path, new_name)
218+ return QueueData(operation=op, path=composed_path,
219+ node=node, share=share)
220+
221+ raise ValueError("Not supported MetaQueue data: %r" % data)
222+
223+ def get_meta_queue(self):
224+ """Get the meta queue from SDT."""
225+ def process(data):
226+ """Enhance data format."""
227+ logger.info("Processing Meta Queue items (%d)", len(data))
228+ all_items = []
229+ for d in data:
230+ logger.debug(" Meta Queue data: %r", d)
231+ parsed = self._parse_mq(d)
232+ all_items.append(parsed)
233+ return all_items
234+
235+ logger.info("Getting meta queue")
236+ d = self.sync_daemon_tool.waiting_metadata()
237+ d.addCallback(process)
238+ return d
239+
240+ def get_folders(self):
241+ """Get the folders info from SDT."""
242+ def process(data):
243+ """Enhance data format."""
244+ logger.info("Processing Folders items (%d)", len(data))
245+ all_items = []
246+ for d in data:
247+ logger.debug(" Folders data: %r", d)
248+ f = FolderData(node=d['node_id'], path=d['path'],
249+ suggested_path=d['suggested_path'],
250+ volume=d['volume_id'],
251+ subscribed=bool(d['subscribed']))
252+ all_items.append(f)
253+ return all_items
254+
255+ logger.info("Getting folders")
256+ d = self.sync_daemon_tool.get_folders()
257+ d.addCallback(process)
258+ return d
259+
260+ def start(self):
261+ """Start SDT."""
262+ logger.info("Calling start")
263+ self.sync_daemon_tool.start()
264+
265+ def quit(self):
266+ """Stop SDT."""
267+ logger.info("Calling quit")
268+ self.sync_daemon_tool.quit()
269+
270+ def connect(self):
271+ """Connect SDT."""
272+ logger.info("Calling connect")
273+ self.sync_daemon_tool.connect()
274+
275+ def disconnect(self):
276+ """Disconnect SDT."""
277+ logger.info("Calling disconnect")
278+ self.sync_daemon_tool.disconnect()
279+
280+ def is_sd_started(self):
281+ """Find out if SD is active in the system."""
282+ try:
283+ self._bus.get_name_owner('com.ubuntuone.SyncDaemon')
284+ except dbus.exceptions.DBusException, err:
285+ if err.get_dbus_name() != \
286+ 'org.freedesktop.DBus.Error.NameHasNoOwner':
287+ raise
288+ started = False
289+ else:
290+ started = True
291+ logger.info("Checking if SD is started: %s", started)
292+ return started
293
294=== modified file 'magicicada/syncdaemon.py'
295--- magicicada/syncdaemon.py 2010-05-23 10:23:35 +0000
296+++ magicicada/syncdaemon.py 2010-05-27 20:56:26 +0000
297@@ -18,17 +18,12 @@
298
299 """The backend that communicates Magicicada with the SyncDaemon."""
300
301-import collections
302 import logging
303-import re
304 import sys
305
306-import dbus
307-from dbus.mainloop.glib import DBusGMainLoop
308-from twisted.internet import reactor
309-
310-from ubuntuone.syncdaemon import tools
311-
312+from twisted.internet import defer, reactor
313+
314+from magicicada.dbusiface import DBusInterface
315 from magicicada.helpers import NO_OP
316
317 # log!
318@@ -41,19 +36,6 @@
319 handler.setFormatter(formatter)
320 logger.setLevel(logging.DEBUG)
321
322-# regular expressions for parsing MetaQueue data
323-RE_OP_LISTDIR = re.compile("(ListDir)\(share_id=(.*?), node_id=(.*?), .*")
324-RE_OP_UNLINK = re.compile("(Unlink)\(share_id=(.*?), node_id=(.*?), .*")
325-RE_OP_MAKEFILE = re.compile(
326- "(MakeFile)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
327-RE_OP_MAKEDIR = re.compile(
328- "(MakeDir)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
329-RE_OP_MOVE = re.compile(
330- "(Move)\(share_id=(.*?), node_id=(.*?), old_parent_id=(.*?), "
331- "new_parent_id=(.*?), new_name=(.*?)\)")
332-
333-# structure that hold content and queue information
334-QueueData = collections.namedtuple('QueueData', 'operation path share node')
335
336 class State(object):
337 """Holds the state of SD."""
338@@ -96,29 +78,17 @@
339 class SyncDaemon(object):
340 """Interface to Ubuntu One's SyncDaemon."""
341
342- def __init__(self):
343+ def __init__(self, dbus_class=DBusInterface):
344+ logger.info("SyncDaemon interface started!")
345+
346 # set up dbus and related stuff
347- loop = DBusGMainLoop(set_as_default=True)
348- self._bus = bus = dbus.SessionBus(mainloop=loop)
349- self.sync_daemon_tool = tools.SyncDaemonTool(bus)
350+ self.dbus = dbus_class(self)
351+
352+ # attributes for GUI, definition and filling
353 self.current_state = State()
354-
355- # hook up for signals and store info for the shutdown
356- _signals = [
357- (self._on_status_changed, 'Status', 'StatusChanged'),
358- (self._on_content_queue_changed, 'Status', 'ContentQueueChanged'),
359- (self._on_name_owner_changed, None, 'NameOwnerChanged'),
360- ]
361- self._dbus_matches = []
362- for method, dbus_lastname, signal_name in _signals:
363- if dbus_lastname is None:
364- dbus_interface = None
365- else:
366- dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname
367- match = bus.add_signal_receiver(method,
368- dbus_interface=dbus_interface,
369- signal_name=signal_name)
370- self._dbus_matches.append((match, dbus_interface, signal_name))
371+ self.folders = None
372+ self.content_queue = None
373+ self.meta_queue = None
374
375 # callbacks for GUI to hook in
376 self.status_changed_callback = NO_OP
377@@ -131,70 +101,69 @@
378 self.on_online_callback = NO_OP
379 self.on_offline_callback = NO_OP
380
381- # calls to obtain data from SDT
382- self._get_content_queue = self.sync_daemon_tool.waiting_content
383- self._get_meta_queue = self.sync_daemon_tool.waiting_metadata
384- self._do_start = self.sync_daemon_tool.start
385- self._do_quit = self.sync_daemon_tool.quit
386- self._do_connect = self.sync_daemon_tool.connect
387- self._do_disconnect = self.sync_daemon_tool.disconnect
388-
389- # previous data
390- self._last_CQ_data = None
391- self._last_MQ_data = None
392-
393 # mq needs to be polled to know progress
394 self._mqcaller = None
395 self._mq_poll_time = 5 # seconds
396
397- # let's log!
398- logger.info("SyncDaemon interface started!")
399+ # load initial data if ubuntuone-client already started
400+ if self.dbus.is_sd_started():
401+ self._get_initial_data()
402
403
404 def shutdown(self):
405 """Shut down the SyncDaemon."""
406 logger.info("SyncDaemon interface going down")
407-
408- # remove the signals from DBus
409- remove = self._bus.remove_signal_receiver
410- for match, dbus_interface, signal in self._dbus_matches:
411- remove(match, dbus_interface=dbus_interface, signal_name=signal)
412+ self.dbus.shutdown()
413
414 # cancel the mq polling caller, if any
415 if self._mqcaller is not None and self._mqcaller.active():
416 self._mqcaller.cancel()
417
418- def _on_name_owner_changed(self, name, oldowner, newowner):
419- """Receives the NameOwnerChanged signal from DBus."""
420- if name == 'com.ubuntuone.SyncDaemon':
421- logger.info("DBus informing about SD: old: %r new: %r",
422- oldowner, newowner)
423-
424- old = bool(oldowner)
425- new = bool(newowner)
426- if old == new:
427- raise ValueError("Owners should have changed! Old: %r "
428- "New: %r" % (oldowner, newowner))
429- self.current_state._set(is_started=new)
430- if new:
431- self.on_started_callback()
432- else:
433- self.on_stopped_callback()
434-
435- def _on_status_changed(self, state):
436- """Receives the StatusChanged signal and send its data."""
437- logger.info("New status info from SD")
438- logger.debug("New status from SD: %r", state)
439-
440- name = state['name']
441- description = state['description']
442- is_error = bool(state['is_error'])
443- is_connected = bool(state['is_connected'])
444- is_online = bool(state['is_online'])
445- queues = state['queues']
446- connection = state['connection']
447-
448- # check status changes to call callbacks
449+ @defer.inlineCallbacks
450+ def _get_initial_data(self):
451+ """Gets the initial SD data."""
452+ logger.info("Getting initial data")
453+
454+ status_data = yield self.dbus.get_status()
455+ self._send_status_changed(*status_data)
456+
457+ self.content_queue = yield self.dbus.get_content_queue()
458+ self.content_queue_changed_callback(self.content_queue)
459+
460+ self.meta_queue = yield self.dbus.get_meta_queue()
461+ self.meta_queue_changed_callback(self.meta_queue)
462+
463+ self.folders = yield self.dbus.get_folders()
464+
465+ @defer.inlineCallbacks
466+ def on_sd_folders_changed(self):
467+ """Folders changed, ask for new information."""
468+ logger.info("SD Folders changed")
469+ self.folders = yield self.dbus.get_folders()
470+
471+ def on_sd_name_owner_changed(self, now_active):
472+ """SyncDaemon name owner changed."""
473+ logger.info("SD Name Owner changed: %s", now_active)
474+ self.current_state._set(is_started=now_active)
475+ if now_active:
476+ self.on_started_callback()
477+ self._get_initial_data()
478+ else:
479+ self.on_stopped_callback()
480+
481+ def on_sd_status_changed(self, *status_data):
482+ """The Status of SD changed.."""
483+ logger.info("SD Status changed")
484+ self._send_status_changed(*status_data)
485+
486+ def _send_status_changed(self, name, description, is_error, is_connected,
487+ is_online, queues, connection):
488+ logger.debug(" new status: name=%r, description=%r, is_error=%s, "
489+ "is_connected=%s, is_online=%s, queues=%r, connection=%r",
490+ name, description, is_error, is_connected, is_online,
491+ queues, connection)
492+
493+ # check status changes to call other callbacks
494 if is_connected and not self.current_state.is_connected:
495 self.on_connected_callback()
496 if not is_connected and self.current_state.is_connected:
497@@ -204,168 +173,70 @@
498 if not is_online and self.current_state.is_online:
499 self.on_offline_callback()
500
501-
502 # set current state to new values and call status changed cb
503- self.current_state._set(**state)
504- self.status_changed_callback(name, description, is_error,
505- is_connected, is_online,
506- queues, connection)
507+ self.current_state._set(name=name, description=description,
508+ is_error=is_error, is_connected=is_connected,
509+ is_online=is_online, queues=queues,
510+ connection=connection)
511+ self.status_changed_callback(name, description, is_error, is_connected,
512+ is_online, queues, connection)
513
514 # if corresponds, supervise MQ
515 self._check_mq()
516
517- def _generate_cq_info(self, data):
518- """Genereates an api friendly version of the data."""
519- all_items = []
520- for d in data:
521- logger.debug("Processing CQ data: %r", d)
522- cq = QueueData(operation=d['operation'], path=d['path'],
523- node=d['node'], share=d['share'])
524- all_items.append(cq)
525- return all_items
526-
527- @property
528- def content_queue(self):
529- """Returns the last known CQ info."""
530- if self._last_CQ_data is None:
531- return []
532- else:
533- return self._generate_cq_info(self._last_CQ_data)
534-
535- def _process_cq(self, data):
536- """Processes ContentQueue data."""
537- # if same data than before, abort notification; else store it for later
538- logger.info("Processing CQ data")
539- if data == self._last_CQ_data:
540- return
541- self._last_CQ_data = data
542- logger.info("New CQ data to process")
543-
544- all_items = self._generate_cq_info(data)
545- self.content_queue_changed_callback(all_items)
546-
547- def _on_content_queue_changed(self, _):
548- """Receives the ContentQueueChanged signal and finds real data."""
549- logger.info("CQ changed in u1.SD!")
550-
551- # get the info
552- d = self._get_content_queue()
553- d.addCallback(self._process_cq)
554-
555- @property
556- def meta_queue(self):
557- """Returns the last known MQ info."""
558- if self._last_MQ_data is None:
559- return []
560- else:
561- all_items = []
562- for d in self._last_MQ_data:
563- all_items.append(self._parse_mq(d))
564- return all_items
565-
566- def _parse_mq(self, data):
567- """Parse MetaQueue string to extract its data."""
568- if data in ('AccountInquiry', 'FreeSpaceInquiry', 'GetPublicFiles',
569- 'ListShares', 'ListVolumes', 'Query'):
570- return QueueData(operation=data, path=None, node=None, share=None)
571-
572- m = RE_OP_LISTDIR.match(data)
573- if m:
574- op, share, node = m.groups()
575- path = '?' # we should get the real path, no API now
576- return QueueData(operation=op, path=path, node=node, share=share)
577-
578- m = RE_OP_MAKEFILE.match(data)
579- if m:
580- op, share, parent, name = m.groups()
581- path = '/?.../' + name # we should get the real path, no API now
582- return QueueData(operation=op, path=path, node=None, share=share)
583-
584- m = RE_OP_MAKEDIR.match(data)
585- if m:
586- op, share, parent, name = m.groups()
587- path = '/?.../' + name # we should get the real path, no API now
588- return QueueData(operation=op, path=path, node=None, share=share)
589-
590- m = RE_OP_UNLINK.match(data)
591- if m:
592- op, share, node, = m.groups()
593- path = '?' # we should get the real path, no API now
594- return QueueData(operation=op, path=path, node=node, share=share)
595-
596- m = RE_OP_MOVE.match(data)
597- if m:
598- op, share, node, old_parent, new_parent, new_name, = m.groups()
599-
600- # we should get the real info, no API now
601- old_path = '/?...'
602- old_name = '?'
603- new_path = '/?...'
604- composed_path = "%s/%s -> %s/%s" % (old_path, old_name,
605- new_path, new_name)
606- return QueueData(operation=op, path=composed_path,
607- node=node, share=share)
608-
609- raise ValueError("Not supported MetaQueue data: %r" % data)
610-
611- def _process_mq(self, data):
612- """Processes MetaQueue data."""
613- # if same data than before, abort notification; else store it for later
614- logger.info("Processing MQ data")
615- if data == self._last_MQ_data:
616- return
617- self._last_MQ_data = data
618- logger.info("New MQ data to process")
619-
620- all_items = []
621- for d in data:
622- logger.debug("Processing MQ data: %r", d)
623- parsed = self._parse_mq(d)
624- logger.debug(" parsed: %s", parsed)
625- all_items.append(parsed)
626-
627- self.meta_queue_changed_callback(all_items)
628-
629- def _on_meta_queue_changed(self):
630- """Finds real data about meta queue."""
631- d = self._get_meta_queue()
632- d.addCallback(self._process_mq)
633-
634+ @defer.inlineCallbacks
635+ def on_sd_content_queue_changed(self):
636+ """Content Queue changed, ask for new information."""
637+ logger.info("SD Content Queue changed")
638+ new_cq = yield self.dbus.get_content_queue()
639+ if new_cq != self.content_queue:
640+ logger.info("Content Queue info is new! %d items", len(new_cq))
641+ self.content_queue = new_cq
642+ self.content_queue_changed_callback(new_cq)
643+
644+ @defer.inlineCallbacks
645 def _check_mq(self):
646 """Check MQ if we should."""
647- # check if we have something to show in MQ!
648- if self.current_state.name != 'QUEUE_MANAGER' or \
649- self.current_state.queues not in (
650- 'WORKING_ON_METADATA', 'WORKING_ON_BOTH'):
651+ state = self.current_state
652+ if state.name != 'QUEUE_MANAGER' or \
653+ state.queues not in ('WORKING_ON_METADATA', 'WORKING_ON_BOTH'):
654 logger.info("Check MQ called but States not in MQ")
655- return
656-
657- # we have a previous call later running?
658- if self._mqcaller is not None and self._mqcaller.active():
659- self._mqcaller.cancel()
660-
661- # get the info a programa
662- logger.info("Asking for MQ information")
663- d = self._get_meta_queue()
664- d.addCallback(self._process_mq)
665- self._mqcaller = reactor.callLater(self._mq_poll_time, self._check_mq)
666+ else:
667+ logger.info("Asking for MQ information")
668+
669+ # have we a previous call later still running?
670+ if self._mqcaller is not None and self._mqcaller.active():
671+ self._mqcaller.cancel()
672+
673+ # get the info
674+ new_mq = yield self.dbus.get_meta_queue()
675+
676+ if new_mq != self.meta_queue:
677+ logger.info("SD Meta Queue changed: %d items", len(new_mq))
678+ self.meta_queue = new_mq
679+ self.meta_queue_changed_callback(new_mq)
680+
681+ # check again later
682+ self._mqcaller = reactor.callLater(self._mq_poll_time,
683+ self._check_mq)
684
685 def start(self):
686 """Starts the SyncDaemon."""
687 logger.info("Starting u1.SD")
688- self._do_start()
689+ self.dbus.start()
690+ self._get_initial_data()
691
692 def quit(self):
693 """Stops the SyncDaemon and makes it quit."""
694 logger.info("Stopping u1.SD")
695- self._do_quit()
696+ self.dbus.quit()
697
698 def connect(self):
699 """Tells the SyncDaemon that the user wants it to connect."""
700 logger.info("Telling u1.SD to connect")
701- self._do_connect()
702+ self.dbus.connect()
703
704 def disconnect(self):
705 """Tells the SyncDaemon that the user wants it to disconnect."""
706 logger.info("Telling u1.SD to disconnect")
707- self._do_disconnect()
708+ self.dbus.disconnect()
709
710=== added file 'magicicada/tests/helpers.py'
711--- magicicada/tests/helpers.py 1970-01-01 00:00:00 +0000
712+++ magicicada/tests/helpers.py 2010-05-27 20:56:26 +0000
713@@ -0,0 +1,49 @@
714+# Helpers for the tessts
715+#
716+# Author: Facundo Batista <facundo@taniquetil.com.ar>
717+#
718+# Copyright 2010 Chicharreros
719+#
720+# This program is free software: you can redistribute it and/or modify it
721+# under the terms of the GNU General Public License version 3, as published
722+# by the Free Software Foundation.
723+#
724+# This program is distributed in the hope that it will be useful, but
725+# WITHOUT ANY WARRANTY; without even the implied warranties of
726+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
727+# PURPOSE. See the GNU General Public License for more details.
728+#
729+# You should have received a copy of the GNU General Public License along
730+# with this program. If not, see <http://www.gnu.org/licenses/>.
731+
732+"""Helpers for the tests."""
733+
734+import logging
735+
736+
737+class MementoHandler(logging.Handler):
738+ """A handler class which store logging records in a list."""
739+
740+ def __init__(self, *args, **kwargs):
741+ """Create the instance, and add a records attribute."""
742+ logging.Handler.__init__(self, *args, **kwargs)
743+ self.records = []
744+
745+ def emit(self, record):
746+ """Just add the record to self.records."""
747+ self.records.append(record)
748+
749+ def check(self, level, msg):
750+ """Check that something is logged."""
751+ for rec in self.records:
752+ if rec.levelname == level and rec.message == msg:
753+ return True
754+ return False
755+
756+ def check_inf(self, msg):
757+ """Shortcut for INFO check."""
758+ return self.check('INFO', msg)
759+
760+ def check_dbg(self, msg):
761+ """Shortcut for DEBUG check."""
762+ return self.check('DEBUG', msg)
763
764=== added file 'magicicada/tests/test_dbusiface.py'
765--- magicicada/tests/test_dbusiface.py 1970-01-01 00:00:00 +0000
766+++ magicicada/tests/test_dbusiface.py 2010-05-27 20:56:26 +0000
767@@ -0,0 +1,665 @@
768+# Tests for the DBus interface
769+#
770+# Author: Facundo Batista <facundo@taniquetil.com.ar>
771+#
772+# Copyright 2010 Chicharreros
773+#
774+# This program is free software: you can redistribute it and/or modify it
775+# under the terms of the GNU General Public License version 3, as published
776+# by the Free Software Foundation.
777+#
778+# This program is distributed in the hope that it will be useful, but
779+# WITHOUT ANY WARRANTY; without even the implied warranties of
780+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
781+# PURPOSE. See the GNU General Public License for more details.
782+#
783+# You should have received a copy of the GNU General Public License along
784+# with this program. If not, see <http://www.gnu.org/licenses/>.
785+
786+"""Tests for the DBus interce towards real syncdaemon."""
787+
788+import logging
789+
790+import dbus
791+from twisted.trial.unittest import TestCase as TwistedTestCase
792+from twisted.internet import defer
793+
794+from magicicada import dbusiface
795+from magicicada.tests.helpers import MementoHandler
796+
797+
798+class FakeSessionBus(object):
799+ """Fake Session Bus."""
800+ def __init__(self, **kwargs):
801+ self._callbacks = {}
802+ self.fake_name_owner = "foo"
803+
804+ def add_signal_receiver(self, method, dbus_interface, signal_name):
805+ """Add a signal receiver."""
806+ self._callbacks[(dbus_interface, signal_name)] = method
807+
808+ def remove_signal_receiver(self, match, dbus_interface, signal_name):
809+ """Remove the signal receiver."""
810+ del self._callbacks[(dbus_interface, signal_name)]
811+
812+ def get_name_owner(self, name):
813+ """Fakes the response of the method."""
814+ assert name == 'com.ubuntuone.SyncDaemon'
815+ if isinstance(self.fake_name_owner, str):
816+ return self.fake_name_owner
817+ else:
818+ raise self.fake_name_owner
819+
820+
821+class CallLoguer(object):
822+ """Class that logs the methods called."""
823+ def __init__(self):
824+ self._called_method = None, ()
825+ self._fake_response = None
826+
827+ def __getattribute__(self, name):
828+ """Return the value if there."""
829+ if name[0] == "_":
830+ return object.__getattribute__(self, name)
831+ else:
832+ def f(*args):
833+ setattr(self, "_called_method", (name, args))
834+ if self._fake_response is None:
835+ # no hurt in returning a deferred, it may be needed
836+ return defer.Deferred()
837+ methname, response = self._fake_response
838+ assert methname == name
839+ return response
840+ return f
841+
842+
843+class FakeSDTool(CallLoguer):
844+ """Fake real SyncDaemonTool."""
845+ def __init__(self, _):
846+ CallLoguer.__init__(self)
847+
848+
849+class FakeSyncDaemon(CallLoguer):
850+ """Fake Magicicada's SyncDaemon."""
851+
852+
853+class SafeTests(TwistedTestCase):
854+ """Safe tests not going outside the testing box."""
855+
856+ def setUp(self):
857+ """Set up."""
858+ dbusiface.SessionBus = FakeSessionBus
859+ dbusiface.SyncDaemonTool = FakeSDTool
860+ self.fsd = FakeSyncDaemon()
861+ self.dbus = dbusiface.DBusInterface(self.fsd)
862+
863+ def check_sdt_called(self, name):
864+ """Check that the SyncDaemonTool method was called."""
865+ self.assertEqual(self.dbus.sync_daemon_tool._called_method[0], name)
866+
867+ def get_msd_called(self, name):
868+ """Get the args from the called Magicicada's SyncDaemon method."""
869+ called_method, called_args = self.fsd._called_method
870+ self.assertEqual(called_method, name)
871+ return called_args
872+
873+ def fake_sdt_response(self, method_name, response):
874+ """Fakes SDT answer in deferred mode."""
875+ self.dbus.sync_daemon_tool._fake_response = (method_name,
876+ defer.succeed(response))
877+
878+class TestSignalHooking(SafeTests):
879+ """Signal hooking tests.
880+
881+ We can not check if the methods are really called, because DBus holds the
882+ method object itself, so no chance in monkeypatching.
883+ """
884+ def _get_hooked(self, iface, signal):
885+ """Return the hooked method if any."""
886+ if iface is None:
887+ interface = None
888+ else:
889+ interface = 'com.ubuntuone.SyncDaemon.' + iface
890+ return self.dbus._bus._callbacks.get((interface, signal))
891+
892+ def test_hook_unhook(self):
893+ """Test the hooked signals are unhooked."""
894+ self.dbus.shutdown()
895+ self.assertEqual(self.dbus._bus._callbacks, {})
896+
897+ def test_status_changed(self):
898+ """Test status changed callback."""
899+ self.assertEqual(self._get_hooked('Status', 'StatusChanged'),
900+ self.dbus._on_status_changed)
901+
902+ def test_content_queue_changed(self):
903+ """Test content queue changed callback."""
904+ self.assertEqual(self._get_hooked('Status', 'ContentQueueChanged'),
905+ self.dbus._on_content_queue_changed)
906+
907+ def test_name_owner_changed(self):
908+ """Test name owner changed callback."""
909+ self.assertEqual(self._get_hooked(None, 'NameOwnerChanged'),
910+ self.dbus._on_name_owner_changed)
911+
912+ def test_folder_created_changed(self):
913+ """Test folder created changed callback."""
914+ self.assertEqual(self._get_hooked('Folders', 'FolderCreated'),
915+ self.dbus._on_folder_created)
916+
917+ def test_folder_deleted_changed(self):
918+ """Test folder deleted changed callback."""
919+ self.assertEqual(self._get_hooked('Folders', 'FolderDeleted'),
920+ self.dbus._on_folder_deleted)
921+
922+
923+class TestSimpleCalls(SafeTests):
924+ """Tests for some simple calls."""
925+
926+ @defer.inlineCallbacks
927+ def test_is_sd_started_yes(self):
928+ """Test is SD started, yes."""
929+ self.dbus._bus.fake_name_owner = 'some owner'
930+ resp = yield self.dbus.is_sd_started()
931+ self.assertTrue(resp)
932+
933+ @defer.inlineCallbacks
934+ def test_is_sd_started_no(self):
935+ """Test is SD started, no."""
936+ self.dbus._bus.fake_name_owner = dbus.exceptions.DBusException(
937+ name='org.freedesktop.DBus.Error.NameHasNoOwner')
938+ resp = yield self.dbus.is_sd_started()
939+ self.assertFalse(resp)
940+
941+
942+class TestDataProcessingStatus(SafeTests):
943+ """Processes Status before sending it to SyncDaemon."""
944+
945+ @defer.inlineCallbacks
946+ def test_get_status(self):
947+ """Test getting status."""
948+ d = dict(name='n', description='d', is_error='', is_connected='True',
949+ is_online='', queues='q', connection='c')
950+ self.fake_sdt_response('get_status', d)
951+ args = yield self.dbus.get_status()
952+ name, descrip, error, connected, online, queues, connection = args
953+ self.assertEqual(name, 'n')
954+ self.assertEqual(descrip, 'd')
955+ self.assertEqual(error, False)
956+ self.assertEqual(connected, True)
957+ self.assertEqual(online, False)
958+ self.assertEqual(queues, 'q')
959+ self.assertEqual(connection, 'c')
960+
961+ def test_status_changed(self):
962+ """Test status changed callback."""
963+ d = dict(name='name', description='description', is_error='',
964+ is_connected='True', is_online='', queues='queues',
965+ connection='connection')
966+ self.dbus._on_status_changed(d)
967+ args = self.get_msd_called("on_sd_status_changed")
968+ name, descrip, error, connected, online, queues, connection = args
969+ self.assertEqual(name, 'name')
970+ self.assertEqual(descrip, 'description')
971+ self.assertEqual(error, False)
972+ self.assertEqual(connected, True)
973+ self.assertEqual(online, False)
974+ self.assertEqual(queues, 'queues')
975+ self.assertEqual(connection, 'connection')
976+
977+
978+class TestDataProcessingNameOwner(SafeTests):
979+ """Processes Name Owner data before sending it to SyncDaemon."""
980+
981+ def test_name_owner_changed_no_syncdaemon(self):
982+ """Test name owner changed callback."""
983+ self.dbus._on_name_owner_changed("foo", "bar", "baz")
984+ self.get_msd_called(None)
985+
986+ def test_name_owner_changed_yes_syncdaemon_TF(self):
987+ """Test name owner changed callback."""
988+ self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "T", "")
989+ rcv, = self.get_msd_called("on_sd_name_owner_changed")
990+ self.assertEqual(rcv, False)
991+
992+ def test_name_owner_changed_yes_syncdaemon_FT(self):
993+ """Test name owner changed callback."""
994+ self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "", "T")
995+ rcv, = self.get_msd_called("on_sd_name_owner_changed")
996+ self.assertEqual(rcv, True)
997+
998+
999+class TestDataProcessingCQ(SafeTests):
1000+ """Processes CQ data before sending it to SyncDaemon."""
1001+
1002+ @defer.inlineCallbacks
1003+ def test_nodata(self):
1004+ """Test with no data in the queue."""
1005+ self.fake_sdt_response('waiting_content', [])
1006+ rcv = yield self.dbus.get_content_queue()
1007+ self.assertEqual(len(rcv), 0)
1008+
1009+ @defer.inlineCallbacks
1010+ def test_one_item(self):
1011+ """Test with one item in the queue."""
1012+ c = dict(operation='oper', path='path', share='share', node='node')
1013+ self.fake_sdt_response('waiting_content', [c])
1014+ rcv = yield self.dbus.get_content_queue()
1015+ self.assertEqual(len(rcv), 1)
1016+ data = rcv[0]
1017+ self.assertEqual(data.operation, 'oper')
1018+ self.assertEqual(data.path, 'path')
1019+ self.assertEqual(data.share, 'share')
1020+ self.assertEqual(data.node, 'node')
1021+
1022+ @defer.inlineCallbacks
1023+ def test_two_items(self):
1024+ """Test with two items in the queue."""
1025+ c = dict(operation='oper1', path='path1', share='share1', node='node1')
1026+ d = dict(operation='oper2', path='path2', share='share2', node='node2')
1027+ self.fake_sdt_response('waiting_content', [c, d])
1028+ rcv = yield self.dbus.get_content_queue()
1029+ self.assertEqual(len(rcv), 2)
1030+ data = rcv[0]
1031+ self.assertEqual(data.operation, 'oper1')
1032+ self.assertEqual(data.path, 'path1')
1033+ self.assertEqual(data.share, 'share1')
1034+ self.assertEqual(data.node, 'node1')
1035+ data = rcv[1]
1036+ self.assertEqual(data.operation, 'oper2')
1037+ self.assertEqual(data.path, 'path2')
1038+ self.assertEqual(data.share, 'share2')
1039+ self.assertEqual(data.node, 'node2')
1040+
1041+
1042+class TestDataProcessingMQ(SafeTests):
1043+ """Processes MQ data before sending it to SyncDaemon."""
1044+
1045+ @defer.inlineCallbacks
1046+ def test_nodata(self):
1047+ """Test with no data in the queue."""
1048+ self.fake_sdt_response('waiting_metadata', [])
1049+ rcv = yield self.dbus.get_meta_queue()
1050+ self.assertEqual(len(rcv), 0)
1051+
1052+ @defer.inlineCallbacks
1053+ def test_one_item(self):
1054+ """Test with one item in the queue."""
1055+ self.fake_sdt_response('waiting_metadata', ['ListShares'])
1056+ rcv = yield self.dbus.get_meta_queue()
1057+ self.assertEqual(len(rcv), 1)
1058+ data = rcv[0]
1059+ self.assertEqual(data.operation, 'ListShares')
1060+ self.assertEqual(data.path, None)
1061+ self.assertEqual(data.share, None)
1062+ self.assertEqual(data.node, None)
1063+
1064+ @defer.inlineCallbacks
1065+ def test_two_items(self):
1066+ """Test ContentQueueChanged signal with two items in the queue."""
1067+ cmd1 = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
1068+ cmd2 = 'GetPublicFiles'
1069+ self.fake_sdt_response('waiting_metadata', [cmd1, cmd2])
1070+ rcv = yield self.dbus.get_meta_queue()
1071+ self.assertEqual(len(rcv), 2)
1072+ data = rcv[0]
1073+ self.assertEqual(data.operation, 'MakeDir')
1074+ self.assertEqual(data.path, '/?.../c')
1075+ self.assertEqual(data.share, 'a')
1076+ self.assertEqual(data.node, None)
1077+ data = rcv[1]
1078+ self.assertEqual(data.operation, 'GetPublicFiles')
1079+ self.assertEqual(data.path, None)
1080+ self.assertEqual(data.share, None)
1081+ self.assertEqual(data.node, None)
1082+
1083+ @defer.inlineCallbacks
1084+ def test_GetPublicFiles(self):
1085+ """Test meta with GetPublicFiles."""
1086+ cmd = 'GetPublicFiles'
1087+ self.fake_sdt_response('waiting_metadata', [cmd])
1088+ rcv = yield self.dbus.get_meta_queue()
1089+ data = rcv[0]
1090+ self.assertEqual(data.operation, 'GetPublicFiles')
1091+ self.assertEqual(data.path, None)
1092+ self.assertEqual(data.share, None)
1093+ self.assertEqual(data.node, None)
1094+
1095+ @defer.inlineCallbacks
1096+ def test_AccountInquiry(self):
1097+ """Test meta with AccountInquiry."""
1098+ cmd = 'AccountInquiry'
1099+ self.fake_sdt_response('waiting_metadata', [cmd])
1100+ rcv = yield self.dbus.get_meta_queue()
1101+ data = rcv[0]
1102+ self.assertEqual(data.operation, 'AccountInquiry')
1103+ self.assertEqual(data.path, None)
1104+ self.assertEqual(data.share, None)
1105+ self.assertEqual(data.node, None)
1106+
1107+ @defer.inlineCallbacks
1108+ def test_FreeSpaceInquiry(self):
1109+ """Test meta with FreeSpaceInquiry."""
1110+ cmd = 'FreeSpaceInquiry'
1111+ self.fake_sdt_response('waiting_metadata', [cmd])
1112+ rcv = yield self.dbus.get_meta_queue()
1113+ data = rcv[0]
1114+ self.assertEqual(data.operation, 'FreeSpaceInquiry')
1115+ self.assertEqual(data.path, None)
1116+ self.assertEqual(data.share, None)
1117+ self.assertEqual(data.node, None)
1118+
1119+ @defer.inlineCallbacks
1120+ def test_ListShares(self):
1121+ """Test meta with ListShares."""
1122+ cmd = 'ListShares'
1123+ self.fake_sdt_response('waiting_metadata', [cmd])
1124+ rcv = yield self.dbus.get_meta_queue()
1125+ data = rcv[0]
1126+ self.assertEqual(data.operation, 'ListShares')
1127+ self.assertEqual(data.path, None)
1128+ self.assertEqual(data.share, None)
1129+ self.assertEqual(data.node, None)
1130+
1131+ @defer.inlineCallbacks
1132+ def test_ListVolumes(self):
1133+ """Test meta with ListVolumes."""
1134+ cmd = 'ListVolumes'
1135+ self.fake_sdt_response('waiting_metadata', [cmd])
1136+ rcv = yield self.dbus.get_meta_queue()
1137+ data = rcv[0]
1138+ self.assertEqual(data.operation, 'ListVolumes')
1139+ self.assertEqual(data.path, None)
1140+ self.assertEqual(data.share, None)
1141+ self.assertEqual(data.node, None)
1142+
1143+ @defer.inlineCallbacks
1144+ def test_Query(self):
1145+ """Test meta with Query."""
1146+ cmd = 'Query'
1147+ self.fake_sdt_response('waiting_metadata', [cmd])
1148+ rcv = yield self.dbus.get_meta_queue()
1149+ data = rcv[0]
1150+ self.assertEqual(data.operation, 'Query')
1151+ self.assertEqual(data.path, None)
1152+ self.assertEqual(data.share, None)
1153+ self.assertEqual(data.node, None)
1154+
1155+ @defer.inlineCallbacks
1156+ def test_ListDir(self):
1157+ """Test meta with ListDir."""
1158+ cmd = 'ListDir(share_id=a, node_id=b, server_hash=c)'
1159+ self.fake_sdt_response('waiting_metadata', [cmd])
1160+ rcv = yield self.dbus.get_meta_queue()
1161+ data = rcv[0]
1162+ self.assertEqual(data.operation, 'ListDir')
1163+ self.assertEqual(data.path, '?')
1164+ self.assertEqual(data.share, 'a')
1165+ self.assertEqual(data.node, 'b')
1166+
1167+ @defer.inlineCallbacks
1168+ def test_MakeDir(self):
1169+ """Test meta with MakeDir."""
1170+ cmd = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
1171+ self.fake_sdt_response('waiting_metadata', [cmd])
1172+ rcv = yield self.dbus.get_meta_queue()
1173+ data = rcv[0]
1174+ self.assertEqual(data.operation, 'MakeDir')
1175+ self.assertEqual(data.path, '/?.../c')
1176+ self.assertEqual(data.share, 'a')
1177+ self.assertEqual(data.node, None)
1178+
1179+ @defer.inlineCallbacks
1180+ def test_MakeFile(self):
1181+ """Test meta with MakeFile."""
1182+ cmd = 'MakeFile(share_id=a, parent_id=b, name=c, marker=d)'
1183+ self.fake_sdt_response('waiting_metadata', [cmd])
1184+ rcv = yield self.dbus.get_meta_queue()
1185+ data = rcv[0]
1186+ self.assertEqual(data.operation, 'MakeFile')
1187+ self.assertEqual(data.path, '/?.../c')
1188+ self.assertEqual(data.share, 'a')
1189+ self.assertEqual(data.node, None)
1190+
1191+ @defer.inlineCallbacks
1192+ def test_Unlink(self):
1193+ """Test meta with Unlink."""
1194+ cmd = 'Unlink(share_id=a, node_id=b, server_hash=c)'
1195+ self.fake_sdt_response('waiting_metadata', [cmd])
1196+ rcv = yield self.dbus.get_meta_queue()
1197+ data = rcv[0]
1198+ self.assertEqual(data.operation, 'Unlink')
1199+ self.assertEqual(data.path, '?')
1200+ self.assertEqual(data.share, 'a')
1201+ self.assertEqual(data.node, 'b')
1202+
1203+ @defer.inlineCallbacks
1204+ def test_Move(self):
1205+ """Test meta with Move."""
1206+ cmd = 'Move(share_id=a, node_id=b, old_parent_id=c, '\
1207+ 'new_parent_id=d, new_name=e)'
1208+ self.fake_sdt_response('waiting_metadata', [cmd])
1209+ rcv = yield self.dbus.get_meta_queue()
1210+ data = rcv[0]
1211+ self.assertEqual(data.operation, 'Move')
1212+ self.assertEqual(data.path, '/?.../? -> /?.../e')
1213+ self.assertEqual(data.share, 'a')
1214+ self.assertEqual(data.node, 'b')
1215+
1216+
1217+class TestDataProcessingFolders(SafeTests):
1218+ """Processes Folders data before sending it to SyncDaemon."""
1219+
1220+ @defer.inlineCallbacks
1221+ def test_nodata(self):
1222+ """Test get folders with no data."""
1223+ self.fake_sdt_response('get_folders', [])
1224+ rcv = yield self.dbus.get_folders()
1225+ self.assertEqual(len(rcv), 0)
1226+
1227+ @defer.inlineCallbacks
1228+ def test_one(self):
1229+ """Test get folders with one."""
1230+ d = dict(node_id='nid', path=u'pth', subscribed='True',
1231+ suggested_path=u'sgp', type='UDF', volume_id='vid')
1232+ self.fake_sdt_response('get_folders', [d])
1233+ rcv = yield self.dbus.get_folders()
1234+ self.assertEqual(len(rcv), 1)
1235+ folder = rcv[0]
1236+ self.assertEqual(folder.node, 'nid')
1237+ self.assertEqual(folder.path, u'pth')
1238+ self.assertEqual(folder.suggested_path, u'sgp')
1239+ self.assertEqual(folder.subscribed, True)
1240+ self.assertEqual(folder.volume, 'vid')
1241+
1242+ @defer.inlineCallbacks
1243+ def test_getting_info_two(self):
1244+ """When changed, update info, got two."""
1245+ d1 = dict(node_id='nid1', path=u'pth1', subscribed='True',
1246+ suggested_path=u'sgp1', type='UDF', volume_id='vid1')
1247+ d2 = dict(node_id='nid2', path=u'pth2', subscribed='',
1248+ suggested_path=u'sgp2', type='UDF', volume_id='vid2')
1249+ self.fake_sdt_response('get_folders', [d1, d2])
1250+ rcv = yield self.dbus.get_folders()
1251+ self.assertEqual(len(rcv), 2)
1252+ folder = rcv[0]
1253+ self.assertEqual(folder.node, 'nid1')
1254+ self.assertEqual(folder.path, u'pth1')
1255+ self.assertEqual(folder.suggested_path, u'sgp1')
1256+ self.assertEqual(folder.subscribed, True)
1257+ self.assertEqual(folder.volume, 'vid1')
1258+ folder = rcv[1]
1259+ self.assertEqual(folder.node, 'nid2')
1260+ self.assertEqual(folder.path, u'pth2')
1261+ self.assertEqual(folder.suggested_path, u'sgp2')
1262+ self.assertEqual(folder.subscribed, False)
1263+ self.assertEqual(folder.volume, 'vid2')
1264+
1265+
1266+class TestToolActions(SafeTests):
1267+ """Actions against SD.tools.
1268+
1269+ Here we test only the actions, not callbacks, as they're tested before
1270+ in what they return.
1271+ """
1272+
1273+ def test_start(self):
1274+ """Test call to start."""
1275+ self.dbus.start()
1276+ self.check_sdt_called("start")
1277+
1278+ def test_quit(self):
1279+ """Test call to quit."""
1280+ self.dbus.quit()
1281+ self.check_sdt_called("quit")
1282+
1283+ def test_connect(self):
1284+ """Test call to connect."""
1285+ self.dbus.connect()
1286+ self.check_sdt_called("connect")
1287+
1288+ def test_disconnect(self):
1289+ """Test call to disconnect."""
1290+ self.dbus.disconnect()
1291+ self.check_sdt_called("disconnect")
1292+
1293+
1294+class TestLogs(SafeTests):
1295+ """Test logging."""
1296+
1297+ def setUp(self):
1298+ """Set up."""
1299+ self.handler = MementoHandler()
1300+ logging.getLogger('magicicada.dbusiface').addHandler(self.handler)
1301+ self.handler.setLevel(logging.DEBUG)
1302+ SafeTests.setUp(self)
1303+
1304+ def test_instancing(self):
1305+ """Just logged SD instancing."""
1306+ self.assertTrue(self.handler.check_inf("DBus interface starting"))
1307+
1308+ def test_shutdown(self):
1309+ """Log when SD shutdowns."""
1310+ self.dbus.shutdown()
1311+ self.assertTrue(self.handler.check_inf("DBus interface going down"))
1312+
1313+ def test_waiting_content(self):
1314+ """Test call to waiting content."""
1315+ self.dbus.get_content_queue()
1316+ self.assertTrue(self.handler.check_inf("Getting content queue"))
1317+
1318+ def test_waiting_meta(self):
1319+ """Test call to waiting meta."""
1320+ self.dbus.get_meta_queue()
1321+ self.assertTrue(self.handler.check_inf("Getting meta queue"))
1322+
1323+ def test_get_status(self):
1324+ """Test call to status."""
1325+ self.dbus.get_status()
1326+ self.assertTrue(self.handler.check_inf("Getting status"))
1327+
1328+ def test_get_folders(self):
1329+ """Test call to folders."""
1330+ self.dbus.get_folders()
1331+ self.assertTrue(self.handler.check_inf("Getting folders"))
1332+
1333+ def test_is_sd_started(self):
1334+ """Test call to is_sd_started."""
1335+ self.dbus.is_sd_started()
1336+ self.assertTrue(self.handler.check_inf(
1337+ "Checking if SD is started: True"))
1338+
1339+ def test_start(self):
1340+ """Test call to start."""
1341+ self.dbus.start()
1342+ self.assertTrue(self.handler.check_inf("Calling start"))
1343+
1344+ def test_quit(self):
1345+ """Test call to quit."""
1346+ self.dbus.quit()
1347+ self.assertTrue(self.handler.check_inf("Calling quit"))
1348+
1349+ def test_connect(self):
1350+ """Test call to connect."""
1351+ self.dbus.connect()
1352+ self.assertTrue(self.handler.check_inf("Calling connect"))
1353+
1354+ def test_disconnect(self):
1355+ """Test call to disconnect."""
1356+ self.dbus.disconnect()
1357+ self.assertTrue(self.handler.check_inf("Calling disconnect"))
1358+
1359+ def test_status_changed(self):
1360+ """Test status changed callback."""
1361+ d = dict(name='name', description='description', is_error='',
1362+ is_connected='True', is_online='', queues='queues',
1363+ connection='connection')
1364+ self.dbus._on_status_changed(d)
1365+ self.assertTrue(self.handler.check_inf("Received Status changed"))
1366+ self.assertTrue(self.handler.check_dbg("Status changed data: %r" % d))
1367+
1368+ def test_content_queue_changed(self):
1369+ """Test content queue changed callback."""
1370+ self.dbus._on_content_queue_changed("foo")
1371+ self.assertTrue(self.handler.check_inf(
1372+ "Received Content Queue changed"))
1373+
1374+ def test_name_owner_changed_other(self):
1375+ """Test name owner changed callback, no SD."""
1376+ self.dbus._on_name_owner_changed("other", "", "T")
1377+ self.assertFalse(self.handler.check_inf("Received Name Owner changed"))
1378+
1379+ def test_name_owner_changed_syncdaemon(self):
1380+ """Test name owner changed callback, SD value ok."""
1381+ self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "", "T")
1382+ self.assertTrue(self.handler.check_inf("Received Name Owner changed"))
1383+ self.assertTrue(self.handler.check_dbg("Name Owner data: u'' u'T'"))
1384+
1385+ def test_name_owner_changed_yes_syncdaemon_TF(self):
1386+ """Test name owner changed callback, SD value bad."""
1387+ self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "F", "T")
1388+ self.assertTrue(self.handler.check_inf("Received Name Owner changed"))
1389+ self.assertTrue(self.handler.check_dbg("Name Owner data: u'F' u'T'"))
1390+ self.assertTrue(self.handler.check("ERROR",
1391+ "Name Owner invalid data: Same bool in old and new!"))
1392+
1393+ def test_folder_created_changed(self):
1394+ """Test folder created changed callback."""
1395+ self.dbus._on_folder_created("foo")
1396+ self.assertTrue(self.handler.check_inf("Received Folder created"))
1397+
1398+ def test_folder_deleted_changed(self):
1399+ """Test folder deleted changed callback."""
1400+ self.dbus._on_folder_deleted("foo")
1401+ self.assertTrue(self.handler.check_inf("Received Folder deleted"))
1402+
1403+ @defer.inlineCallbacks
1404+ def test_content_queue_processing(self):
1405+ """Test with one item in the queue."""
1406+ c = dict(operation='oper', path='path', share='share', node='node')
1407+ self.fake_sdt_response('waiting_content', [c])
1408+ yield self.dbus.get_content_queue()
1409+ self.assertTrue(self.handler.check_inf(
1410+ "Processing Content Queue items (1)"))
1411+ self.assertTrue(self.handler.check_dbg(
1412+ " Content Queue data: %s" % c))
1413+
1414+ @defer.inlineCallbacks
1415+ def test_meta_queue_processing(self):
1416+ """Test with one item in the queue."""
1417+ self.fake_sdt_response('waiting_metadata', ['ListShares'])
1418+ yield self.dbus.get_meta_queue()
1419+ self.assertTrue(self.handler.check_inf(
1420+ "Processing Meta Queue items (1)"))
1421+ self.assertTrue(self.handler.check_dbg(
1422+ " Meta Queue data: u'ListShares'"))
1423+
1424+ @defer.inlineCallbacks
1425+ def test_folders_processing(self):
1426+ """Test get folders with one."""
1427+ d = dict(node_id='nid', path=u'pth', subscribed='True',
1428+ suggested_path=u'sgp', type='UDF', volume_id='vid')
1429+ self.fake_sdt_response('get_folders', [d])
1430+ yield self.dbus.get_folders()
1431+ self.assertTrue(self.handler.check_inf("Processing Folders items (1)"))
1432+ self.assertTrue(self.handler.check_dbg(" Folders data: %r" % d))
1433
1434=== modified file 'magicicada/tests/test_magicicada.py'
1435--- magicicada/tests/test_magicicada.py 2010-05-27 02:01:27 +0000
1436+++ magicicada/tests/test_magicicada.py 2010-05-27 20:56:26 +0000
1437@@ -25,6 +25,7 @@
1438 from twisted.trial.unittest import TestCase
1439
1440 from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon
1441+from magicicada.dbusiface import QueueData
1442 from magicicada.helpers import NO_OP
1443
1444
1445@@ -278,9 +279,9 @@
1446 """Build some data to pass to queue changed callback and related."""
1447 items = []
1448 for i in xrange(limit):
1449- cq = syncdaemon.QueueData(operation='operation %i' % i,
1450- path='path %i' % i, node='node %i' % i,
1451- share='share %i' % i)
1452+ cq = QueueData(operation='operation %i' % i,
1453+ path='path %i' % i, node='node %i' % i,
1454+ share='share %i' % i)
1455 items.append(cq)
1456 return items
1457
1458
1459=== modified file 'magicicada/tests/test_syncdaemon.py'
1460--- magicicada/tests/test_syncdaemon.py 2010-05-22 20:27:11 +0000
1461+++ magicicada/tests/test_syncdaemon.py 2010-05-27 20:56:26 +0000
1462@@ -21,49 +21,133 @@
1463 import logging
1464 import unittest
1465
1466-import dbus
1467-from dbus.mainloop.glib import DBusGMainLoop
1468-
1469-# this should be imported *before* importing the reactor below, as needs to
1470-# install the glib connection first
1471 from magicicada.syncdaemon import SyncDaemon, State
1472-from magicicada.helpers import NO_OP
1473+from magicicada.tests.helpers import MementoHandler
1474
1475-from dbus.lowlevel import SignalMessage
1476 from twisted.trial.unittest import TestCase as TwistedTestCase
1477 from twisted.internet import defer, reactor
1478
1479-from ubuntuone.syncdaemon.dbus_interface import DBUS_IFACE_STATUS_NAME
1480-
1481-
1482-class SignalsBaseTest(TwistedTestCase):
1483- """Base infrastructure to tests the signals."""
1484-
1485- timeout = 2
1486+
1487+class FakeDBusInterface(object):
1488+ """Fake DBus Interface, for SD to not use dbus at all during tests."""
1489+
1490+ fake_sd_started = False
1491+
1492+ def __init__(self, sd):
1493+ pass
1494+
1495+ def shutdown(self):
1496+ pass
1497+
1498+ def get_status(self):
1499+ """Fake status."""
1500+ return defer.succeed(('fakename', 'fakedescrip', False, True,
1501+ False, 'fakequeues', 'fakeconnection'))
1502+ def get_folders(self):
1503+ """Fake folders."""
1504+ return defer.succeed('fakedata')
1505+ get_content_queue = get_meta_queue = get_folders
1506+ start = quit = connect = disconnect = get_folders
1507+
1508+ def is_sd_started(self):
1509+ """Fake response."""
1510+ return self.fake_sd_started
1511+
1512+
1513+class BaseTest(TwistedTestCase):
1514+ """Base test with a SD."""
1515+
1516+ timeout = 1
1517
1518 def setUp(self):
1519- """Set up the test."""
1520- self.loop = DBusGMainLoop(set_as_default=True)
1521- self.bus = dbus.bus.BusConnection(mainloop=self.loop)
1522- self.sd = SyncDaemon()
1523+ """Set up."""
1524+ self.sd = SyncDaemon(FakeDBusInterface)
1525
1526 def tearDown(self):
1527- """Tear down the test."""
1528+ """Tear down."""
1529 self.sd.shutdown()
1530
1531- def send_signal(self, interface, signal, signature, *args):
1532- """Send a DBus signal."""
1533- msg = SignalMessage('/status', interface, signal)
1534- msg.set_no_reply(True)
1535- msg.append(*args, signature=signature)
1536- self.bus.send_message(msg)
1537-
1538-
1539-class SimpleSignalsTests(SignalsBaseTest):
1540+
1541+class InitialDataTests(unittest.TestCase):
1542+ """Tests for initial data gathering."""
1543+
1544+ def test_called_by_start(self):
1545+ """Check that start calls get initial data."""
1546+ sd = SyncDaemon(FakeDBusInterface)
1547+ called = []
1548+ sd._get_initial_data = lambda: called.append(True)
1549+ sd.start()
1550+ self.assertTrue(called)
1551+
1552+ def test_called_by_nameownerchanged_no(self):
1553+ """Check that it is called when discover that sd started."""
1554+ sd = SyncDaemon(FakeDBusInterface)
1555+ called = []
1556+ sd._get_initial_data = lambda: called.append(True)
1557+ sd.on_sd_name_owner_changed(True)
1558+ self.assertTrue(called)
1559+
1560+ def test_called_by_nameownerchanged_yes(self):
1561+ """Check that it is not called when discover that sd stopped."""
1562+ sd = SyncDaemon(FakeDBusInterface)
1563+ called = []
1564+ sd._get_initial_data = lambda: called.append(True)
1565+ sd.on_sd_name_owner_changed(False)
1566+ self.assertFalse(called)
1567+
1568+ def test_called_beggining_no(self):
1569+ """Check that it should not be called if no SD."""
1570+ called = []
1571+ orig_met = SyncDaemon._get_initial_data
1572+ SyncDaemon._get_initial_data = lambda s: called.append(True)
1573+ SyncDaemon(FakeDBusInterface)
1574+ SyncDaemon._get_initial_data = orig_met
1575+ self.assertFalse(called)
1576+
1577+ def test_called_beggining_yes(self):
1578+ """Check that it should be called if SD already started."""
1579+ called = []
1580+ orig_met = SyncDaemon._get_initial_data
1581+ SyncDaemon._get_initial_data = lambda s: called.append(True)
1582+ FakeDBusInterface.fake_sd_started = True
1583+ SyncDaemon(FakeDBusInterface)
1584+ SyncDaemon._get_initial_data = orig_met
1585+ self.assertTrue(called)
1586+
1587+ def test_calls_callbacks(self):
1588+ """Check that initial data calls the callbacks for new data."""
1589+ called = []
1590+ sd = SyncDaemon(FakeDBusInterface)
1591+ f = lambda *a: called.append(True)
1592+ sd.status_changed_callback = f
1593+ sd.content_queue_changed_callback = f
1594+ sd.meta_queue_changed_callback = f
1595+
1596+ sd._get_initial_data()
1597+ self.assertEqual(len(called), 3)
1598+
1599+
1600+class StatusChangedTests(BaseTest):
1601 """Simple signals checking."""
1602
1603+ @defer.inlineCallbacks
1604+ def test_initial_value(self):
1605+ """Fills the status info initially."""
1606+ called = []
1607+ def fake():
1608+ """Fake method."""
1609+ called.append(True)
1610+ return defer.succeed(('fakename', 'fakedescrip', False, True,
1611+ False, 'fakequeues', 'fakeconnection'))
1612+
1613+ self.sd.dbus.get_status = fake
1614+ yield self.sd._get_initial_data()
1615+ self.assertTrue(called)
1616+
1617 def test_statuschanged(self):
1618 """Test StatusChanged signal."""
1619+ deferred = defer.Deferred()
1620+
1621 def callback(name, description, is_error, is_connected, is_online,
1622 queues, connection):
1623 """Check received data."""
1624@@ -76,325 +160,208 @@
1625 self.assertEqual(connection, 'connection')
1626 deferred.callback(True)
1627
1628- # set the callback
1629 self.sd.status_changed_callback = callback
1630-
1631- # send signal with signature and structures like original syncdaemon
1632- d = dict(name='name', description='description', is_error='',
1633- is_connected='True', is_online='', queues='queues',
1634- connection='connection')
1635- self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
1636-
1637- deferred = defer.Deferred()
1638+ self.sd.on_sd_status_changed('name', 'description', False, True,
1639+ False, 'queues', 'connection')
1640 return deferred
1641
1642-
1643-class ContentQueueChangedTests(SignalsBaseTest):
1644+ def test_status_changed_affects_cuurent_status(self):
1645+ """Makes changes to see how status are reflected."""
1646+ # one set of values
1647+ self.sd.on_sd_status_changed('name1', 'description1', False, True,
1648+ False, 'queues1', 'connection1')
1649+ self.assertEqual(self.sd.current_state.name, 'name1')
1650+ self.assertEqual(self.sd.current_state.description, 'description1')
1651+ self.assertEqual(self.sd.current_state.is_error, False)
1652+ self.assertEqual(self.sd.current_state.is_connected, True)
1653+ self.assertEqual(self.sd.current_state.is_online, False)
1654+ self.assertEqual(self.sd.current_state.queues, 'queues1')
1655+ self.assertEqual(self.sd.current_state.connection, 'connection1')
1656+
1657+ # again, to be sure they actually are updated
1658+ self.sd.on_sd_status_changed('name2', 'description2', True, False,
1659+ True, 'queues2', 'connection2')
1660+ self.assertEqual(self.sd.current_state.name, 'name2')
1661+ self.assertEqual(self.sd.current_state.description, 'description2')
1662+ self.assertEqual(self.sd.current_state.is_error, True)
1663+ self.assertEqual(self.sd.current_state.is_connected, False)
1664+ self.assertEqual(self.sd.current_state.is_online, True)
1665+ self.assertEqual(self.sd.current_state.queues, 'queues2')
1666+ self.assertEqual(self.sd.current_state.connection, 'connection2')
1667+
1668+
1669+class ContentQueueChangedTests(BaseTest):
1670 """Check the ContenQueueChanged handling."""
1671
1672+ @defer.inlineCallbacks
1673+ def test_initial_value(self):
1674+ """Fills the content queue info initially."""
1675+ called = []
1676+ self.sd.dbus.get_content_queue = lambda: called.append(True)
1677+ yield self.sd._get_initial_data()
1678+ self.assertTrue(called)
1679+
1680 def test_without_setting_callback(self):
1681 """It should work even if not hooking into the callback."""
1682- self.sd._process_cq([])
1683-
1684- def _contentqueuechanged_test(self, somedata):
1685- """Test ContentQueueChanged signal with some data."""
1686- def callback(queued_elements):
1687- """Check received data."""
1688- self.assertEqual(len(queued_elements), len(somedata))
1689- for received, original in zip(queued_elements, somedata):
1690- self.assertEqual(received.operation, original['operation'])
1691- self.assertEqual(received.path, original['path'])
1692- self.assertEqual(received.share, original['share'])
1693- self.assertEqual(received.node, original['node'])
1694- deferred.callback(True)
1695-
1696- # set the callback
1697- self.sd.content_queue_changed_callback = callback
1698-
1699- # monkeypatch SyncDaemon to quickly return the queued elements
1700- self.sd._get_content_queue = lambda: defer.succeed(somedata)
1701-
1702- # send signal with signature and structures like original syncdaemon,
1703- # but note that in this case we don't care of this info
1704- data = {'foo': {'bar':'1', 'baz':'2'}}
1705- self.send_signal(DBUS_IFACE_STATUS_NAME, 'ContentQueueChanged',
1706- 'a{sa{ss}}', data)
1707- deferred = defer.Deferred()
1708- return deferred
1709-
1710- def test_contentqueuechanged_nodata(self):
1711- """Test ContentQueueChanged signal with no data in the queue."""
1712- return self._contentqueuechanged_test([])
1713-
1714- def test_contentqueuechanged_oneitem(self):
1715- """Test ContentQueueChanged signal with one item in the queue."""
1716- c = dict(operation='oper', path='path', share='share', node='node')
1717- return self._contentqueuechanged_test([c])
1718-
1719- def test_contentqueuechanged_twoitems(self):
1720- """Test ContentQueueChanged signal with two items in the queue."""
1721- c = dict(operation='oper1', path='path1', share='share1', node='node1')
1722- d = dict(operation='oper2', path='path2', share='share2', node='node2')
1723- return self._contentqueuechanged_test([c, d])
1724-
1725- def test_no_double_callback_for_same_info(self):
1726- """No callback call for same info in the CQ."""
1727- callback_called = []
1728- def callback(queued_elements):
1729- """Store the callbacked stuff."""
1730- callback_called.append(queued_elements)
1731-
1732- # set the callback
1733- self.sd.content_queue_changed_callback = callback
1734-
1735- # data to test
1736- c = dict(operation='oper1', path='path1', share='share1', node='node1')
1737- d = dict(operation='oper2', path='path2', share='share2', node='node2')
1738- e = dict(operation='oper3', path='path3', share='share3', node='node3')
1739-
1740- # call a sequence of different and repeated data
1741- self.sd._process_cq([c])
1742- self.sd._process_cq([d])
1743- self.sd._process_cq([d]) # repeated!
1744- self.sd._process_cq([c])
1745- self.sd._process_cq([e])
1746- self.sd._process_cq([e]) # repeated!
1747- self.sd._process_cq([e]) # repeated!
1748- self.sd._process_cq([d])
1749- self.sd._process_cq([d, d])
1750- self.sd._process_cq([d, d]) # repeated!
1751- self.sd._process_cq([d])
1752- should_be = [ [c], [d], [c], [e], [d], [d, d], [d] ]
1753-
1754- # check order and that it wasn't repeated
1755- self.assertEqual(len(callback_called), len(should_be))
1756- for cq_received, cq_original in zip(callback_called, should_be):
1757- for received, original in zip(cq_received, cq_original):
1758- self.assertEqual(received.operation, original['operation'])
1759- self.assertEqual(received.path, original['path'])
1760- self.assertEqual(received.share, original['share'])
1761- self.assertEqual(received.node, original['node'])
1762-
1763- def test_CQ_state_none(self):
1764- """Check the ContentQueue info, being none."""
1765- self.assertEqual(len(self.sd.content_queue), 0)
1766+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1767+ self.sd.on_sd_content_queue_changed()
1768+
1769+ def test_callback_call(self):
1770+ """Call the callback."""
1771+ called = []
1772+ self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
1773+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1774+ self.sd.on_sd_content_queue_changed()
1775+ self.assertTrue(called)
1776+
1777+ def test_callback_call_twice_different(self):
1778+ """Call the callback twice for different info."""
1779+ called = []
1780+ self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
1781+
1782+ # first call
1783+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1784+ self.sd.on_sd_content_queue_changed()
1785+ self.assertEqual(called, [['foo']])
1786+
1787+ # second call, different info
1788+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['bar'])
1789+ self.sd.on_sd_content_queue_changed()
1790+ self.assertEqual(called, [['foo'], ['bar']])
1791+
1792+ def test_callback_call_twice_same(self):
1793+ """Call the callback once, even getting twice the same info."""
1794+ called = []
1795+ self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
1796+
1797+ # first call
1798+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1799+ self.sd.on_sd_content_queue_changed()
1800+ self.assertEqual(called, [['foo']])
1801+
1802+ # second call, same info
1803+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1804+ self.sd.on_sd_content_queue_changed()
1805+ self.assertEqual(called, [['foo']])
1806+
1807+ def test_CQ_state_nothing(self):
1808+ """Check the ContentQueue info, being nothing."""
1809+ self.sd.dbus.get_content_queue = lambda: defer.succeed([])
1810+ self.sd.on_sd_content_queue_changed()
1811+ self.assertEqual(self.sd.content_queue, [])
1812
1813 def test_CQ_state_one(self):
1814 """Check the ContentQueue info, being one."""
1815- d = dict(operation='oper', path='path', share='share', node='node')
1816- self.sd._process_cq([d])
1817- self.assertEqual(len(self.sd.content_queue), 1)
1818-
1819- # check the data
1820- cqit = self.sd.content_queue[0]
1821- self.assertEqual(cqit.operation, 'oper')
1822- self.assertEqual(cqit.path, 'path')
1823- self.assertEqual(cqit.share, 'share')
1824- self.assertEqual(cqit.node, 'node')
1825-
1826- def test_CQ_state_several(self):
1827- """Check the ContentQueue info, several calls, last one is bigger."""
1828- c = dict(operation='oper1', path='path1', share='share1', node='node1')
1829- d = dict(operation='oper2', path='path2', share='share2', node='node2')
1830- self.sd._process_cq([c])
1831- self.sd._process_cq([d])
1832- self.sd._process_cq([c, d])
1833- self.assertEqual(len(self.sd.content_queue), 2)
1834-
1835- # check the data
1836- cqit = self.sd.content_queue[0]
1837- self.assertEqual(cqit.operation, 'oper1')
1838- self.assertEqual(cqit.path, 'path1')
1839- self.assertEqual(cqit.share, 'share1')
1840- self.assertEqual(cqit.node, 'node1')
1841- cqit = self.sd.content_queue[1]
1842- self.assertEqual(cqit.operation, 'oper2')
1843- self.assertEqual(cqit.path, 'path2')
1844- self.assertEqual(cqit.share, 'share2')
1845- self.assertEqual(cqit.node, 'node2')
1846-
1847-
1848-class MetaQueueChangedTests(SignalsBaseTest):
1849+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
1850+ self.sd.on_sd_content_queue_changed()
1851+ self.assertEqual(self.sd.content_queue, ['foo'])
1852+
1853+ def test_CQ_state_two(self):
1854+ """Check the ContentQueue info, two."""
1855+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo', 'bar'])
1856+ self.sd.on_sd_content_queue_changed()
1857+ self.assertEqual(self.sd.content_queue, ['foo', 'bar'])
1858+
1859+
1860+class MetaQueueChangedTests(BaseTest):
1861 """Check the MetaQueueChanged handling."""
1862
1863- def test_without_setting_callback(self):
1864- """It should work even if not hooking into the callback."""
1865- self.sd._process_mq([])
1866-
1867- def _metaqueuechanged_test(self, inpdata, outdata):
1868- """Test MetaQueueChanged signal with some data."""
1869- deferred = defer.Deferred()
1870- def callback(queued_elements):
1871- """Check received data."""
1872- self.assertEqual(len(queued_elements), len(outdata))
1873- for received, original in zip(queued_elements, outdata):
1874- self.assertEqual(received.operation, original['operation'])
1875- self.assertEqual(received.path, original['path'])
1876- self.assertEqual(received.share, original['share'])
1877- self.assertEqual(received.node, original['node'])
1878- deferred.callback(True)
1879-
1880- # set the callback
1881- self.sd.meta_queue_changed_callback = callback
1882-
1883- # execute the function that trigger this (not by a dbus signal, as
1884- # that was not available in Lucid)
1885- self.sd._process_mq(inpdata)
1886-
1887- return deferred
1888-
1889- def test_metaqueuechanged_nodata(self):
1890- """Test MetaQueueChanged signal with no data in the queue."""
1891- return self._metaqueuechanged_test([], [])
1892-
1893- def test_GetPublicFiles(self):
1894- """Test meta with GetPublicFiles."""
1895- r = dict(operation='GetPublicFiles', path=None, share=None, node=None)
1896- return self._metaqueuechanged_test(['GetPublicFiles'], [r])
1897-
1898- def test_AccountInquiry(self):
1899- """Test meta with AccountInquiry."""
1900- r = dict(operation='AccountInquiry', path=None, share=None, node=None)
1901- return self._metaqueuechanged_test(['AccountInquiry'], [r])
1902-
1903- def test_FreeSpaceInquiry(self):
1904- """Test meta with FreeSpaceInquiry."""
1905- r = dict(operation='FreeSpaceInquiry', path=None,
1906- share=None, node=None)
1907- return self._metaqueuechanged_test(['FreeSpaceInquiry'], [r])
1908-
1909- def test_ListShares(self):
1910- """Test meta with ListShares."""
1911- r = dict(operation='ListShares', path=None, share=None, node=None)
1912- return self._metaqueuechanged_test(['ListShares'], [r])
1913-
1914- def test_ListVolumes(self):
1915- """Test meta with ListVolumes."""
1916- r = dict(operation='ListVolumes', path=None, share=None, node=None)
1917- return self._metaqueuechanged_test(['ListVolumes'], [r])
1918-
1919- def test_Query(self):
1920- """Test meta with Query."""
1921- r = dict(operation='Query', path=None, share=None, node=None)
1922- return self._metaqueuechanged_test(['Query'], [r])
1923-
1924- def test_ListDir(self):
1925- """Test meta with ListDir."""
1926- r = dict(operation='ListDir', path='?', share='a', node='b')
1927- cmd = 'ListDir(share_id=a, node_id=b, server_hash=c)'
1928- return self._metaqueuechanged_test([cmd], [r])
1929-
1930- def test_MakeDir(self):
1931- """Test meta with MakeDir."""
1932- r = dict(operation='MakeDir', path='/?.../c', share='a', node=None)
1933- cmd = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
1934- return self._metaqueuechanged_test([cmd], [r])
1935-
1936- def test_MakeFile(self):
1937- """Test meta with MakeFile."""
1938- r = dict(operation='MakeFile', path='/?.../c', share='a', node=None)
1939- cmd = 'MakeFile(share_id=a, parent_id=b, name=c, marker=d)'
1940- return self._metaqueuechanged_test([cmd], [r])
1941-
1942- def test_Unlink(self):
1943- """Test meta with Unlink."""
1944- r = dict(operation='Unlink', path='?', share='a', node='b')
1945- cmd = 'Unlink(share_id=a, node_id=b, server_hash=c)'
1946- return self._metaqueuechanged_test([cmd], [r])
1947-
1948- def test_Move(self):
1949- """Test meta with Move."""
1950- r = dict(operation='Move', path='/?.../? -> /?.../e',
1951- share='a', node='b')
1952- cmd = 'Move(share_id=a, node_id=b, old_parent_id=c, '\
1953- 'new_parent_id=d, new_name=e)'
1954- return self._metaqueuechanged_test([cmd], [r])
1955-
1956- def test_metaqueuechanged_twoitems(self):
1957- """Test MetaQueueChanged signal with two items in the queue."""
1958- r1 = dict(operation='AccountInquiry', path=None, share=None, node=None)
1959- r2 = dict(operation='ListShares', path=None, share=None, node=None)
1960- return self._metaqueuechanged_test(['AccountInquiry', 'ListShares'],
1961- [r1, r2])
1962-
1963- def test_no_double_callback_for_same_info(self):
1964- """No callback call for same info in the MQ."""
1965- callback_called = []
1966- def callback(queued_elements):
1967- """Store the callbacked stuff."""
1968- callback_called.append(queued_elements)
1969-
1970- # set the callback
1971- self.sd.meta_queue_changed_callback = callback
1972-
1973- # data to test
1974- r1 = dict(operation='AccountInquiry', path=None, share=None, node=None)
1975- cmd1 = 'AccountInquiry'
1976- r2 = dict(operation='ListShares', path=None, share=None, node=None)
1977- cmd2 = 'ListShares'
1978- r3 = dict(operation='ListDir', path='?', share='a', node='b')
1979- cmd3 = 'ListDir(share_id=a, node_id=b, server_hash=c)'
1980-
1981- # call a sequence of different and repeated data
1982- self.sd._process_mq([cmd1])
1983- self.sd._process_mq([cmd2])
1984- self.sd._process_mq([cmd2]) # repeated!
1985- self.sd._process_mq([cmd1])
1986- self.sd._process_mq([cmd3])
1987- self.sd._process_mq([cmd3]) # repeated!
1988- self.sd._process_mq([cmd3]) # repeated!
1989- self.sd._process_mq([cmd2])
1990- self.sd._process_mq([cmd2, cmd2])
1991- self.sd._process_mq([cmd2, cmd2]) # repeated!
1992- self.sd._process_mq([cmd2])
1993- should_be = [ [r1], [r2], [r1], [r3], [r2], [r2, r2], [r2] ]
1994-
1995- # check order and that it wasn't repeated
1996- self.assertEqual(len(callback_called), len(should_be))
1997- for cq_received, cq_original in zip(callback_called, should_be):
1998- for received, original in zip(cq_received, cq_original):
1999- self.assertEqual(received.operation, original['operation'])
2000- self.assertEqual(received.path, original['path'])
2001- self.assertEqual(received.share, original['share'])
2002- self.assertEqual(received.node, original['node'])
2003+ def setUp(self):
2004+ """Set up."""
2005+ BaseTest.setUp(self)
2006+ self.sd.current_state._set(name='QUEUE_MANAGER',
2007+ queues='WORKING_ON_METADATA')
2008+
2009+ @defer.inlineCallbacks
2010+ def test_initial_value(self):
2011+ """Fills the meta queue info initially."""
2012+ called = []
2013+ self.sd.dbus.get_meta_queue = lambda: called.append(True)
2014+ yield self.sd._get_initial_data()
2015+ self.assertTrue(called)
2016+
2017+ def test_callback_call(self):
2018+ """Call the callback."""
2019+ called = []
2020+ self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
2021+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2022+ self.sd._check_mq()
2023+ self.assertTrue(called)
2024+
2025+ def test_callback_call_twice_different(self):
2026+ """Call the callback twice for different info."""
2027+ called = []
2028+ self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
2029+
2030+ # first call
2031+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2032+ self.sd._check_mq()
2033+ self.assertEqual(called, [['foo']])
2034+
2035+ # second call, different info
2036+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['bar'])
2037+ self.sd._check_mq()
2038+ self.assertEqual(called, [['foo'], ['bar']])
2039+
2040+ def test_callback_call_twice_same(self):
2041+ """Call the callback once, even getting twice the same info."""
2042+ called = []
2043+ self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
2044+
2045+ # first call
2046+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2047+ self.sd._check_mq()
2048+ self.assertEqual(called, [['foo']])
2049+
2050+ # second call, same info
2051+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2052+ self.sd._check_mq()
2053+ self.assertEqual(called, [['foo']])
2054+
2055+ def test_polling_initiated_state_changed(self):
2056+ """The polling initiates when state changes."""
2057+ called = []
2058+ self.sd._check_mq = lambda: called.append(True)
2059+
2060+ # send some status changed
2061+ self.sd.on_sd_status_changed('name', 'description', False, True,
2062+ False, 'queues', 'connection')
2063+ self.assertTrue(called)
2064
2065 def test_mq_polling_workinginmetadata(self):
2066 """Check that it polls mq while working in metadata."""
2067-
2068 # set the callback
2069- self.sd._get_meta_queue = lambda *a: deferred.callback(True)
2070-
2071- # send signal with signature and structures like original syncdaemon
2072- d = dict(name='QUEUE_MANAGER', queues='WORKING_ON_METADATA',
2073- description='description', is_error='', is_connected='True',
2074- is_online='', connection='conn')
2075- self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
2076-
2077 deferred = defer.Deferred()
2078+ def fake():
2079+ """Fake."""
2080+ deferred.callback(True)
2081+ return defer.succeed("foo")
2082+ self.sd.dbus.get_meta_queue = fake
2083+
2084+ # send status changed to working in metadata
2085+ self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
2086+ True, False, 'WORKING_ON_METADATA',
2087+ 'connection')
2088 return deferred
2089
2090 def test_mq_polling_workinginboth(self):
2091 """Check that it polls mq while working in both."""
2092-
2093 # set the callback
2094- self.sd._get_meta_queue = lambda *a: deferred.callback(True)
2095-
2096- # send signal with signature and structures like original syncdaemon
2097- d = dict(name='QUEUE_MANAGER', queues='WORKING_ON_BOTH',
2098- description='description', is_error='', is_connected='True',
2099- is_online='', connection='conn')
2100- self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
2101-
2102 deferred = defer.Deferred()
2103+ def fake():
2104+ """Fake."""
2105+ deferred.callback(True)
2106+ return defer.succeed("foo")
2107+ self.sd.dbus.get_meta_queue = fake
2108+
2109+ # send status changed to working in metadata
2110+ self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
2111+ True, False, 'WORKING_ON_BOTH',
2112+ 'connection')
2113 return deferred
2114
2115 def test_mq_polling_untilfinish(self):
2116 """Check that it polls mq until no more is needed."""
2117- # prepare different status changed signals
2118- d1 = dict(name='QUEUE_MANAGER', queues='WORKING_ON_BOTH',
2119- description='description', is_error='', is_connected='True',
2120- is_online='', connection='conn')
2121-
2122 d2 = dict(name='QUEUE_MANAGER', queues='WORKING_ON_CONTENT',
2123 description='description', is_error='', is_connected='True',
2124 is_online='', connection='conn')
2125@@ -402,61 +369,47 @@
2126 # set the callback, and adjust the polling time to faster
2127 calls = []
2128 def fake_get(*a):
2129+ """Fake get."""
2130 calls.append(None)
2131 if len(calls) < 3:
2132 pass # no changes, should keep calling
2133 elif len(calls) == 3:
2134- self.send_signal(DBUS_IFACE_STATUS_NAME,
2135- 'StatusChanged', 'a{ss}', d2)
2136+ self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description',
2137+ False, True, False,
2138+ 'WORKING_ON_CONTENT', 'connect')
2139+
2140 # allow time to see if a mistaken call happens
2141 reactor.callLater(.5, deferred.callback, True)
2142 else:
2143 deferred.errback(ValueError("Too many calls"))
2144- return defer.Deferred()
2145+ return defer.succeed("foo")
2146
2147- self.sd._get_meta_queue = fake_get
2148+ self.sd.dbus.get_meta_queue = fake_get
2149 self.sd._mq_poll_time = .1
2150
2151- self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d1)
2152+ self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
2153+ True, False, 'WORKING_ON_BOTH',
2154+ 'connection')
2155 deferred = defer.Deferred()
2156 return deferred
2157
2158- def test_MQ_state_none(self):
2159- """Check the MetaQueue info, being none."""
2160- self.assertEqual(len(self.sd.meta_queue), 0)
2161+ def test_MQ_state_nothing(self):
2162+ """Check the MetaQueue info, being nothing."""
2163+ self.sd.dbus.get_meta_queue = lambda: defer.succeed([])
2164+ self.sd._check_mq()
2165+ self.assertEqual(self.sd.meta_queue, [])
2166
2167 def test_MQ_state_one(self):
2168 """Check the MetaQueue info, being one."""
2169- self.sd._process_mq(['ListShares'])
2170- self.assertEqual(len(self.sd.meta_queue), 1)
2171-
2172- # check the data
2173- mqit = self.sd.meta_queue[0]
2174- self.assertEqual(mqit.operation, 'ListShares')
2175- self.assertEqual(mqit.path, None)
2176- self.assertEqual(mqit.share, None)
2177- self.assertEqual(mqit.node, None)
2178-
2179- def test_MQ_state_several(self):
2180- """Check the MetaQueue info, several calls, last one is bigger."""
2181- cmd1 = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
2182- cmd2 = 'GetPublicFiles'
2183- self.sd._process_mq([cmd1])
2184- self.sd._process_mq([cmd2])
2185- self.sd._process_mq([cmd1, cmd2])
2186- self.assertEqual(len(self.sd.meta_queue), 2)
2187-
2188- # check the data
2189- mqit = self.sd.meta_queue[0]
2190- self.assertEqual(mqit.operation, 'MakeDir')
2191- self.assertEqual(mqit.path, '/?.../c')
2192- self.assertEqual(mqit.share, 'a')
2193- self.assertEqual(mqit.node, None)
2194- mqit = self.sd.meta_queue[1]
2195- self.assertEqual(mqit.operation, 'GetPublicFiles')
2196- self.assertEqual(mqit.path, None)
2197- self.assertEqual(mqit.share, None)
2198- self.assertEqual(mqit.node, None)
2199+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2200+ self.sd._check_mq()
2201+ self.assertEqual(self.sd.meta_queue, ['foo'])
2202+
2203+ def test_MQ_state_two(self):
2204+ """Check the MetaQueue info, two."""
2205+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo', 'bar'])
2206+ self.sd._check_mq()
2207+ self.assertEqual(self.sd.meta_queue, ['foo', 'bar'])
2208
2209
2210 class StateTests(unittest.TestCase):
2211@@ -519,95 +472,51 @@
2212 f = lambda *a, **k: setattr(self, 'called', True)
2213 setattr(obj, method_name, f)
2214
2215- def test_defaults_are_callable(self):
2216- """Check the attributes are callable."""
2217- meths = (self.sd._get_content_queue, self.sd._get_meta_queue,
2218- self.sd._do_start, self.sd._do_quit,
2219- self.sd._do_connect, self.sd._do_disconnect)
2220- for meth in meths:
2221- self.assertTrue(callable(meth), "Meth %r is not callable" % meth)
2222-
2223- def test_is_connected_yes(self):
2224- """Check is_connected, True."""
2225- d = dict(name='name', description='description', is_error='',
2226- is_connected='True', is_online='', queues='queues',
2227- connection='connection')
2228- self.sd._on_status_changed(d)
2229- self.assertTrue(self.sd.current_state.is_connected)
2230-
2231- def test_is_connected_no(self):
2232- """Check is_connected, False."""
2233- d = dict(name='name', description='description', is_error='',
2234- is_connected='', is_online='', queues='queues',
2235- connection='connection')
2236- self.sd._on_status_changed(d)
2237- self.assertFalse(self.sd.current_state.is_connected)
2238-
2239- def test_is_online_yes(self):
2240- """Check is_online, True."""
2241- d = dict(name='name', description='description', is_error='',
2242- is_connected='True', is_online='True', queues='queues',
2243- connection='connection')
2244- self.sd._on_status_changed(d)
2245- self.assertTrue(self.sd.current_state.is_online)
2246-
2247- def test_is_online_no(self):
2248- """Check is_online, False."""
2249- d = dict(name='name', description='description', is_error='',
2250- is_connected='True', is_online='', queues='queues',
2251- connection='connection')
2252- self.sd._on_status_changed(d)
2253- self.assertFalse(self.sd.current_state.is_online)
2254-
2255 def test_is_started_yes(self):
2256 """Check is_started, True."""
2257 # simulate the signal that indicates the name was registered
2258- self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', '', 'yes')
2259+ self.sd.on_sd_name_owner_changed(True)
2260 self.assertTrue(self.sd.current_state.is_started)
2261
2262 def test_is_started_no(self):
2263 """Check is_started, False."""
2264- self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'yes', '')
2265+ self.sd.on_sd_name_owner_changed(False)
2266 self.assertFalse(self.sd.current_state.is_started)
2267
2268 def test_start(self):
2269 """Test start calls SD."""
2270- self.mpatch_called(self.sd, '_do_start')
2271+ self.mpatch_called(self.sd.dbus, 'start')
2272 self.sd.start()
2273 self.assertTrue(self.called)
2274
2275 def test_quit(self):
2276 """Test quit calls SD."""
2277- self.mpatch_called(self.sd, '_do_quit')
2278+ self.mpatch_called(self.sd.dbus, 'quit')
2279 self.sd.quit()
2280 self.assertTrue(self.called)
2281
2282 def test_connect(self):
2283 """Test connect calls SD."""
2284- self.mpatch_called(self.sd, '_do_connect')
2285+ self.mpatch_called(self.sd.dbus, 'connect')
2286 self.sd.connect()
2287 self.assertTrue(self.called)
2288
2289 def test_disconnect(self):
2290 """Test disconnect calls SD."""
2291- self.mpatch_called(self.sd, '_do_disconnect')
2292+ self.mpatch_called(self.sd.dbus, 'disconnect')
2293 self.sd.disconnect()
2294 self.assertTrue(self.called)
2295
2296 def test_on_started(self):
2297 """Called when SD started."""
2298 self.flag_called(self.sd, 'on_started_callback')
2299-
2300- # simulate the signal that indicates the name was registered
2301- self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', '', 'yes')
2302+ self.sd.on_sd_name_owner_changed(True)
2303 self.assertTrue(self.called)
2304
2305 def test_on_stopped(self):
2306 """Called when SD stopped."""
2307 self.flag_called(self.sd, 'on_stopped_callback')
2308-
2309- # simulate the signal that indicates the name was registered
2310- self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'yes', '')
2311+ self.sd.on_sd_name_owner_changed(False)
2312 self.assertTrue(self.called)
2313
2314 def test_on_connected(self):
2315@@ -615,10 +524,8 @@
2316 self.flag_called(self.sd, 'on_connected_callback')
2317
2318 # first signal with connected in True
2319- d = dict(name='name', description='description', is_error='',
2320- is_connected='True', is_online='', queues='queues',
2321- connection='connection')
2322- self.sd._on_status_changed(d)
2323+ self.sd.on_sd_status_changed('name', 'description', False, True,
2324+ False, 'queues', 'connection')
2325 self.assertTrue(self.called)
2326
2327 def test_on_disconnected(self):
2328@@ -626,12 +533,10 @@
2329 self.flag_called(self.sd, 'on_disconnected_callback')
2330
2331 # connect and disconnect
2332- d = dict(name='name', description='description', is_error='',
2333- is_connected='True', is_online='', queues='queues',
2334- connection='connection')
2335- self.sd._on_status_changed(d)
2336- d['is_connected'] = ''
2337- self.sd._on_status_changed(d)
2338+ self.sd.on_sd_status_changed('name', 'description', False, True,
2339+ False, 'queues', 'connection')
2340+ self.sd.on_sd_status_changed('name', 'description', False, False,
2341+ False, 'queues', 'connection')
2342 self.assertTrue(self.called)
2343
2344 def test_on_online(self):
2345@@ -639,10 +544,8 @@
2346 self.flag_called(self.sd, 'on_online_callback')
2347
2348 # first signal with online in True
2349- d = dict(name='name', description='description', is_error='',
2350- is_connected='True', is_online='True', queues='queues',
2351- connection='connection')
2352- self.sd._on_status_changed(d)
2353+ self.sd.on_sd_status_changed('name', 'description', False, True,
2354+ True, 'queues', 'connection')
2355 self.assertTrue(self.called)
2356
2357 def test_on_offline(self):
2358@@ -650,52 +553,23 @@
2359 self.flag_called(self.sd, 'on_offline_callback')
2360
2361 # go online and then offline
2362- d = dict(name='name', description='description', is_error='',
2363- is_connected='True', is_online='True', queues='queues',
2364- connection='connection')
2365- self.sd._on_status_changed(d)
2366- d['is_online'] = ''
2367- self.sd._on_status_changed(d)
2368+ self.sd.on_sd_status_changed('name', 'description', False, True,
2369+ True, 'queues', 'connection')
2370+ self.sd.on_sd_status_changed('name', 'description', False, True,
2371+ False, 'queues', 'connection')
2372 self.assertTrue(self.called)
2373
2374
2375-class MementoHandler(logging.Handler):
2376- """A handler class which store logging records in a list."""
2377-
2378- def __init__(self, *args, **kwargs):
2379- """Create the instance, and add a records attribute."""
2380- logging.Handler.__init__(self, *args, **kwargs)
2381- self.records = []
2382-
2383- def emit(self, record):
2384- """Just add the record to self.records."""
2385- self.records.append(record)
2386-
2387- def check(self, level, msg):
2388- """Check that something is logged."""
2389- for rec in self.records:
2390- if rec.levelname == level and rec.message == msg:
2391- return True
2392- raise ValueError("Log not found (%s) %r" % (level, msg))
2393-
2394
2395 class TestLogs(unittest.TestCase):
2396 """Test logging."""
2397
2398 def setUp(self):
2399 """Set up."""
2400- self.handler = MementoHandler()
2401- logging.getLogger('magicicada.syncdaemon').addHandler(self.handler)
2402- self.handler.setLevel(logging.DEBUG)
2403- self.sd = SyncDaemon()
2404-
2405- # don't use real SD!
2406- self.sd._get_content_queue = lambda: defer.Deferred()
2407- self.sd._get_meta_queue = lambda: defer.Deferred()
2408- self.sd._do_start = NO_OP
2409- self.sd._do_quit = NO_OP
2410- self.sd._do_connect = NO_OP
2411- self.sd._do_disconnect = NO_OP
2412+ self.hdlr = MementoHandler()
2413+ logging.getLogger('magicicada.syncdaemon').addHandler(self.hdlr)
2414+ self.hdlr.setLevel(logging.DEBUG)
2415+ self.sd = SyncDaemon(FakeDBusInterface)
2416
2417 def tearDown(self):
2418 """Shut down!"""
2419@@ -703,100 +577,109 @@
2420
2421 def test_instancing(self):
2422 """Just logged SD instancing."""
2423- self.assertTrue(self.handler.check('INFO',
2424- "SyncDaemon interface started!"))
2425+ self.assertTrue(self.hdlr.check_inf("SyncDaemon interface started!"))
2426
2427 def test_shutdown(self):
2428 """Log when SD shutdowns."""
2429 self.sd.shutdown()
2430- self.assertTrue(self.handler.check('INFO',
2431- "SyncDaemon interface going down"))
2432+ self.assertTrue(self.hdlr.check_inf("SyncDaemon interface going down"))
2433+
2434+ @defer.inlineCallbacks
2435+ def test_initial_value(self):
2436+ """Log the initial filling."""
2437+ yield self.sd._get_initial_data()
2438+ self.assertTrue(self.hdlr.check_inf("Getting initial data"))
2439
2440 def test_start(self):
2441 """Log the call to start."""
2442 self.sd.start()
2443- self.assertTrue(self.handler.check('INFO',
2444- "Starting u1.SD"))
2445+ self.assertTrue(self.hdlr.check_inf("Starting u1.SD"))
2446
2447 def test_quit(self):
2448 """Log the call to quit."""
2449 self.sd.quit()
2450- self.assertTrue(self.handler.check('INFO',
2451- "Stopping u1.SD"))
2452+ self.assertTrue(self.hdlr.check_inf("Stopping u1.SD"))
2453
2454 def test_connect(self):
2455 """Log the call to connect."""
2456 self.sd.connect()
2457- self.assertTrue(self.handler.check('INFO',
2458- "Telling u1.SD to connect"))
2459+ self.assertTrue(self.hdlr.check_inf("Telling u1.SD to connect"))
2460
2461 def test_disconnect(self):
2462 """Log the call to disconnect."""
2463 self.sd.disconnect()
2464- self.assertTrue(self.handler.check('INFO',
2465- "Telling u1.SD to disconnect"))
2466+ self.assertTrue(self.hdlr.check_inf("Telling u1.SD to disconnect"))
2467
2468 def test_check_mq_true(self):
2469 """Log the MQ check when it asks for info."""
2470 self.sd.current_state._set(name='QUEUE_MANAGER',
2471 queues='WORKING_ON_METADATA')
2472 self.sd._check_mq()
2473- self.assertTrue(self.handler.check('INFO',
2474- "Asking for MQ information"))
2475+ self.assertTrue(self.hdlr.check_inf("Asking for MQ information"))
2476
2477 def test_check_mq_noreally(self):
2478 """Log the MQ check when it should not work."""
2479 self.sd.current_state._set(name='QUEUE_MANAGER',
2480 queues='WORKING_ON_CONTENT')
2481 self.sd._check_mq()
2482- self.assertTrue(self.handler.check('INFO',
2483+ self.assertTrue(self.hdlr.check_inf(
2484 "Check MQ called but States not in MQ"))
2485
2486- def test_process_mq_called(self):
2487- """Log that process_mq is called."""
2488- self.sd._process_mq([])
2489- self.assertTrue(self.handler.check('INFO', "Processing MQ data"))
2490-
2491- def test_process_mq_new_data(self):
2492- """Log that process_mq has new data."""
2493- self.sd._process_mq(['AccountInquiry'])
2494- self.assertTrue(self.handler.check('INFO', "New MQ data to process"))
2495- self.assertTrue(self.handler.check('DEBUG',
2496- "Processing MQ data: u'AccountInquiry'"))
2497- self.assertTrue(self.handler.check('DEBUG',
2498- " parsed: QueueData(operation="
2499- "'AccountInquiry', path=None, share=None, node=None)"))
2500-
2501- def test_process_cq_called(self):
2502- """Log that process_cq is called."""
2503- self.sd._process_cq([])
2504- self.assertTrue(self.handler.check('INFO', "Processing CQ data"))
2505-
2506- def test_process_cq_new_data(self):
2507+ def test_meta_queue_changed(self):
2508+ """Log that MQ has new data."""
2509+ self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
2510+ self.sd.current_state._set(name='QUEUE_MANAGER',
2511+ queues='WORKING_ON_METADATA')
2512+ self.sd._check_mq()
2513+ self.assertTrue(self.hdlr.check_inf("SD Meta Queue changed: 1 items"))
2514+
2515+ def test_content_queue_changed(self):
2516 """Log that process_cq has new data."""
2517- c = dict(operation='op', path='pth', share='shr', node='n')
2518- self.sd._process_cq([c])
2519- self.assertTrue(self.handler.check('INFO', "New CQ data to process"))
2520- self.assertTrue(self.handler.check('DEBUG',
2521- "Processing CQ data: %r" % c))
2522+ self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
2523+ self.sd.on_sd_content_queue_changed()
2524+ self.assertTrue(self.hdlr.check_inf("SD Content Queue changed"))
2525+ self.assertTrue(self.hdlr.check_inf(
2526+ "Content Queue info is new! 1 items"))
2527
2528 def test_on_status_changed(self):
2529 """Log status changed."""
2530- d = dict(name='name', description='description', is_error='',
2531- is_connected='True', is_online='', queues='queues',
2532- connection='connection')
2533- self.sd._on_status_changed(d)
2534- self.assertTrue(self.handler.check('INFO', "New status info from SD"))
2535- self.assertTrue(self.handler.check('DEBUG',
2536- "New status from SD: %r" % d))
2537+ self.sd.on_sd_status_changed('name', 'description', False, True,
2538+ False, 'queues', 'connection')
2539+ self.assertTrue(self.hdlr.check_inf("SD Status changed"))
2540+ self.assertTrue(self.hdlr.check_dbg(" new status: name=u'name', "
2541+ "description=u'description', is_error=False, is_connected=True, "
2542+ "is_online=False, queues=u'queues', connection=u'connection'"))
2543
2544- def test_on_content_queue_changed(self):
2545- """Log content queue changed."""
2546- self.sd._on_content_queue_changed(None)
2547- self.assertTrue(self.handler.check('INFO', "CQ changed in u1.SD!"))
2548+ def test_folders_changed(self):
2549+ """Log when folders changed."""
2550+ self.sd.on_sd_folders_changed()
2551+ self.assertTrue(self.hdlr.check_inf("SD Folders changed"))
2552
2553 def test_on_name_owner_changed(self):
2554 """Log name owner changed."""
2555- self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'old', '')
2556- self.assertTrue(self.handler.check('INFO',
2557- "DBus informing about SD: old: u'old' new: u''"))
2558+ self.sd.on_sd_name_owner_changed(True)
2559+ self.assertTrue(self.hdlr.check_inf("SD Name Owner changed: True"))
2560+
2561+
2562+class FoldersTests(BaseTest):
2563+ """Folders checking."""
2564+
2565+ def test_foldercreated_callback(self):
2566+ """Gets the new data after the folders changed."""
2567+ # set the callback
2568+ called = []
2569+ self.sd.dbus.get_folders = lambda: called.append(True)
2570+
2571+ # they changed!
2572+ self.sd.on_sd_folders_changed()
2573+
2574+ # test
2575+ self.assertTrue(called)
2576+
2577+ @defer.inlineCallbacks
2578+ def test_initial_value(self):
2579+ """Fills the folder info initially."""
2580+ called = []
2581+ self.sd.dbus.get_folders = lambda: called.append(True)
2582+ yield self.sd._get_initial_data()
2583+ self.assertTrue(called)

Subscribers

People subscribed via source and target branches