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
=== added file 'magicicada/dbusiface.py'
--- magicicada/dbusiface.py 1970-01-01 00:00:00 +0000
+++ magicicada/dbusiface.py 2010-05-27 20:56:26 +0000
@@ -0,0 +1,288 @@
1# dbusiface.py
2#
3# Author: Facundo Batista <facundo@taniquetil.com.ar>
4#
5# Copyright 2010 Chicharreros
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""The DBus Interface."""
20
21import collections
22import logging
23import re
24import sys
25
26import dbus
27from dbus import SessionBus
28from dbus.mainloop.glib import DBusGMainLoop
29
30from ubuntuone.syncdaemon.tools import SyncDaemonTool
31
32# log!
33logger = logging.getLogger('magicicada.dbusiface')
34handler = logging.StreamHandler(sys.stdout)
35logger.addHandler(handler)
36formatter = logging.Formatter("%(asctime)s %(name)s:%(lineno)-4d "
37 "%(levelname)-8s %(message)s",
38 '%Y-%m-%d %H:%M:%S')
39handler.setFormatter(formatter)
40logger.setLevel(logging.DEBUG)
41
42
43QueueData = collections.namedtuple('QueueData', 'operation path share node')
44FolderData = collections.namedtuple('FolderData',
45 'node path suggested_path subscribed volume')
46
47# regular expressions for parsing MetaQueue data
48RE_OP_LISTDIR = re.compile("(ListDir)\(share_id=(.*?), node_id=(.*?), .*")
49RE_OP_UNLINK = re.compile("(Unlink)\(share_id=(.*?), node_id=(.*?), .*")
50RE_OP_MAKEFILE = re.compile(
51 "(MakeFile)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
52RE_OP_MAKEDIR = re.compile(
53 "(MakeDir)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
54RE_OP_MOVE = re.compile(
55 "(Move)\(share_id=(.*?), node_id=(.*?), old_parent_id=(.*?), "
56 "new_parent_id=(.*?), new_name=(.*?)\)")
57
58
59class DBusInterface(object):
60 """The DBus Interface to Ubuntu One's SyncDaemon."""
61
62 def __init__(self, msd):
63 # magicicada's syncdaemon
64 self.msd = msd
65 logger.info("DBus interface starting")
66
67 # set up dbus and related stuff
68 loop = DBusGMainLoop(set_as_default=True)
69 self._bus = bus = SessionBus(mainloop=loop)
70 self.sync_daemon_tool = SyncDaemonTool(bus)
71
72 # hook up for signals and store info for the shutdown
73 _signals = [
74 (self._on_status_changed, 'Status', 'StatusChanged'),
75 (self._on_content_queue_changed, 'Status', 'ContentQueueChanged'),
76 (self._on_name_owner_changed, None, 'NameOwnerChanged'),
77 (self._on_folder_created, 'Folders', 'FolderCreated'),
78 (self._on_folder_deleted, 'Folders', 'FolderDeleted'),
79 ]
80 self._dbus_matches = []
81 for method, dbus_lastname, signal_name in _signals:
82 if dbus_lastname is None:
83 dbus_interface = None
84 else:
85 dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname
86 match = bus.add_signal_receiver(method,
87 dbus_interface=dbus_interface,
88 signal_name=signal_name)
89 self._dbus_matches.append((match, dbus_interface, signal_name))
90
91
92 def shutdown(self):
93 """Shut down the SyncDaemon."""
94 logger.info("DBus interface going down")
95
96 # remove the signals from DBus
97 remove = self._bus.remove_signal_receiver
98 for match, dbus_interface, signal in self._dbus_matches:
99 remove(match, dbus_interface=dbus_interface, signal_name=signal)
100
101 def _process_status(self, state):
102 """Transform status information."""
103 name = state['name']
104 description = state['description']
105 is_error = bool(state['is_error'])
106 is_connected = bool(state['is_connected'])
107 is_online = bool(state['is_online'])
108 queues = state['queues']
109 connection = state['connection']
110 return (name, description, is_error, is_connected,
111 is_online, queues, connection)
112
113 def get_status(self):
114 """Gets SD status."""
115 logger.info("Getting status")
116 d = self.sync_daemon_tool.get_status()
117 d.addCallback(self._process_status)
118 return d
119
120 def _on_status_changed(self, state):
121 """Call the SD callback."""
122 logger.info("Received Status changed")
123 logger.debug("Status changed data: %r", state)
124 data = self._process_status(state)
125 self.msd.on_sd_status_changed(*data)
126
127 def _on_content_queue_changed(self, _):
128 """Call the SD callback."""
129 logger.info("Received Content Queue changed")
130 self.msd.on_sd_content_queue_changed()
131
132 def _on_name_owner_changed(self, name, oldowner, newowner):
133 """Receive the NameOwnerChanged signal from DBus."""
134 if name != 'com.ubuntuone.SyncDaemon':
135 return
136
137 logger.info("Received Name Owner changed")
138 logger.debug("Name Owner data: %r %r", oldowner, newowner)
139 old = bool(oldowner)
140 new = bool(newowner)
141 if old == new:
142 logger.error("Name Owner invalid data: Same bool in old and new!")
143 return
144 self.msd.on_sd_name_owner_changed(new)
145
146 def _on_folder_created(self, _):
147 """Call the SD callback."""
148 logger.info("Received Folder created")
149 self.msd.on_sd_folders_changed()
150
151 def _on_folder_deleted(self, _):
152 """Call the SD callback."""
153 logger.info("Received Folder deleted")
154 self.msd.on_sd_folders_changed()
155
156 def get_content_queue(self):
157 """Get the content queue from SDT."""
158 def process(data):
159 """Enhance data format."""
160 logger.info("Processing Content Queue items (%d)", len(data))
161 all_items = []
162 for d in data:
163 logger.debug(" Content Queue data: %r", d)
164 cq = QueueData(operation=d['operation'], path=d['path'],
165 node=d['node'], share=d['share'])
166 all_items.append(cq)
167 return all_items
168
169 logger.info("Getting content queue")
170 d = self.sync_daemon_tool.waiting_content()
171 d.addCallback(process)
172 return d
173
174 def _parse_mq(self, data):
175 """Parse MetaQueue string to extract its data."""
176 if data in ('AccountInquiry', 'FreeSpaceInquiry', 'GetPublicFiles',
177 'ListShares', 'ListVolumes', 'Query'):
178 return QueueData(operation=data, path=None, node=None, share=None)
179
180 m = RE_OP_LISTDIR.match(data)
181 if m:
182 op, share, node = m.groups()
183 path = '?' # we should get the real path, no API now
184 return QueueData(operation=op, path=path, node=node, share=share)
185
186 m = RE_OP_MAKEFILE.match(data)
187 if m:
188 op, share, parent, name = m.groups()
189 path = '/?.../' + name # we should get the real path, no API now
190 return QueueData(operation=op, path=path, node=None, share=share)
191
192 m = RE_OP_MAKEDIR.match(data)
193 if m:
194 op, share, parent, name = m.groups()
195 path = '/?.../' + name # we should get the real path, no API now
196 return QueueData(operation=op, path=path, node=None, share=share)
197
198 m = RE_OP_UNLINK.match(data)
199 if m:
200 op, share, node, = m.groups()
201 path = '?' # we should get the real path, no API now
202 return QueueData(operation=op, path=path, node=node, share=share)
203
204 m = RE_OP_MOVE.match(data)
205 if m:
206 op, share, node, old_parent, new_parent, new_name, = m.groups()
207
208 # we should get the real info, no API now
209 old_path = '/?...'
210 old_name = '?'
211 new_path = '/?...'
212 composed_path = "%s/%s -> %s/%s" % (old_path, old_name,
213 new_path, new_name)
214 return QueueData(operation=op, path=composed_path,
215 node=node, share=share)
216
217 raise ValueError("Not supported MetaQueue data: %r" % data)
218
219 def get_meta_queue(self):
220 """Get the meta queue from SDT."""
221 def process(data):
222 """Enhance data format."""
223 logger.info("Processing Meta Queue items (%d)", len(data))
224 all_items = []
225 for d in data:
226 logger.debug(" Meta Queue data: %r", d)
227 parsed = self._parse_mq(d)
228 all_items.append(parsed)
229 return all_items
230
231 logger.info("Getting meta queue")
232 d = self.sync_daemon_tool.waiting_metadata()
233 d.addCallback(process)
234 return d
235
236 def get_folders(self):
237 """Get the folders info from SDT."""
238 def process(data):
239 """Enhance data format."""
240 logger.info("Processing Folders items (%d)", len(data))
241 all_items = []
242 for d in data:
243 logger.debug(" Folders data: %r", d)
244 f = FolderData(node=d['node_id'], path=d['path'],
245 suggested_path=d['suggested_path'],
246 volume=d['volume_id'],
247 subscribed=bool(d['subscribed']))
248 all_items.append(f)
249 return all_items
250
251 logger.info("Getting folders")
252 d = self.sync_daemon_tool.get_folders()
253 d.addCallback(process)
254 return d
255
256 def start(self):
257 """Start SDT."""
258 logger.info("Calling start")
259 self.sync_daemon_tool.start()
260
261 def quit(self):
262 """Stop SDT."""
263 logger.info("Calling quit")
264 self.sync_daemon_tool.quit()
265
266 def connect(self):
267 """Connect SDT."""
268 logger.info("Calling connect")
269 self.sync_daemon_tool.connect()
270
271 def disconnect(self):
272 """Disconnect SDT."""
273 logger.info("Calling disconnect")
274 self.sync_daemon_tool.disconnect()
275
276 def is_sd_started(self):
277 """Find out if SD is active in the system."""
278 try:
279 self._bus.get_name_owner('com.ubuntuone.SyncDaemon')
280 except dbus.exceptions.DBusException, err:
281 if err.get_dbus_name() != \
282 'org.freedesktop.DBus.Error.NameHasNoOwner':
283 raise
284 started = False
285 else:
286 started = True
287 logger.info("Checking if SD is started: %s", started)
288 return started
0289
=== modified file 'magicicada/syncdaemon.py'
--- magicicada/syncdaemon.py 2010-05-23 10:23:35 +0000
+++ magicicada/syncdaemon.py 2010-05-27 20:56:26 +0000
@@ -18,17 +18,12 @@
1818
19"""The backend that communicates Magicicada with the SyncDaemon."""19"""The backend that communicates Magicicada with the SyncDaemon."""
2020
21import collections
22import logging21import logging
23import re
24import sys22import sys
2523
26import dbus24from twisted.internet import defer, reactor
27from dbus.mainloop.glib import DBusGMainLoop25
28from twisted.internet import reactor26from magicicada.dbusiface import DBusInterface
29
30from ubuntuone.syncdaemon import tools
31
32from magicicada.helpers import NO_OP27from magicicada.helpers import NO_OP
3328
34# log!29# log!
@@ -41,19 +36,6 @@
41handler.setFormatter(formatter)36handler.setFormatter(formatter)
42logger.setLevel(logging.DEBUG)37logger.setLevel(logging.DEBUG)
4338
44# regular expressions for parsing MetaQueue data
45RE_OP_LISTDIR = re.compile("(ListDir)\(share_id=(.*?), node_id=(.*?), .*")
46RE_OP_UNLINK = re.compile("(Unlink)\(share_id=(.*?), node_id=(.*?), .*")
47RE_OP_MAKEFILE = re.compile(
48 "(MakeFile)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
49RE_OP_MAKEDIR = re.compile(
50 "(MakeDir)\(share_id=(.*?), parent_id=(.*?), name=(.*?), .*")
51RE_OP_MOVE = re.compile(
52 "(Move)\(share_id=(.*?), node_id=(.*?), old_parent_id=(.*?), "
53 "new_parent_id=(.*?), new_name=(.*?)\)")
54
55# structure that hold content and queue information
56QueueData = collections.namedtuple('QueueData', 'operation path share node')
5739
58class State(object):40class State(object):
59 """Holds the state of SD."""41 """Holds the state of SD."""
@@ -96,29 +78,17 @@
96class SyncDaemon(object):78class SyncDaemon(object):
97 """Interface to Ubuntu One's SyncDaemon."""79 """Interface to Ubuntu One's SyncDaemon."""
9880
99 def __init__(self):81 def __init__(self, dbus_class=DBusInterface):
82 logger.info("SyncDaemon interface started!")
83
100 # set up dbus and related stuff84 # set up dbus and related stuff
101 loop = DBusGMainLoop(set_as_default=True)85 self.dbus = dbus_class(self)
102 self._bus = bus = dbus.SessionBus(mainloop=loop)86
103 self.sync_daemon_tool = tools.SyncDaemonTool(bus)87 # attributes for GUI, definition and filling
104 self.current_state = State()88 self.current_state = State()
10589 self.folders = None
106 # hook up for signals and store info for the shutdown90 self.content_queue = None
107 _signals = [91 self.meta_queue = None
108 (self._on_status_changed, 'Status', 'StatusChanged'),
109 (self._on_content_queue_changed, 'Status', 'ContentQueueChanged'),
110 (self._on_name_owner_changed, None, 'NameOwnerChanged'),
111 ]
112 self._dbus_matches = []
113 for method, dbus_lastname, signal_name in _signals:
114 if dbus_lastname is None:
115 dbus_interface = None
116 else:
117 dbus_interface = 'com.ubuntuone.SyncDaemon.' + dbus_lastname
118 match = bus.add_signal_receiver(method,
119 dbus_interface=dbus_interface,
120 signal_name=signal_name)
121 self._dbus_matches.append((match, dbus_interface, signal_name))
12292
123 # callbacks for GUI to hook in93 # callbacks for GUI to hook in
124 self.status_changed_callback = NO_OP94 self.status_changed_callback = NO_OP
@@ -131,70 +101,69 @@
131 self.on_online_callback = NO_OP101 self.on_online_callback = NO_OP
132 self.on_offline_callback = NO_OP102 self.on_offline_callback = NO_OP
133103
134 # calls to obtain data from SDT
135 self._get_content_queue = self.sync_daemon_tool.waiting_content
136 self._get_meta_queue = self.sync_daemon_tool.waiting_metadata
137 self._do_start = self.sync_daemon_tool.start
138 self._do_quit = self.sync_daemon_tool.quit
139 self._do_connect = self.sync_daemon_tool.connect
140 self._do_disconnect = self.sync_daemon_tool.disconnect
141
142 # previous data
143 self._last_CQ_data = None
144 self._last_MQ_data = None
145
146 # mq needs to be polled to know progress104 # mq needs to be polled to know progress
147 self._mqcaller = None105 self._mqcaller = None
148 self._mq_poll_time = 5 # seconds106 self._mq_poll_time = 5 # seconds
149107
150 # let's log!108 # load initial data if ubuntuone-client already started
151 logger.info("SyncDaemon interface started!")109 if self.dbus.is_sd_started():
110 self._get_initial_data()
152111
153112
154 def shutdown(self):113 def shutdown(self):
155 """Shut down the SyncDaemon."""114 """Shut down the SyncDaemon."""
156 logger.info("SyncDaemon interface going down")115 logger.info("SyncDaemon interface going down")
157116 self.dbus.shutdown()
158 # remove the signals from DBus
159 remove = self._bus.remove_signal_receiver
160 for match, dbus_interface, signal in self._dbus_matches:
161 remove(match, dbus_interface=dbus_interface, signal_name=signal)
162117
163 # cancel the mq polling caller, if any118 # cancel the mq polling caller, if any
164 if self._mqcaller is not None and self._mqcaller.active():119 if self._mqcaller is not None and self._mqcaller.active():
165 self._mqcaller.cancel()120 self._mqcaller.cancel()
166121
167 def _on_name_owner_changed(self, name, oldowner, newowner):122 @defer.inlineCallbacks
168 """Receives the NameOwnerChanged signal from DBus."""123 def _get_initial_data(self):
169 if name == 'com.ubuntuone.SyncDaemon':124 """Gets the initial SD data."""
170 logger.info("DBus informing about SD: old: %r new: %r",125 logger.info("Getting initial data")
171 oldowner, newowner)126
172127 status_data = yield self.dbus.get_status()
173 old = bool(oldowner)128 self._send_status_changed(*status_data)
174 new = bool(newowner)129
175 if old == new:130 self.content_queue = yield self.dbus.get_content_queue()
176 raise ValueError("Owners should have changed! Old: %r "131 self.content_queue_changed_callback(self.content_queue)
177 "New: %r" % (oldowner, newowner))132
178 self.current_state._set(is_started=new)133 self.meta_queue = yield self.dbus.get_meta_queue()
179 if new:134 self.meta_queue_changed_callback(self.meta_queue)
180 self.on_started_callback()135
181 else:136 self.folders = yield self.dbus.get_folders()
182 self.on_stopped_callback()137
183138 @defer.inlineCallbacks
184 def _on_status_changed(self, state):139 def on_sd_folders_changed(self):
185 """Receives the StatusChanged signal and send its data."""140 """Folders changed, ask for new information."""
186 logger.info("New status info from SD")141 logger.info("SD Folders changed")
187 logger.debug("New status from SD: %r", state)142 self.folders = yield self.dbus.get_folders()
188143
189 name = state['name']144 def on_sd_name_owner_changed(self, now_active):
190 description = state['description']145 """SyncDaemon name owner changed."""
191 is_error = bool(state['is_error'])146 logger.info("SD Name Owner changed: %s", now_active)
192 is_connected = bool(state['is_connected'])147 self.current_state._set(is_started=now_active)
193 is_online = bool(state['is_online'])148 if now_active:
194 queues = state['queues']149 self.on_started_callback()
195 connection = state['connection']150 self._get_initial_data()
196151 else:
197 # check status changes to call callbacks152 self.on_stopped_callback()
153
154 def on_sd_status_changed(self, *status_data):
155 """The Status of SD changed.."""
156 logger.info("SD Status changed")
157 self._send_status_changed(*status_data)
158
159 def _send_status_changed(self, name, description, is_error, is_connected,
160 is_online, queues, connection):
161 logger.debug(" new status: name=%r, description=%r, is_error=%s, "
162 "is_connected=%s, is_online=%s, queues=%r, connection=%r",
163 name, description, is_error, is_connected, is_online,
164 queues, connection)
165
166 # check status changes to call other callbacks
198 if is_connected and not self.current_state.is_connected:167 if is_connected and not self.current_state.is_connected:
199 self.on_connected_callback()168 self.on_connected_callback()
200 if not is_connected and self.current_state.is_connected:169 if not is_connected and self.current_state.is_connected:
@@ -204,168 +173,70 @@
204 if not is_online and self.current_state.is_online:173 if not is_online and self.current_state.is_online:
205 self.on_offline_callback()174 self.on_offline_callback()
206175
207
208 # set current state to new values and call status changed cb176 # set current state to new values and call status changed cb
209 self.current_state._set(**state)177 self.current_state._set(name=name, description=description,
210 self.status_changed_callback(name, description, is_error,178 is_error=is_error, is_connected=is_connected,
211 is_connected, is_online,179 is_online=is_online, queues=queues,
212 queues, connection)180 connection=connection)
181 self.status_changed_callback(name, description, is_error, is_connected,
182 is_online, queues, connection)
213183
214 # if corresponds, supervise MQ184 # if corresponds, supervise MQ
215 self._check_mq()185 self._check_mq()
216186
217 def _generate_cq_info(self, data):187 @defer.inlineCallbacks
218 """Genereates an api friendly version of the data."""188 def on_sd_content_queue_changed(self):
219 all_items = []189 """Content Queue changed, ask for new information."""
220 for d in data:190 logger.info("SD Content Queue changed")
221 logger.debug("Processing CQ data: %r", d)191 new_cq = yield self.dbus.get_content_queue()
222 cq = QueueData(operation=d['operation'], path=d['path'],192 if new_cq != self.content_queue:
223 node=d['node'], share=d['share'])193 logger.info("Content Queue info is new! %d items", len(new_cq))
224 all_items.append(cq)194 self.content_queue = new_cq
225 return all_items195 self.content_queue_changed_callback(new_cq)
226196
227 @property197 @defer.inlineCallbacks
228 def content_queue(self):
229 """Returns the last known CQ info."""
230 if self._last_CQ_data is None:
231 return []
232 else:
233 return self._generate_cq_info(self._last_CQ_data)
234
235 def _process_cq(self, data):
236 """Processes ContentQueue data."""
237 # if same data than before, abort notification; else store it for later
238 logger.info("Processing CQ data")
239 if data == self._last_CQ_data:
240 return
241 self._last_CQ_data = data
242 logger.info("New CQ data to process")
243
244 all_items = self._generate_cq_info(data)
245 self.content_queue_changed_callback(all_items)
246
247 def _on_content_queue_changed(self, _):
248 """Receives the ContentQueueChanged signal and finds real data."""
249 logger.info("CQ changed in u1.SD!")
250
251 # get the info
252 d = self._get_content_queue()
253 d.addCallback(self._process_cq)
254
255 @property
256 def meta_queue(self):
257 """Returns the last known MQ info."""
258 if self._last_MQ_data is None:
259 return []
260 else:
261 all_items = []
262 for d in self._last_MQ_data:
263 all_items.append(self._parse_mq(d))
264 return all_items
265
266 def _parse_mq(self, data):
267 """Parse MetaQueue string to extract its data."""
268 if data in ('AccountInquiry', 'FreeSpaceInquiry', 'GetPublicFiles',
269 'ListShares', 'ListVolumes', 'Query'):
270 return QueueData(operation=data, path=None, node=None, share=None)
271
272 m = RE_OP_LISTDIR.match(data)
273 if m:
274 op, share, node = m.groups()
275 path = '?' # we should get the real path, no API now
276 return QueueData(operation=op, path=path, node=node, share=share)
277
278 m = RE_OP_MAKEFILE.match(data)
279 if m:
280 op, share, parent, name = m.groups()
281 path = '/?.../' + name # we should get the real path, no API now
282 return QueueData(operation=op, path=path, node=None, share=share)
283
284 m = RE_OP_MAKEDIR.match(data)
285 if m:
286 op, share, parent, name = m.groups()
287 path = '/?.../' + name # we should get the real path, no API now
288 return QueueData(operation=op, path=path, node=None, share=share)
289
290 m = RE_OP_UNLINK.match(data)
291 if m:
292 op, share, node, = m.groups()
293 path = '?' # we should get the real path, no API now
294 return QueueData(operation=op, path=path, node=node, share=share)
295
296 m = RE_OP_MOVE.match(data)
297 if m:
298 op, share, node, old_parent, new_parent, new_name, = m.groups()
299
300 # we should get the real info, no API now
301 old_path = '/?...'
302 old_name = '?'
303 new_path = '/?...'
304 composed_path = "%s/%s -> %s/%s" % (old_path, old_name,
305 new_path, new_name)
306 return QueueData(operation=op, path=composed_path,
307 node=node, share=share)
308
309 raise ValueError("Not supported MetaQueue data: %r" % data)
310
311 def _process_mq(self, data):
312 """Processes MetaQueue data."""
313 # if same data than before, abort notification; else store it for later
314 logger.info("Processing MQ data")
315 if data == self._last_MQ_data:
316 return
317 self._last_MQ_data = data
318 logger.info("New MQ data to process")
319
320 all_items = []
321 for d in data:
322 logger.debug("Processing MQ data: %r", d)
323 parsed = self._parse_mq(d)
324 logger.debug(" parsed: %s", parsed)
325 all_items.append(parsed)
326
327 self.meta_queue_changed_callback(all_items)
328
329 def _on_meta_queue_changed(self):
330 """Finds real data about meta queue."""
331 d = self._get_meta_queue()
332 d.addCallback(self._process_mq)
333
334 def _check_mq(self):198 def _check_mq(self):
335 """Check MQ if we should."""199 """Check MQ if we should."""
336 # check if we have something to show in MQ!200 state = self.current_state
337 if self.current_state.name != 'QUEUE_MANAGER' or \201 if state.name != 'QUEUE_MANAGER' or \
338 self.current_state.queues not in (202 state.queues not in ('WORKING_ON_METADATA', 'WORKING_ON_BOTH'):
339 'WORKING_ON_METADATA', 'WORKING_ON_BOTH'):
340 logger.info("Check MQ called but States not in MQ")203 logger.info("Check MQ called but States not in MQ")
341 return204 else:
342205 logger.info("Asking for MQ information")
343 # we have a previous call later running?206
344 if self._mqcaller is not None and self._mqcaller.active():207 # have we a previous call later still running?
345 self._mqcaller.cancel()208 if self._mqcaller is not None and self._mqcaller.active():
346209 self._mqcaller.cancel()
347 # get the info a programa210
348 logger.info("Asking for MQ information")211 # get the info
349 d = self._get_meta_queue()212 new_mq = yield self.dbus.get_meta_queue()
350 d.addCallback(self._process_mq)213
351 self._mqcaller = reactor.callLater(self._mq_poll_time, self._check_mq)214 if new_mq != self.meta_queue:
215 logger.info("SD Meta Queue changed: %d items", len(new_mq))
216 self.meta_queue = new_mq
217 self.meta_queue_changed_callback(new_mq)
218
219 # check again later
220 self._mqcaller = reactor.callLater(self._mq_poll_time,
221 self._check_mq)
352222
353 def start(self):223 def start(self):
354 """Starts the SyncDaemon."""224 """Starts the SyncDaemon."""
355 logger.info("Starting u1.SD")225 logger.info("Starting u1.SD")
356 self._do_start()226 self.dbus.start()
227 self._get_initial_data()
357228
358 def quit(self):229 def quit(self):
359 """Stops the SyncDaemon and makes it quit."""230 """Stops the SyncDaemon and makes it quit."""
360 logger.info("Stopping u1.SD")231 logger.info("Stopping u1.SD")
361 self._do_quit()232 self.dbus.quit()
362233
363 def connect(self):234 def connect(self):
364 """Tells the SyncDaemon that the user wants it to connect."""235 """Tells the SyncDaemon that the user wants it to connect."""
365 logger.info("Telling u1.SD to connect")236 logger.info("Telling u1.SD to connect")
366 self._do_connect()237 self.dbus.connect()
367238
368 def disconnect(self):239 def disconnect(self):
369 """Tells the SyncDaemon that the user wants it to disconnect."""240 """Tells the SyncDaemon that the user wants it to disconnect."""
370 logger.info("Telling u1.SD to disconnect")241 logger.info("Telling u1.SD to disconnect")
371 self._do_disconnect()242 self.dbus.disconnect()
372243
=== added file 'magicicada/tests/helpers.py'
--- magicicada/tests/helpers.py 1970-01-01 00:00:00 +0000
+++ magicicada/tests/helpers.py 2010-05-27 20:56:26 +0000
@@ -0,0 +1,49 @@
1# Helpers for the tessts
2#
3# Author: Facundo Batista <facundo@taniquetil.com.ar>
4#
5# Copyright 2010 Chicharreros
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Helpers for the tests."""
20
21import logging
22
23
24class MementoHandler(logging.Handler):
25 """A handler class which store logging records in a list."""
26
27 def __init__(self, *args, **kwargs):
28 """Create the instance, and add a records attribute."""
29 logging.Handler.__init__(self, *args, **kwargs)
30 self.records = []
31
32 def emit(self, record):
33 """Just add the record to self.records."""
34 self.records.append(record)
35
36 def check(self, level, msg):
37 """Check that something is logged."""
38 for rec in self.records:
39 if rec.levelname == level and rec.message == msg:
40 return True
41 return False
42
43 def check_inf(self, msg):
44 """Shortcut for INFO check."""
45 return self.check('INFO', msg)
46
47 def check_dbg(self, msg):
48 """Shortcut for DEBUG check."""
49 return self.check('DEBUG', msg)
050
=== added file 'magicicada/tests/test_dbusiface.py'
--- magicicada/tests/test_dbusiface.py 1970-01-01 00:00:00 +0000
+++ magicicada/tests/test_dbusiface.py 2010-05-27 20:56:26 +0000
@@ -0,0 +1,665 @@
1# Tests for the DBus interface
2#
3# Author: Facundo Batista <facundo@taniquetil.com.ar>
4#
5# Copyright 2010 Chicharreros
6#
7# This program is free software: you can redistribute it and/or modify it
8# under the terms of the GNU General Public License version 3, as published
9# by the Free Software Foundation.
10#
11# This program is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranties of
13# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14# PURPOSE. See the GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License along
17# with this program. If not, see <http://www.gnu.org/licenses/>.
18
19"""Tests for the DBus interce towards real syncdaemon."""
20
21import logging
22
23import dbus
24from twisted.trial.unittest import TestCase as TwistedTestCase
25from twisted.internet import defer
26
27from magicicada import dbusiface
28from magicicada.tests.helpers import MementoHandler
29
30
31class FakeSessionBus(object):
32 """Fake Session Bus."""
33 def __init__(self, **kwargs):
34 self._callbacks = {}
35 self.fake_name_owner = "foo"
36
37 def add_signal_receiver(self, method, dbus_interface, signal_name):
38 """Add a signal receiver."""
39 self._callbacks[(dbus_interface, signal_name)] = method
40
41 def remove_signal_receiver(self, match, dbus_interface, signal_name):
42 """Remove the signal receiver."""
43 del self._callbacks[(dbus_interface, signal_name)]
44
45 def get_name_owner(self, name):
46 """Fakes the response of the method."""
47 assert name == 'com.ubuntuone.SyncDaemon'
48 if isinstance(self.fake_name_owner, str):
49 return self.fake_name_owner
50 else:
51 raise self.fake_name_owner
52
53
54class CallLoguer(object):
55 """Class that logs the methods called."""
56 def __init__(self):
57 self._called_method = None, ()
58 self._fake_response = None
59
60 def __getattribute__(self, name):
61 """Return the value if there."""
62 if name[0] == "_":
63 return object.__getattribute__(self, name)
64 else:
65 def f(*args):
66 setattr(self, "_called_method", (name, args))
67 if self._fake_response is None:
68 # no hurt in returning a deferred, it may be needed
69 return defer.Deferred()
70 methname, response = self._fake_response
71 assert methname == name
72 return response
73 return f
74
75
76class FakeSDTool(CallLoguer):
77 """Fake real SyncDaemonTool."""
78 def __init__(self, _):
79 CallLoguer.__init__(self)
80
81
82class FakeSyncDaemon(CallLoguer):
83 """Fake Magicicada's SyncDaemon."""
84
85
86class SafeTests(TwistedTestCase):
87 """Safe tests not going outside the testing box."""
88
89 def setUp(self):
90 """Set up."""
91 dbusiface.SessionBus = FakeSessionBus
92 dbusiface.SyncDaemonTool = FakeSDTool
93 self.fsd = FakeSyncDaemon()
94 self.dbus = dbusiface.DBusInterface(self.fsd)
95
96 def check_sdt_called(self, name):
97 """Check that the SyncDaemonTool method was called."""
98 self.assertEqual(self.dbus.sync_daemon_tool._called_method[0], name)
99
100 def get_msd_called(self, name):
101 """Get the args from the called Magicicada's SyncDaemon method."""
102 called_method, called_args = self.fsd._called_method
103 self.assertEqual(called_method, name)
104 return called_args
105
106 def fake_sdt_response(self, method_name, response):
107 """Fakes SDT answer in deferred mode."""
108 self.dbus.sync_daemon_tool._fake_response = (method_name,
109 defer.succeed(response))
110
111class TestSignalHooking(SafeTests):
112 """Signal hooking tests.
113
114 We can not check if the methods are really called, because DBus holds the
115 method object itself, so no chance in monkeypatching.
116 """
117 def _get_hooked(self, iface, signal):
118 """Return the hooked method if any."""
119 if iface is None:
120 interface = None
121 else:
122 interface = 'com.ubuntuone.SyncDaemon.' + iface
123 return self.dbus._bus._callbacks.get((interface, signal))
124
125 def test_hook_unhook(self):
126 """Test the hooked signals are unhooked."""
127 self.dbus.shutdown()
128 self.assertEqual(self.dbus._bus._callbacks, {})
129
130 def test_status_changed(self):
131 """Test status changed callback."""
132 self.assertEqual(self._get_hooked('Status', 'StatusChanged'),
133 self.dbus._on_status_changed)
134
135 def test_content_queue_changed(self):
136 """Test content queue changed callback."""
137 self.assertEqual(self._get_hooked('Status', 'ContentQueueChanged'),
138 self.dbus._on_content_queue_changed)
139
140 def test_name_owner_changed(self):
141 """Test name owner changed callback."""
142 self.assertEqual(self._get_hooked(None, 'NameOwnerChanged'),
143 self.dbus._on_name_owner_changed)
144
145 def test_folder_created_changed(self):
146 """Test folder created changed callback."""
147 self.assertEqual(self._get_hooked('Folders', 'FolderCreated'),
148 self.dbus._on_folder_created)
149
150 def test_folder_deleted_changed(self):
151 """Test folder deleted changed callback."""
152 self.assertEqual(self._get_hooked('Folders', 'FolderDeleted'),
153 self.dbus._on_folder_deleted)
154
155
156class TestSimpleCalls(SafeTests):
157 """Tests for some simple calls."""
158
159 @defer.inlineCallbacks
160 def test_is_sd_started_yes(self):
161 """Test is SD started, yes."""
162 self.dbus._bus.fake_name_owner = 'some owner'
163 resp = yield self.dbus.is_sd_started()
164 self.assertTrue(resp)
165
166 @defer.inlineCallbacks
167 def test_is_sd_started_no(self):
168 """Test is SD started, no."""
169 self.dbus._bus.fake_name_owner = dbus.exceptions.DBusException(
170 name='org.freedesktop.DBus.Error.NameHasNoOwner')
171 resp = yield self.dbus.is_sd_started()
172 self.assertFalse(resp)
173
174
175class TestDataProcessingStatus(SafeTests):
176 """Processes Status before sending it to SyncDaemon."""
177
178 @defer.inlineCallbacks
179 def test_get_status(self):
180 """Test getting status."""
181 d = dict(name='n', description='d', is_error='', is_connected='True',
182 is_online='', queues='q', connection='c')
183 self.fake_sdt_response('get_status', d)
184 args = yield self.dbus.get_status()
185 name, descrip, error, connected, online, queues, connection = args
186 self.assertEqual(name, 'n')
187 self.assertEqual(descrip, 'd')
188 self.assertEqual(error, False)
189 self.assertEqual(connected, True)
190 self.assertEqual(online, False)
191 self.assertEqual(queues, 'q')
192 self.assertEqual(connection, 'c')
193
194 def test_status_changed(self):
195 """Test status changed callback."""
196 d = dict(name='name', description='description', is_error='',
197 is_connected='True', is_online='', queues='queues',
198 connection='connection')
199 self.dbus._on_status_changed(d)
200 args = self.get_msd_called("on_sd_status_changed")
201 name, descrip, error, connected, online, queues, connection = args
202 self.assertEqual(name, 'name')
203 self.assertEqual(descrip, 'description')
204 self.assertEqual(error, False)
205 self.assertEqual(connected, True)
206 self.assertEqual(online, False)
207 self.assertEqual(queues, 'queues')
208 self.assertEqual(connection, 'connection')
209
210
211class TestDataProcessingNameOwner(SafeTests):
212 """Processes Name Owner data before sending it to SyncDaemon."""
213
214 def test_name_owner_changed_no_syncdaemon(self):
215 """Test name owner changed callback."""
216 self.dbus._on_name_owner_changed("foo", "bar", "baz")
217 self.get_msd_called(None)
218
219 def test_name_owner_changed_yes_syncdaemon_TF(self):
220 """Test name owner changed callback."""
221 self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "T", "")
222 rcv, = self.get_msd_called("on_sd_name_owner_changed")
223 self.assertEqual(rcv, False)
224
225 def test_name_owner_changed_yes_syncdaemon_FT(self):
226 """Test name owner changed callback."""
227 self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "", "T")
228 rcv, = self.get_msd_called("on_sd_name_owner_changed")
229 self.assertEqual(rcv, True)
230
231
232class TestDataProcessingCQ(SafeTests):
233 """Processes CQ data before sending it to SyncDaemon."""
234
235 @defer.inlineCallbacks
236 def test_nodata(self):
237 """Test with no data in the queue."""
238 self.fake_sdt_response('waiting_content', [])
239 rcv = yield self.dbus.get_content_queue()
240 self.assertEqual(len(rcv), 0)
241
242 @defer.inlineCallbacks
243 def test_one_item(self):
244 """Test with one item in the queue."""
245 c = dict(operation='oper', path='path', share='share', node='node')
246 self.fake_sdt_response('waiting_content', [c])
247 rcv = yield self.dbus.get_content_queue()
248 self.assertEqual(len(rcv), 1)
249 data = rcv[0]
250 self.assertEqual(data.operation, 'oper')
251 self.assertEqual(data.path, 'path')
252 self.assertEqual(data.share, 'share')
253 self.assertEqual(data.node, 'node')
254
255 @defer.inlineCallbacks
256 def test_two_items(self):
257 """Test with two items in the queue."""
258 c = dict(operation='oper1', path='path1', share='share1', node='node1')
259 d = dict(operation='oper2', path='path2', share='share2', node='node2')
260 self.fake_sdt_response('waiting_content', [c, d])
261 rcv = yield self.dbus.get_content_queue()
262 self.assertEqual(len(rcv), 2)
263 data = rcv[0]
264 self.assertEqual(data.operation, 'oper1')
265 self.assertEqual(data.path, 'path1')
266 self.assertEqual(data.share, 'share1')
267 self.assertEqual(data.node, 'node1')
268 data = rcv[1]
269 self.assertEqual(data.operation, 'oper2')
270 self.assertEqual(data.path, 'path2')
271 self.assertEqual(data.share, 'share2')
272 self.assertEqual(data.node, 'node2')
273
274
275class TestDataProcessingMQ(SafeTests):
276 """Processes MQ data before sending it to SyncDaemon."""
277
278 @defer.inlineCallbacks
279 def test_nodata(self):
280 """Test with no data in the queue."""
281 self.fake_sdt_response('waiting_metadata', [])
282 rcv = yield self.dbus.get_meta_queue()
283 self.assertEqual(len(rcv), 0)
284
285 @defer.inlineCallbacks
286 def test_one_item(self):
287 """Test with one item in the queue."""
288 self.fake_sdt_response('waiting_metadata', ['ListShares'])
289 rcv = yield self.dbus.get_meta_queue()
290 self.assertEqual(len(rcv), 1)
291 data = rcv[0]
292 self.assertEqual(data.operation, 'ListShares')
293 self.assertEqual(data.path, None)
294 self.assertEqual(data.share, None)
295 self.assertEqual(data.node, None)
296
297 @defer.inlineCallbacks
298 def test_two_items(self):
299 """Test ContentQueueChanged signal with two items in the queue."""
300 cmd1 = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
301 cmd2 = 'GetPublicFiles'
302 self.fake_sdt_response('waiting_metadata', [cmd1, cmd2])
303 rcv = yield self.dbus.get_meta_queue()
304 self.assertEqual(len(rcv), 2)
305 data = rcv[0]
306 self.assertEqual(data.operation, 'MakeDir')
307 self.assertEqual(data.path, '/?.../c')
308 self.assertEqual(data.share, 'a')
309 self.assertEqual(data.node, None)
310 data = rcv[1]
311 self.assertEqual(data.operation, 'GetPublicFiles')
312 self.assertEqual(data.path, None)
313 self.assertEqual(data.share, None)
314 self.assertEqual(data.node, None)
315
316 @defer.inlineCallbacks
317 def test_GetPublicFiles(self):
318 """Test meta with GetPublicFiles."""
319 cmd = 'GetPublicFiles'
320 self.fake_sdt_response('waiting_metadata', [cmd])
321 rcv = yield self.dbus.get_meta_queue()
322 data = rcv[0]
323 self.assertEqual(data.operation, 'GetPublicFiles')
324 self.assertEqual(data.path, None)
325 self.assertEqual(data.share, None)
326 self.assertEqual(data.node, None)
327
328 @defer.inlineCallbacks
329 def test_AccountInquiry(self):
330 """Test meta with AccountInquiry."""
331 cmd = 'AccountInquiry'
332 self.fake_sdt_response('waiting_metadata', [cmd])
333 rcv = yield self.dbus.get_meta_queue()
334 data = rcv[0]
335 self.assertEqual(data.operation, 'AccountInquiry')
336 self.assertEqual(data.path, None)
337 self.assertEqual(data.share, None)
338 self.assertEqual(data.node, None)
339
340 @defer.inlineCallbacks
341 def test_FreeSpaceInquiry(self):
342 """Test meta with FreeSpaceInquiry."""
343 cmd = 'FreeSpaceInquiry'
344 self.fake_sdt_response('waiting_metadata', [cmd])
345 rcv = yield self.dbus.get_meta_queue()
346 data = rcv[0]
347 self.assertEqual(data.operation, 'FreeSpaceInquiry')
348 self.assertEqual(data.path, None)
349 self.assertEqual(data.share, None)
350 self.assertEqual(data.node, None)
351
352 @defer.inlineCallbacks
353 def test_ListShares(self):
354 """Test meta with ListShares."""
355 cmd = 'ListShares'
356 self.fake_sdt_response('waiting_metadata', [cmd])
357 rcv = yield self.dbus.get_meta_queue()
358 data = rcv[0]
359 self.assertEqual(data.operation, 'ListShares')
360 self.assertEqual(data.path, None)
361 self.assertEqual(data.share, None)
362 self.assertEqual(data.node, None)
363
364 @defer.inlineCallbacks
365 def test_ListVolumes(self):
366 """Test meta with ListVolumes."""
367 cmd = 'ListVolumes'
368 self.fake_sdt_response('waiting_metadata', [cmd])
369 rcv = yield self.dbus.get_meta_queue()
370 data = rcv[0]
371 self.assertEqual(data.operation, 'ListVolumes')
372 self.assertEqual(data.path, None)
373 self.assertEqual(data.share, None)
374 self.assertEqual(data.node, None)
375
376 @defer.inlineCallbacks
377 def test_Query(self):
378 """Test meta with Query."""
379 cmd = 'Query'
380 self.fake_sdt_response('waiting_metadata', [cmd])
381 rcv = yield self.dbus.get_meta_queue()
382 data = rcv[0]
383 self.assertEqual(data.operation, 'Query')
384 self.assertEqual(data.path, None)
385 self.assertEqual(data.share, None)
386 self.assertEqual(data.node, None)
387
388 @defer.inlineCallbacks
389 def test_ListDir(self):
390 """Test meta with ListDir."""
391 cmd = 'ListDir(share_id=a, node_id=b, server_hash=c)'
392 self.fake_sdt_response('waiting_metadata', [cmd])
393 rcv = yield self.dbus.get_meta_queue()
394 data = rcv[0]
395 self.assertEqual(data.operation, 'ListDir')
396 self.assertEqual(data.path, '?')
397 self.assertEqual(data.share, 'a')
398 self.assertEqual(data.node, 'b')
399
400 @defer.inlineCallbacks
401 def test_MakeDir(self):
402 """Test meta with MakeDir."""
403 cmd = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
404 self.fake_sdt_response('waiting_metadata', [cmd])
405 rcv = yield self.dbus.get_meta_queue()
406 data = rcv[0]
407 self.assertEqual(data.operation, 'MakeDir')
408 self.assertEqual(data.path, '/?.../c')
409 self.assertEqual(data.share, 'a')
410 self.assertEqual(data.node, None)
411
412 @defer.inlineCallbacks
413 def test_MakeFile(self):
414 """Test meta with MakeFile."""
415 cmd = 'MakeFile(share_id=a, parent_id=b, name=c, marker=d)'
416 self.fake_sdt_response('waiting_metadata', [cmd])
417 rcv = yield self.dbus.get_meta_queue()
418 data = rcv[0]
419 self.assertEqual(data.operation, 'MakeFile')
420 self.assertEqual(data.path, '/?.../c')
421 self.assertEqual(data.share, 'a')
422 self.assertEqual(data.node, None)
423
424 @defer.inlineCallbacks
425 def test_Unlink(self):
426 """Test meta with Unlink."""
427 cmd = 'Unlink(share_id=a, node_id=b, server_hash=c)'
428 self.fake_sdt_response('waiting_metadata', [cmd])
429 rcv = yield self.dbus.get_meta_queue()
430 data = rcv[0]
431 self.assertEqual(data.operation, 'Unlink')
432 self.assertEqual(data.path, '?')
433 self.assertEqual(data.share, 'a')
434 self.assertEqual(data.node, 'b')
435
436 @defer.inlineCallbacks
437 def test_Move(self):
438 """Test meta with Move."""
439 cmd = 'Move(share_id=a, node_id=b, old_parent_id=c, '\
440 'new_parent_id=d, new_name=e)'
441 self.fake_sdt_response('waiting_metadata', [cmd])
442 rcv = yield self.dbus.get_meta_queue()
443 data = rcv[0]
444 self.assertEqual(data.operation, 'Move')
445 self.assertEqual(data.path, '/?.../? -> /?.../e')
446 self.assertEqual(data.share, 'a')
447 self.assertEqual(data.node, 'b')
448
449
450class TestDataProcessingFolders(SafeTests):
451 """Processes Folders data before sending it to SyncDaemon."""
452
453 @defer.inlineCallbacks
454 def test_nodata(self):
455 """Test get folders with no data."""
456 self.fake_sdt_response('get_folders', [])
457 rcv = yield self.dbus.get_folders()
458 self.assertEqual(len(rcv), 0)
459
460 @defer.inlineCallbacks
461 def test_one(self):
462 """Test get folders with one."""
463 d = dict(node_id='nid', path=u'pth', subscribed='True',
464 suggested_path=u'sgp', type='UDF', volume_id='vid')
465 self.fake_sdt_response('get_folders', [d])
466 rcv = yield self.dbus.get_folders()
467 self.assertEqual(len(rcv), 1)
468 folder = rcv[0]
469 self.assertEqual(folder.node, 'nid')
470 self.assertEqual(folder.path, u'pth')
471 self.assertEqual(folder.suggested_path, u'sgp')
472 self.assertEqual(folder.subscribed, True)
473 self.assertEqual(folder.volume, 'vid')
474
475 @defer.inlineCallbacks
476 def test_getting_info_two(self):
477 """When changed, update info, got two."""
478 d1 = dict(node_id='nid1', path=u'pth1', subscribed='True',
479 suggested_path=u'sgp1', type='UDF', volume_id='vid1')
480 d2 = dict(node_id='nid2', path=u'pth2', subscribed='',
481 suggested_path=u'sgp2', type='UDF', volume_id='vid2')
482 self.fake_sdt_response('get_folders', [d1, d2])
483 rcv = yield self.dbus.get_folders()
484 self.assertEqual(len(rcv), 2)
485 folder = rcv[0]
486 self.assertEqual(folder.node, 'nid1')
487 self.assertEqual(folder.path, u'pth1')
488 self.assertEqual(folder.suggested_path, u'sgp1')
489 self.assertEqual(folder.subscribed, True)
490 self.assertEqual(folder.volume, 'vid1')
491 folder = rcv[1]
492 self.assertEqual(folder.node, 'nid2')
493 self.assertEqual(folder.path, u'pth2')
494 self.assertEqual(folder.suggested_path, u'sgp2')
495 self.assertEqual(folder.subscribed, False)
496 self.assertEqual(folder.volume, 'vid2')
497
498
499class TestToolActions(SafeTests):
500 """Actions against SD.tools.
501
502 Here we test only the actions, not callbacks, as they're tested before
503 in what they return.
504 """
505
506 def test_start(self):
507 """Test call to start."""
508 self.dbus.start()
509 self.check_sdt_called("start")
510
511 def test_quit(self):
512 """Test call to quit."""
513 self.dbus.quit()
514 self.check_sdt_called("quit")
515
516 def test_connect(self):
517 """Test call to connect."""
518 self.dbus.connect()
519 self.check_sdt_called("connect")
520
521 def test_disconnect(self):
522 """Test call to disconnect."""
523 self.dbus.disconnect()
524 self.check_sdt_called("disconnect")
525
526
527class TestLogs(SafeTests):
528 """Test logging."""
529
530 def setUp(self):
531 """Set up."""
532 self.handler = MementoHandler()
533 logging.getLogger('magicicada.dbusiface').addHandler(self.handler)
534 self.handler.setLevel(logging.DEBUG)
535 SafeTests.setUp(self)
536
537 def test_instancing(self):
538 """Just logged SD instancing."""
539 self.assertTrue(self.handler.check_inf("DBus interface starting"))
540
541 def test_shutdown(self):
542 """Log when SD shutdowns."""
543 self.dbus.shutdown()
544 self.assertTrue(self.handler.check_inf("DBus interface going down"))
545
546 def test_waiting_content(self):
547 """Test call to waiting content."""
548 self.dbus.get_content_queue()
549 self.assertTrue(self.handler.check_inf("Getting content queue"))
550
551 def test_waiting_meta(self):
552 """Test call to waiting meta."""
553 self.dbus.get_meta_queue()
554 self.assertTrue(self.handler.check_inf("Getting meta queue"))
555
556 def test_get_status(self):
557 """Test call to status."""
558 self.dbus.get_status()
559 self.assertTrue(self.handler.check_inf("Getting status"))
560
561 def test_get_folders(self):
562 """Test call to folders."""
563 self.dbus.get_folders()
564 self.assertTrue(self.handler.check_inf("Getting folders"))
565
566 def test_is_sd_started(self):
567 """Test call to is_sd_started."""
568 self.dbus.is_sd_started()
569 self.assertTrue(self.handler.check_inf(
570 "Checking if SD is started: True"))
571
572 def test_start(self):
573 """Test call to start."""
574 self.dbus.start()
575 self.assertTrue(self.handler.check_inf("Calling start"))
576
577 def test_quit(self):
578 """Test call to quit."""
579 self.dbus.quit()
580 self.assertTrue(self.handler.check_inf("Calling quit"))
581
582 def test_connect(self):
583 """Test call to connect."""
584 self.dbus.connect()
585 self.assertTrue(self.handler.check_inf("Calling connect"))
586
587 def test_disconnect(self):
588 """Test call to disconnect."""
589 self.dbus.disconnect()
590 self.assertTrue(self.handler.check_inf("Calling disconnect"))
591
592 def test_status_changed(self):
593 """Test status changed callback."""
594 d = dict(name='name', description='description', is_error='',
595 is_connected='True', is_online='', queues='queues',
596 connection='connection')
597 self.dbus._on_status_changed(d)
598 self.assertTrue(self.handler.check_inf("Received Status changed"))
599 self.assertTrue(self.handler.check_dbg("Status changed data: %r" % d))
600
601 def test_content_queue_changed(self):
602 """Test content queue changed callback."""
603 self.dbus._on_content_queue_changed("foo")
604 self.assertTrue(self.handler.check_inf(
605 "Received Content Queue changed"))
606
607 def test_name_owner_changed_other(self):
608 """Test name owner changed callback, no SD."""
609 self.dbus._on_name_owner_changed("other", "", "T")
610 self.assertFalse(self.handler.check_inf("Received Name Owner changed"))
611
612 def test_name_owner_changed_syncdaemon(self):
613 """Test name owner changed callback, SD value ok."""
614 self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "", "T")
615 self.assertTrue(self.handler.check_inf("Received Name Owner changed"))
616 self.assertTrue(self.handler.check_dbg("Name Owner data: u'' u'T'"))
617
618 def test_name_owner_changed_yes_syncdaemon_TF(self):
619 """Test name owner changed callback, SD value bad."""
620 self.dbus._on_name_owner_changed("com.ubuntuone.SyncDaemon", "F", "T")
621 self.assertTrue(self.handler.check_inf("Received Name Owner changed"))
622 self.assertTrue(self.handler.check_dbg("Name Owner data: u'F' u'T'"))
623 self.assertTrue(self.handler.check("ERROR",
624 "Name Owner invalid data: Same bool in old and new!"))
625
626 def test_folder_created_changed(self):
627 """Test folder created changed callback."""
628 self.dbus._on_folder_created("foo")
629 self.assertTrue(self.handler.check_inf("Received Folder created"))
630
631 def test_folder_deleted_changed(self):
632 """Test folder deleted changed callback."""
633 self.dbus._on_folder_deleted("foo")
634 self.assertTrue(self.handler.check_inf("Received Folder deleted"))
635
636 @defer.inlineCallbacks
637 def test_content_queue_processing(self):
638 """Test with one item in the queue."""
639 c = dict(operation='oper', path='path', share='share', node='node')
640 self.fake_sdt_response('waiting_content', [c])
641 yield self.dbus.get_content_queue()
642 self.assertTrue(self.handler.check_inf(
643 "Processing Content Queue items (1)"))
644 self.assertTrue(self.handler.check_dbg(
645 " Content Queue data: %s" % c))
646
647 @defer.inlineCallbacks
648 def test_meta_queue_processing(self):
649 """Test with one item in the queue."""
650 self.fake_sdt_response('waiting_metadata', ['ListShares'])
651 yield self.dbus.get_meta_queue()
652 self.assertTrue(self.handler.check_inf(
653 "Processing Meta Queue items (1)"))
654 self.assertTrue(self.handler.check_dbg(
655 " Meta Queue data: u'ListShares'"))
656
657 @defer.inlineCallbacks
658 def test_folders_processing(self):
659 """Test get folders with one."""
660 d = dict(node_id='nid', path=u'pth', subscribed='True',
661 suggested_path=u'sgp', type='UDF', volume_id='vid')
662 self.fake_sdt_response('get_folders', [d])
663 yield self.dbus.get_folders()
664 self.assertTrue(self.handler.check_inf("Processing Folders items (1)"))
665 self.assertTrue(self.handler.check_dbg(" Folders data: %r" % d))
0666
=== modified file 'magicicada/tests/test_magicicada.py'
--- magicicada/tests/test_magicicada.py 2010-05-27 02:01:27 +0000
+++ magicicada/tests/test_magicicada.py 2010-05-27 20:56:26 +0000
@@ -25,6 +25,7 @@
25from twisted.trial.unittest import TestCase25from twisted.trial.unittest import TestCase
2626
27from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon27from magicicada import MagicicadaUI, CONTENT_QUEUE, META_QUEUE, syncdaemon
28from magicicada.dbusiface import QueueData
28from magicicada.helpers import NO_OP29from magicicada.helpers import NO_OP
2930
3031
@@ -278,9 +279,9 @@
278 """Build some data to pass to queue changed callback and related."""279 """Build some data to pass to queue changed callback and related."""
279 items = []280 items = []
280 for i in xrange(limit):281 for i in xrange(limit):
281 cq = syncdaemon.QueueData(operation='operation %i' % i,282 cq = QueueData(operation='operation %i' % i,
282 path='path %i' % i, node='node %i' % i,283 path='path %i' % i, node='node %i' % i,
283 share='share %i' % i)284 share='share %i' % i)
284 items.append(cq)285 items.append(cq)
285 return items286 return items
286287
287288
=== modified file 'magicicada/tests/test_syncdaemon.py'
--- magicicada/tests/test_syncdaemon.py 2010-05-22 20:27:11 +0000
+++ magicicada/tests/test_syncdaemon.py 2010-05-27 20:56:26 +0000
@@ -21,49 +21,133 @@
21import logging21import logging
22import unittest22import unittest
2323
24import dbus
25from dbus.mainloop.glib import DBusGMainLoop
26
27# this should be imported *before* importing the reactor below, as needs to
28# install the glib connection first
29from magicicada.syncdaemon import SyncDaemon, State24from magicicada.syncdaemon import SyncDaemon, State
30from magicicada.helpers import NO_OP25from magicicada.tests.helpers import MementoHandler
3126
32from dbus.lowlevel import SignalMessage
33from twisted.trial.unittest import TestCase as TwistedTestCase27from twisted.trial.unittest import TestCase as TwistedTestCase
34from twisted.internet import defer, reactor28from twisted.internet import defer, reactor
3529
36from ubuntuone.syncdaemon.dbus_interface import DBUS_IFACE_STATUS_NAME30
3731class FakeDBusInterface(object):
3832 """Fake DBus Interface, for SD to not use dbus at all during tests."""
39class SignalsBaseTest(TwistedTestCase):33
40 """Base infrastructure to tests the signals."""34 fake_sd_started = False
4135
42 timeout = 236 def __init__(self, sd):
37 pass
38
39 def shutdown(self):
40 pass
41
42 def get_status(self):
43 """Fake status."""
44 return defer.succeed(('fakename', 'fakedescrip', False, True,
45 False, 'fakequeues', 'fakeconnection'))
46 def get_folders(self):
47 """Fake folders."""
48 return defer.succeed('fakedata')
49 get_content_queue = get_meta_queue = get_folders
50 start = quit = connect = disconnect = get_folders
51
52 def is_sd_started(self):
53 """Fake response."""
54 return self.fake_sd_started
55
56
57class BaseTest(TwistedTestCase):
58 """Base test with a SD."""
59
60 timeout = 1
4361
44 def setUp(self):62 def setUp(self):
45 """Set up the test."""63 """Set up."""
46 self.loop = DBusGMainLoop(set_as_default=True)64 self.sd = SyncDaemon(FakeDBusInterface)
47 self.bus = dbus.bus.BusConnection(mainloop=self.loop)
48 self.sd = SyncDaemon()
4965
50 def tearDown(self):66 def tearDown(self):
51 """Tear down the test."""67 """Tear down."""
52 self.sd.shutdown()68 self.sd.shutdown()
5369
54 def send_signal(self, interface, signal, signature, *args):70
55 """Send a DBus signal."""71class InitialDataTests(unittest.TestCase):
56 msg = SignalMessage('/status', interface, signal)72 """Tests for initial data gathering."""
57 msg.set_no_reply(True)73
58 msg.append(*args, signature=signature)74 def test_called_by_start(self):
59 self.bus.send_message(msg)75 """Check that start calls get initial data."""
6076 sd = SyncDaemon(FakeDBusInterface)
6177 called = []
62class SimpleSignalsTests(SignalsBaseTest):78 sd._get_initial_data = lambda: called.append(True)
79 sd.start()
80 self.assertTrue(called)
81
82 def test_called_by_nameownerchanged_no(self):
83 """Check that it is called when discover that sd started."""
84 sd = SyncDaemon(FakeDBusInterface)
85 called = []
86 sd._get_initial_data = lambda: called.append(True)
87 sd.on_sd_name_owner_changed(True)
88 self.assertTrue(called)
89
90 def test_called_by_nameownerchanged_yes(self):
91 """Check that it is not called when discover that sd stopped."""
92 sd = SyncDaemon(FakeDBusInterface)
93 called = []
94 sd._get_initial_data = lambda: called.append(True)
95 sd.on_sd_name_owner_changed(False)
96 self.assertFalse(called)
97
98 def test_called_beggining_no(self):
99 """Check that it should not be called if no SD."""
100 called = []
101 orig_met = SyncDaemon._get_initial_data
102 SyncDaemon._get_initial_data = lambda s: called.append(True)
103 SyncDaemon(FakeDBusInterface)
104 SyncDaemon._get_initial_data = orig_met
105 self.assertFalse(called)
106
107 def test_called_beggining_yes(self):
108 """Check that it should be called if SD already started."""
109 called = []
110 orig_met = SyncDaemon._get_initial_data
111 SyncDaemon._get_initial_data = lambda s: called.append(True)
112 FakeDBusInterface.fake_sd_started = True
113 SyncDaemon(FakeDBusInterface)
114 SyncDaemon._get_initial_data = orig_met
115 self.assertTrue(called)
116
117 def test_calls_callbacks(self):
118 """Check that initial data calls the callbacks for new data."""
119 called = []
120 sd = SyncDaemon(FakeDBusInterface)
121 f = lambda *a: called.append(True)
122 sd.status_changed_callback = f
123 sd.content_queue_changed_callback = f
124 sd.meta_queue_changed_callback = f
125
126 sd._get_initial_data()
127 self.assertEqual(len(called), 3)
128
129
130class StatusChangedTests(BaseTest):
63 """Simple signals checking."""131 """Simple signals checking."""
64132
133 @defer.inlineCallbacks
134 def test_initial_value(self):
135 """Fills the status info initially."""
136 called = []
137 def fake():
138 """Fake method."""
139 called.append(True)
140 return defer.succeed(('fakename', 'fakedescrip', False, True,
141 False, 'fakequeues', 'fakeconnection'))
142
143 self.sd.dbus.get_status = fake
144 yield self.sd._get_initial_data()
145 self.assertTrue(called)
146
65 def test_statuschanged(self):147 def test_statuschanged(self):
66 """Test StatusChanged signal."""148 """Test StatusChanged signal."""
149 deferred = defer.Deferred()
150
67 def callback(name, description, is_error, is_connected, is_online,151 def callback(name, description, is_error, is_connected, is_online,
68 queues, connection):152 queues, connection):
69 """Check received data."""153 """Check received data."""
@@ -76,325 +160,208 @@
76 self.assertEqual(connection, 'connection')160 self.assertEqual(connection, 'connection')
77 deferred.callback(True)161 deferred.callback(True)
78162
79 # set the callback
80 self.sd.status_changed_callback = callback163 self.sd.status_changed_callback = callback
81164 self.sd.on_sd_status_changed('name', 'description', False, True,
82 # send signal with signature and structures like original syncdaemon165 False, 'queues', 'connection')
83 d = dict(name='name', description='description', is_error='',
84 is_connected='True', is_online='', queues='queues',
85 connection='connection')
86 self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
87
88 deferred = defer.Deferred()
89 return deferred166 return deferred
90167
91168 def test_status_changed_affects_cuurent_status(self):
92class ContentQueueChangedTests(SignalsBaseTest):169 """Makes changes to see how status are reflected."""
170 # one set of values
171 self.sd.on_sd_status_changed('name1', 'description1', False, True,
172 False, 'queues1', 'connection1')
173 self.assertEqual(self.sd.current_state.name, 'name1')
174 self.assertEqual(self.sd.current_state.description, 'description1')
175 self.assertEqual(self.sd.current_state.is_error, False)
176 self.assertEqual(self.sd.current_state.is_connected, True)
177 self.assertEqual(self.sd.current_state.is_online, False)
178 self.assertEqual(self.sd.current_state.queues, 'queues1')
179 self.assertEqual(self.sd.current_state.connection, 'connection1')
180
181 # again, to be sure they actually are updated
182 self.sd.on_sd_status_changed('name2', 'description2', True, False,
183 True, 'queues2', 'connection2')
184 self.assertEqual(self.sd.current_state.name, 'name2')
185 self.assertEqual(self.sd.current_state.description, 'description2')
186 self.assertEqual(self.sd.current_state.is_error, True)
187 self.assertEqual(self.sd.current_state.is_connected, False)
188 self.assertEqual(self.sd.current_state.is_online, True)
189 self.assertEqual(self.sd.current_state.queues, 'queues2')
190 self.assertEqual(self.sd.current_state.connection, 'connection2')
191
192
193class ContentQueueChangedTests(BaseTest):
93 """Check the ContenQueueChanged handling."""194 """Check the ContenQueueChanged handling."""
94195
196 @defer.inlineCallbacks
197 def test_initial_value(self):
198 """Fills the content queue info initially."""
199 called = []
200 self.sd.dbus.get_content_queue = lambda: called.append(True)
201 yield self.sd._get_initial_data()
202 self.assertTrue(called)
203
95 def test_without_setting_callback(self):204 def test_without_setting_callback(self):
96 """It should work even if not hooking into the callback."""205 """It should work even if not hooking into the callback."""
97 self.sd._process_cq([])206 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
98207 self.sd.on_sd_content_queue_changed()
99 def _contentqueuechanged_test(self, somedata):208
100 """Test ContentQueueChanged signal with some data."""209 def test_callback_call(self):
101 def callback(queued_elements):210 """Call the callback."""
102 """Check received data."""211 called = []
103 self.assertEqual(len(queued_elements), len(somedata))212 self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
104 for received, original in zip(queued_elements, somedata):213 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
105 self.assertEqual(received.operation, original['operation'])214 self.sd.on_sd_content_queue_changed()
106 self.assertEqual(received.path, original['path'])215 self.assertTrue(called)
107 self.assertEqual(received.share, original['share'])216
108 self.assertEqual(received.node, original['node'])217 def test_callback_call_twice_different(self):
109 deferred.callback(True)218 """Call the callback twice for different info."""
110219 called = []
111 # set the callback220 self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
112 self.sd.content_queue_changed_callback = callback221
113222 # first call
114 # monkeypatch SyncDaemon to quickly return the queued elements223 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
115 self.sd._get_content_queue = lambda: defer.succeed(somedata)224 self.sd.on_sd_content_queue_changed()
116225 self.assertEqual(called, [['foo']])
117 # send signal with signature and structures like original syncdaemon,226
118 # but note that in this case we don't care of this info227 # second call, different info
119 data = {'foo': {'bar':'1', 'baz':'2'}}228 self.sd.dbus.get_content_queue = lambda: defer.succeed(['bar'])
120 self.send_signal(DBUS_IFACE_STATUS_NAME, 'ContentQueueChanged',229 self.sd.on_sd_content_queue_changed()
121 'a{sa{ss}}', data)230 self.assertEqual(called, [['foo'], ['bar']])
122 deferred = defer.Deferred()231
123 return deferred232 def test_callback_call_twice_same(self):
124233 """Call the callback once, even getting twice the same info."""
125 def test_contentqueuechanged_nodata(self):234 called = []
126 """Test ContentQueueChanged signal with no data in the queue."""235 self.sd.content_queue_changed_callback = lambda cq: called.append(cq)
127 return self._contentqueuechanged_test([])236
128237 # first call
129 def test_contentqueuechanged_oneitem(self):238 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
130 """Test ContentQueueChanged signal with one item in the queue."""239 self.sd.on_sd_content_queue_changed()
131 c = dict(operation='oper', path='path', share='share', node='node')240 self.assertEqual(called, [['foo']])
132 return self._contentqueuechanged_test([c])241
133242 # second call, same info
134 def test_contentqueuechanged_twoitems(self):243 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
135 """Test ContentQueueChanged signal with two items in the queue."""244 self.sd.on_sd_content_queue_changed()
136 c = dict(operation='oper1', path='path1', share='share1', node='node1')245 self.assertEqual(called, [['foo']])
137 d = dict(operation='oper2', path='path2', share='share2', node='node2')246
138 return self._contentqueuechanged_test([c, d])247 def test_CQ_state_nothing(self):
139248 """Check the ContentQueue info, being nothing."""
140 def test_no_double_callback_for_same_info(self):249 self.sd.dbus.get_content_queue = lambda: defer.succeed([])
141 """No callback call for same info in the CQ."""250 self.sd.on_sd_content_queue_changed()
142 callback_called = []251 self.assertEqual(self.sd.content_queue, [])
143 def callback(queued_elements):
144 """Store the callbacked stuff."""
145 callback_called.append(queued_elements)
146
147 # set the callback
148 self.sd.content_queue_changed_callback = callback
149
150 # data to test
151 c = dict(operation='oper1', path='path1', share='share1', node='node1')
152 d = dict(operation='oper2', path='path2', share='share2', node='node2')
153 e = dict(operation='oper3', path='path3', share='share3', node='node3')
154
155 # call a sequence of different and repeated data
156 self.sd._process_cq([c])
157 self.sd._process_cq([d])
158 self.sd._process_cq([d]) # repeated!
159 self.sd._process_cq([c])
160 self.sd._process_cq([e])
161 self.sd._process_cq([e]) # repeated!
162 self.sd._process_cq([e]) # repeated!
163 self.sd._process_cq([d])
164 self.sd._process_cq([d, d])
165 self.sd._process_cq([d, d]) # repeated!
166 self.sd._process_cq([d])
167 should_be = [ [c], [d], [c], [e], [d], [d, d], [d] ]
168
169 # check order and that it wasn't repeated
170 self.assertEqual(len(callback_called), len(should_be))
171 for cq_received, cq_original in zip(callback_called, should_be):
172 for received, original in zip(cq_received, cq_original):
173 self.assertEqual(received.operation, original['operation'])
174 self.assertEqual(received.path, original['path'])
175 self.assertEqual(received.share, original['share'])
176 self.assertEqual(received.node, original['node'])
177
178 def test_CQ_state_none(self):
179 """Check the ContentQueue info, being none."""
180 self.assertEqual(len(self.sd.content_queue), 0)
181252
182 def test_CQ_state_one(self):253 def test_CQ_state_one(self):
183 """Check the ContentQueue info, being one."""254 """Check the ContentQueue info, being one."""
184 d = dict(operation='oper', path='path', share='share', node='node')255 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
185 self.sd._process_cq([d])256 self.sd.on_sd_content_queue_changed()
186 self.assertEqual(len(self.sd.content_queue), 1)257 self.assertEqual(self.sd.content_queue, ['foo'])
187258
188 # check the data259 def test_CQ_state_two(self):
189 cqit = self.sd.content_queue[0]260 """Check the ContentQueue info, two."""
190 self.assertEqual(cqit.operation, 'oper')261 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo', 'bar'])
191 self.assertEqual(cqit.path, 'path')262 self.sd.on_sd_content_queue_changed()
192 self.assertEqual(cqit.share, 'share')263 self.assertEqual(self.sd.content_queue, ['foo', 'bar'])
193 self.assertEqual(cqit.node, 'node')264
194265
195 def test_CQ_state_several(self):266class MetaQueueChangedTests(BaseTest):
196 """Check the ContentQueue info, several calls, last one is bigger."""
197 c = dict(operation='oper1', path='path1', share='share1', node='node1')
198 d = dict(operation='oper2', path='path2', share='share2', node='node2')
199 self.sd._process_cq([c])
200 self.sd._process_cq([d])
201 self.sd._process_cq([c, d])
202 self.assertEqual(len(self.sd.content_queue), 2)
203
204 # check the data
205 cqit = self.sd.content_queue[0]
206 self.assertEqual(cqit.operation, 'oper1')
207 self.assertEqual(cqit.path, 'path1')
208 self.assertEqual(cqit.share, 'share1')
209 self.assertEqual(cqit.node, 'node1')
210 cqit = self.sd.content_queue[1]
211 self.assertEqual(cqit.operation, 'oper2')
212 self.assertEqual(cqit.path, 'path2')
213 self.assertEqual(cqit.share, 'share2')
214 self.assertEqual(cqit.node, 'node2')
215
216
217class MetaQueueChangedTests(SignalsBaseTest):
218 """Check the MetaQueueChanged handling."""267 """Check the MetaQueueChanged handling."""
219268
220 def test_without_setting_callback(self):269 def setUp(self):
221 """It should work even if not hooking into the callback."""270 """Set up."""
222 self.sd._process_mq([])271 BaseTest.setUp(self)
223272 self.sd.current_state._set(name='QUEUE_MANAGER',
224 def _metaqueuechanged_test(self, inpdata, outdata):273 queues='WORKING_ON_METADATA')
225 """Test MetaQueueChanged signal with some data."""274
226 deferred = defer.Deferred()275 @defer.inlineCallbacks
227 def callback(queued_elements):276 def test_initial_value(self):
228 """Check received data."""277 """Fills the meta queue info initially."""
229 self.assertEqual(len(queued_elements), len(outdata))278 called = []
230 for received, original in zip(queued_elements, outdata):279 self.sd.dbus.get_meta_queue = lambda: called.append(True)
231 self.assertEqual(received.operation, original['operation'])280 yield self.sd._get_initial_data()
232 self.assertEqual(received.path, original['path'])281 self.assertTrue(called)
233 self.assertEqual(received.share, original['share'])282
234 self.assertEqual(received.node, original['node'])283 def test_callback_call(self):
235 deferred.callback(True)284 """Call the callback."""
236285 called = []
237 # set the callback286 self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
238 self.sd.meta_queue_changed_callback = callback287 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
239288 self.sd._check_mq()
240 # execute the function that trigger this (not by a dbus signal, as289 self.assertTrue(called)
241 # that was not available in Lucid)290
242 self.sd._process_mq(inpdata)291 def test_callback_call_twice_different(self):
243292 """Call the callback twice for different info."""
244 return deferred293 called = []
245294 self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
246 def test_metaqueuechanged_nodata(self):295
247 """Test MetaQueueChanged signal with no data in the queue."""296 # first call
248 return self._metaqueuechanged_test([], [])297 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
249298 self.sd._check_mq()
250 def test_GetPublicFiles(self):299 self.assertEqual(called, [['foo']])
251 """Test meta with GetPublicFiles."""300
252 r = dict(operation='GetPublicFiles', path=None, share=None, node=None)301 # second call, different info
253 return self._metaqueuechanged_test(['GetPublicFiles'], [r])302 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['bar'])
254303 self.sd._check_mq()
255 def test_AccountInquiry(self):304 self.assertEqual(called, [['foo'], ['bar']])
256 """Test meta with AccountInquiry."""305
257 r = dict(operation='AccountInquiry', path=None, share=None, node=None)306 def test_callback_call_twice_same(self):
258 return self._metaqueuechanged_test(['AccountInquiry'], [r])307 """Call the callback once, even getting twice the same info."""
259308 called = []
260 def test_FreeSpaceInquiry(self):309 self.sd.meta_queue_changed_callback = lambda mq: called.append(mq)
261 """Test meta with FreeSpaceInquiry."""310
262 r = dict(operation='FreeSpaceInquiry', path=None,311 # first call
263 share=None, node=None)312 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
264 return self._metaqueuechanged_test(['FreeSpaceInquiry'], [r])313 self.sd._check_mq()
265314 self.assertEqual(called, [['foo']])
266 def test_ListShares(self):315
267 """Test meta with ListShares."""316 # second call, same info
268 r = dict(operation='ListShares', path=None, share=None, node=None)317 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
269 return self._metaqueuechanged_test(['ListShares'], [r])318 self.sd._check_mq()
270319 self.assertEqual(called, [['foo']])
271 def test_ListVolumes(self):320
272 """Test meta with ListVolumes."""321 def test_polling_initiated_state_changed(self):
273 r = dict(operation='ListVolumes', path=None, share=None, node=None)322 """The polling initiates when state changes."""
274 return self._metaqueuechanged_test(['ListVolumes'], [r])323 called = []
275324 self.sd._check_mq = lambda: called.append(True)
276 def test_Query(self):325
277 """Test meta with Query."""326 # send some status changed
278 r = dict(operation='Query', path=None, share=None, node=None)327 self.sd.on_sd_status_changed('name', 'description', False, True,
279 return self._metaqueuechanged_test(['Query'], [r])328 False, 'queues', 'connection')
280329 self.assertTrue(called)
281 def test_ListDir(self):
282 """Test meta with ListDir."""
283 r = dict(operation='ListDir', path='?', share='a', node='b')
284 cmd = 'ListDir(share_id=a, node_id=b, server_hash=c)'
285 return self._metaqueuechanged_test([cmd], [r])
286
287 def test_MakeDir(self):
288 """Test meta with MakeDir."""
289 r = dict(operation='MakeDir', path='/?.../c', share='a', node=None)
290 cmd = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
291 return self._metaqueuechanged_test([cmd], [r])
292
293 def test_MakeFile(self):
294 """Test meta with MakeFile."""
295 r = dict(operation='MakeFile', path='/?.../c', share='a', node=None)
296 cmd = 'MakeFile(share_id=a, parent_id=b, name=c, marker=d)'
297 return self._metaqueuechanged_test([cmd], [r])
298
299 def test_Unlink(self):
300 """Test meta with Unlink."""
301 r = dict(operation='Unlink', path='?', share='a', node='b')
302 cmd = 'Unlink(share_id=a, node_id=b, server_hash=c)'
303 return self._metaqueuechanged_test([cmd], [r])
304
305 def test_Move(self):
306 """Test meta with Move."""
307 r = dict(operation='Move', path='/?.../? -> /?.../e',
308 share='a', node='b')
309 cmd = 'Move(share_id=a, node_id=b, old_parent_id=c, '\
310 'new_parent_id=d, new_name=e)'
311 return self._metaqueuechanged_test([cmd], [r])
312
313 def test_metaqueuechanged_twoitems(self):
314 """Test MetaQueueChanged signal with two items in the queue."""
315 r1 = dict(operation='AccountInquiry', path=None, share=None, node=None)
316 r2 = dict(operation='ListShares', path=None, share=None, node=None)
317 return self._metaqueuechanged_test(['AccountInquiry', 'ListShares'],
318 [r1, r2])
319
320 def test_no_double_callback_for_same_info(self):
321 """No callback call for same info in the MQ."""
322 callback_called = []
323 def callback(queued_elements):
324 """Store the callbacked stuff."""
325 callback_called.append(queued_elements)
326
327 # set the callback
328 self.sd.meta_queue_changed_callback = callback
329
330 # data to test
331 r1 = dict(operation='AccountInquiry', path=None, share=None, node=None)
332 cmd1 = 'AccountInquiry'
333 r2 = dict(operation='ListShares', path=None, share=None, node=None)
334 cmd2 = 'ListShares'
335 r3 = dict(operation='ListDir', path='?', share='a', node='b')
336 cmd3 = 'ListDir(share_id=a, node_id=b, server_hash=c)'
337
338 # call a sequence of different and repeated data
339 self.sd._process_mq([cmd1])
340 self.sd._process_mq([cmd2])
341 self.sd._process_mq([cmd2]) # repeated!
342 self.sd._process_mq([cmd1])
343 self.sd._process_mq([cmd3])
344 self.sd._process_mq([cmd3]) # repeated!
345 self.sd._process_mq([cmd3]) # repeated!
346 self.sd._process_mq([cmd2])
347 self.sd._process_mq([cmd2, cmd2])
348 self.sd._process_mq([cmd2, cmd2]) # repeated!
349 self.sd._process_mq([cmd2])
350 should_be = [ [r1], [r2], [r1], [r3], [r2], [r2, r2], [r2] ]
351
352 # check order and that it wasn't repeated
353 self.assertEqual(len(callback_called), len(should_be))
354 for cq_received, cq_original in zip(callback_called, should_be):
355 for received, original in zip(cq_received, cq_original):
356 self.assertEqual(received.operation, original['operation'])
357 self.assertEqual(received.path, original['path'])
358 self.assertEqual(received.share, original['share'])
359 self.assertEqual(received.node, original['node'])
360330
361 def test_mq_polling_workinginmetadata(self):331 def test_mq_polling_workinginmetadata(self):
362 """Check that it polls mq while working in metadata."""332 """Check that it polls mq while working in metadata."""
363
364 # set the callback333 # set the callback
365 self.sd._get_meta_queue = lambda *a: deferred.callback(True)
366
367 # send signal with signature and structures like original syncdaemon
368 d = dict(name='QUEUE_MANAGER', queues='WORKING_ON_METADATA',
369 description='description', is_error='', is_connected='True',
370 is_online='', connection='conn')
371 self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
372
373 deferred = defer.Deferred()334 deferred = defer.Deferred()
335 def fake():
336 """Fake."""
337 deferred.callback(True)
338 return defer.succeed("foo")
339 self.sd.dbus.get_meta_queue = fake
340
341 # send status changed to working in metadata
342 self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
343 True, False, 'WORKING_ON_METADATA',
344 'connection')
374 return deferred345 return deferred
375346
376 def test_mq_polling_workinginboth(self):347 def test_mq_polling_workinginboth(self):
377 """Check that it polls mq while working in both."""348 """Check that it polls mq while working in both."""
378
379 # set the callback349 # set the callback
380 self.sd._get_meta_queue = lambda *a: deferred.callback(True)
381
382 # send signal with signature and structures like original syncdaemon
383 d = dict(name='QUEUE_MANAGER', queues='WORKING_ON_BOTH',
384 description='description', is_error='', is_connected='True',
385 is_online='', connection='conn')
386 self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d)
387
388 deferred = defer.Deferred()350 deferred = defer.Deferred()
351 def fake():
352 """Fake."""
353 deferred.callback(True)
354 return defer.succeed("foo")
355 self.sd.dbus.get_meta_queue = fake
356
357 # send status changed to working in metadata
358 self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
359 True, False, 'WORKING_ON_BOTH',
360 'connection')
389 return deferred361 return deferred
390362
391 def test_mq_polling_untilfinish(self):363 def test_mq_polling_untilfinish(self):
392 """Check that it polls mq until no more is needed."""364 """Check that it polls mq until no more is needed."""
393 # prepare different status changed signals
394 d1 = dict(name='QUEUE_MANAGER', queues='WORKING_ON_BOTH',
395 description='description', is_error='', is_connected='True',
396 is_online='', connection='conn')
397
398 d2 = dict(name='QUEUE_MANAGER', queues='WORKING_ON_CONTENT',365 d2 = dict(name='QUEUE_MANAGER', queues='WORKING_ON_CONTENT',
399 description='description', is_error='', is_connected='True',366 description='description', is_error='', is_connected='True',
400 is_online='', connection='conn')367 is_online='', connection='conn')
@@ -402,61 +369,47 @@
402 # set the callback, and adjust the polling time to faster369 # set the callback, and adjust the polling time to faster
403 calls = []370 calls = []
404 def fake_get(*a):371 def fake_get(*a):
372 """Fake get."""
405 calls.append(None)373 calls.append(None)
406 if len(calls) < 3:374 if len(calls) < 3:
407 pass # no changes, should keep calling375 pass # no changes, should keep calling
408 elif len(calls) == 3:376 elif len(calls) == 3:
409 self.send_signal(DBUS_IFACE_STATUS_NAME,377 self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description',
410 'StatusChanged', 'a{ss}', d2)378 False, True, False,
379 'WORKING_ON_CONTENT', 'connect')
380
411 # allow time to see if a mistaken call happens381 # allow time to see if a mistaken call happens
412 reactor.callLater(.5, deferred.callback, True)382 reactor.callLater(.5, deferred.callback, True)
413 else:383 else:
414 deferred.errback(ValueError("Too many calls"))384 deferred.errback(ValueError("Too many calls"))
415 return defer.Deferred()385 return defer.succeed("foo")
416386
417 self.sd._get_meta_queue = fake_get387 self.sd.dbus.get_meta_queue = fake_get
418 self.sd._mq_poll_time = .1388 self.sd._mq_poll_time = .1
419389
420 self.send_signal(DBUS_IFACE_STATUS_NAME, 'StatusChanged', 'a{ss}', d1)390 self.sd.on_sd_status_changed('QUEUE_MANAGER', 'description', False,
391 True, False, 'WORKING_ON_BOTH',
392 'connection')
421 deferred = defer.Deferred()393 deferred = defer.Deferred()
422 return deferred394 return deferred
423395
424 def test_MQ_state_none(self):396 def test_MQ_state_nothing(self):
425 """Check the MetaQueue info, being none."""397 """Check the MetaQueue info, being nothing."""
426 self.assertEqual(len(self.sd.meta_queue), 0)398 self.sd.dbus.get_meta_queue = lambda: defer.succeed([])
399 self.sd._check_mq()
400 self.assertEqual(self.sd.meta_queue, [])
427401
428 def test_MQ_state_one(self):402 def test_MQ_state_one(self):
429 """Check the MetaQueue info, being one."""403 """Check the MetaQueue info, being one."""
430 self.sd._process_mq(['ListShares'])404 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
431 self.assertEqual(len(self.sd.meta_queue), 1)405 self.sd._check_mq()
432406 self.assertEqual(self.sd.meta_queue, ['foo'])
433 # check the data407
434 mqit = self.sd.meta_queue[0]408 def test_MQ_state_two(self):
435 self.assertEqual(mqit.operation, 'ListShares')409 """Check the MetaQueue info, two."""
436 self.assertEqual(mqit.path, None)410 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo', 'bar'])
437 self.assertEqual(mqit.share, None)411 self.sd._check_mq()
438 self.assertEqual(mqit.node, None)412 self.assertEqual(self.sd.meta_queue, ['foo', 'bar'])
439
440 def test_MQ_state_several(self):
441 """Check the MetaQueue info, several calls, last one is bigger."""
442 cmd1 = 'MakeDir(share_id=a, parent_id=b, name=c, marker=d)'
443 cmd2 = 'GetPublicFiles'
444 self.sd._process_mq([cmd1])
445 self.sd._process_mq([cmd2])
446 self.sd._process_mq([cmd1, cmd2])
447 self.assertEqual(len(self.sd.meta_queue), 2)
448
449 # check the data
450 mqit = self.sd.meta_queue[0]
451 self.assertEqual(mqit.operation, 'MakeDir')
452 self.assertEqual(mqit.path, '/?.../c')
453 self.assertEqual(mqit.share, 'a')
454 self.assertEqual(mqit.node, None)
455 mqit = self.sd.meta_queue[1]
456 self.assertEqual(mqit.operation, 'GetPublicFiles')
457 self.assertEqual(mqit.path, None)
458 self.assertEqual(mqit.share, None)
459 self.assertEqual(mqit.node, None)
460413
461414
462class StateTests(unittest.TestCase):415class StateTests(unittest.TestCase):
@@ -519,95 +472,51 @@
519 f = lambda *a, **k: setattr(self, 'called', True)472 f = lambda *a, **k: setattr(self, 'called', True)
520 setattr(obj, method_name, f)473 setattr(obj, method_name, f)
521474
522 def test_defaults_are_callable(self):
523 """Check the attributes are callable."""
524 meths = (self.sd._get_content_queue, self.sd._get_meta_queue,
525 self.sd._do_start, self.sd._do_quit,
526 self.sd._do_connect, self.sd._do_disconnect)
527 for meth in meths:
528 self.assertTrue(callable(meth), "Meth %r is not callable" % meth)
529
530 def test_is_connected_yes(self):
531 """Check is_connected, True."""
532 d = dict(name='name', description='description', is_error='',
533 is_connected='True', is_online='', queues='queues',
534 connection='connection')
535 self.sd._on_status_changed(d)
536 self.assertTrue(self.sd.current_state.is_connected)
537
538 def test_is_connected_no(self):
539 """Check is_connected, False."""
540 d = dict(name='name', description='description', is_error='',
541 is_connected='', is_online='', queues='queues',
542 connection='connection')
543 self.sd._on_status_changed(d)
544 self.assertFalse(self.sd.current_state.is_connected)
545
546 def test_is_online_yes(self):
547 """Check is_online, True."""
548 d = dict(name='name', description='description', is_error='',
549 is_connected='True', is_online='True', queues='queues',
550 connection='connection')
551 self.sd._on_status_changed(d)
552 self.assertTrue(self.sd.current_state.is_online)
553
554 def test_is_online_no(self):
555 """Check is_online, False."""
556 d = dict(name='name', description='description', is_error='',
557 is_connected='True', is_online='', queues='queues',
558 connection='connection')
559 self.sd._on_status_changed(d)
560 self.assertFalse(self.sd.current_state.is_online)
561
562 def test_is_started_yes(self):475 def test_is_started_yes(self):
563 """Check is_started, True."""476 """Check is_started, True."""
564 # simulate the signal that indicates the name was registered477 # simulate the signal that indicates the name was registered
565 self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', '', 'yes')478 self.sd.on_sd_name_owner_changed(True)
566 self.assertTrue(self.sd.current_state.is_started)479 self.assertTrue(self.sd.current_state.is_started)
567480
568 def test_is_started_no(self):481 def test_is_started_no(self):
569 """Check is_started, False."""482 """Check is_started, False."""
570 self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'yes', '')483 self.sd.on_sd_name_owner_changed(False)
571 self.assertFalse(self.sd.current_state.is_started)484 self.assertFalse(self.sd.current_state.is_started)
572485
573 def test_start(self):486 def test_start(self):
574 """Test start calls SD."""487 """Test start calls SD."""
575 self.mpatch_called(self.sd, '_do_start')488 self.mpatch_called(self.sd.dbus, 'start')
576 self.sd.start()489 self.sd.start()
577 self.assertTrue(self.called)490 self.assertTrue(self.called)
578491
579 def test_quit(self):492 def test_quit(self):
580 """Test quit calls SD."""493 """Test quit calls SD."""
581 self.mpatch_called(self.sd, '_do_quit')494 self.mpatch_called(self.sd.dbus, 'quit')
582 self.sd.quit()495 self.sd.quit()
583 self.assertTrue(self.called)496 self.assertTrue(self.called)
584497
585 def test_connect(self):498 def test_connect(self):
586 """Test connect calls SD."""499 """Test connect calls SD."""
587 self.mpatch_called(self.sd, '_do_connect')500 self.mpatch_called(self.sd.dbus, 'connect')
588 self.sd.connect()501 self.sd.connect()
589 self.assertTrue(self.called)502 self.assertTrue(self.called)
590503
591 def test_disconnect(self):504 def test_disconnect(self):
592 """Test disconnect calls SD."""505 """Test disconnect calls SD."""
593 self.mpatch_called(self.sd, '_do_disconnect')506 self.mpatch_called(self.sd.dbus, 'disconnect')
594 self.sd.disconnect()507 self.sd.disconnect()
595 self.assertTrue(self.called)508 self.assertTrue(self.called)
596509
597 def test_on_started(self):510 def test_on_started(self):
598 """Called when SD started."""511 """Called when SD started."""
599 self.flag_called(self.sd, 'on_started_callback')512 self.flag_called(self.sd, 'on_started_callback')
600513 self.sd.on_sd_name_owner_changed(True)
601 # simulate the signal that indicates the name was registered
602 self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', '', 'yes')
603 self.assertTrue(self.called)514 self.assertTrue(self.called)
604515
605 def test_on_stopped(self):516 def test_on_stopped(self):
606 """Called when SD stopped."""517 """Called when SD stopped."""
607 self.flag_called(self.sd, 'on_stopped_callback')518 self.flag_called(self.sd, 'on_stopped_callback')
608519 self.sd.on_sd_name_owner_changed(False)
609 # simulate the signal that indicates the name was registered
610 self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'yes', '')
611 self.assertTrue(self.called)520 self.assertTrue(self.called)
612521
613 def test_on_connected(self):522 def test_on_connected(self):
@@ -615,10 +524,8 @@
615 self.flag_called(self.sd, 'on_connected_callback')524 self.flag_called(self.sd, 'on_connected_callback')
616525
617 # first signal with connected in True526 # first signal with connected in True
618 d = dict(name='name', description='description', is_error='',527 self.sd.on_sd_status_changed('name', 'description', False, True,
619 is_connected='True', is_online='', queues='queues',528 False, 'queues', 'connection')
620 connection='connection')
621 self.sd._on_status_changed(d)
622 self.assertTrue(self.called)529 self.assertTrue(self.called)
623530
624 def test_on_disconnected(self):531 def test_on_disconnected(self):
@@ -626,12 +533,10 @@
626 self.flag_called(self.sd, 'on_disconnected_callback')533 self.flag_called(self.sd, 'on_disconnected_callback')
627534
628 # connect and disconnect535 # connect and disconnect
629 d = dict(name='name', description='description', is_error='',536 self.sd.on_sd_status_changed('name', 'description', False, True,
630 is_connected='True', is_online='', queues='queues',537 False, 'queues', 'connection')
631 connection='connection')538 self.sd.on_sd_status_changed('name', 'description', False, False,
632 self.sd._on_status_changed(d)539 False, 'queues', 'connection')
633 d['is_connected'] = ''
634 self.sd._on_status_changed(d)
635 self.assertTrue(self.called)540 self.assertTrue(self.called)
636541
637 def test_on_online(self):542 def test_on_online(self):
@@ -639,10 +544,8 @@
639 self.flag_called(self.sd, 'on_online_callback')544 self.flag_called(self.sd, 'on_online_callback')
640545
641 # first signal with online in True546 # first signal with online in True
642 d = dict(name='name', description='description', is_error='',547 self.sd.on_sd_status_changed('name', 'description', False, True,
643 is_connected='True', is_online='True', queues='queues',548 True, 'queues', 'connection')
644 connection='connection')
645 self.sd._on_status_changed(d)
646 self.assertTrue(self.called)549 self.assertTrue(self.called)
647550
648 def test_on_offline(self):551 def test_on_offline(self):
@@ -650,52 +553,23 @@
650 self.flag_called(self.sd, 'on_offline_callback')553 self.flag_called(self.sd, 'on_offline_callback')
651554
652 # go online and then offline555 # go online and then offline
653 d = dict(name='name', description='description', is_error='',556 self.sd.on_sd_status_changed('name', 'description', False, True,
654 is_connected='True', is_online='True', queues='queues',557 True, 'queues', 'connection')
655 connection='connection')558 self.sd.on_sd_status_changed('name', 'description', False, True,
656 self.sd._on_status_changed(d)559 False, 'queues', 'connection')
657 d['is_online'] = ''
658 self.sd._on_status_changed(d)
659 self.assertTrue(self.called)560 self.assertTrue(self.called)
660561
661562
662class MementoHandler(logging.Handler):
663 """A handler class which store logging records in a list."""
664
665 def __init__(self, *args, **kwargs):
666 """Create the instance, and add a records attribute."""
667 logging.Handler.__init__(self, *args, **kwargs)
668 self.records = []
669
670 def emit(self, record):
671 """Just add the record to self.records."""
672 self.records.append(record)
673
674 def check(self, level, msg):
675 """Check that something is logged."""
676 for rec in self.records:
677 if rec.levelname == level and rec.message == msg:
678 return True
679 raise ValueError("Log not found (%s) %r" % (level, msg))
680
681563
682class TestLogs(unittest.TestCase):564class TestLogs(unittest.TestCase):
683 """Test logging."""565 """Test logging."""
684566
685 def setUp(self):567 def setUp(self):
686 """Set up."""568 """Set up."""
687 self.handler = MementoHandler()569 self.hdlr = MementoHandler()
688 logging.getLogger('magicicada.syncdaemon').addHandler(self.handler)570 logging.getLogger('magicicada.syncdaemon').addHandler(self.hdlr)
689 self.handler.setLevel(logging.DEBUG)571 self.hdlr.setLevel(logging.DEBUG)
690 self.sd = SyncDaemon()572 self.sd = SyncDaemon(FakeDBusInterface)
691
692 # don't use real SD!
693 self.sd._get_content_queue = lambda: defer.Deferred()
694 self.sd._get_meta_queue = lambda: defer.Deferred()
695 self.sd._do_start = NO_OP
696 self.sd._do_quit = NO_OP
697 self.sd._do_connect = NO_OP
698 self.sd._do_disconnect = NO_OP
699573
700 def tearDown(self):574 def tearDown(self):
701 """Shut down!"""575 """Shut down!"""
@@ -703,100 +577,109 @@
703577
704 def test_instancing(self):578 def test_instancing(self):
705 """Just logged SD instancing."""579 """Just logged SD instancing."""
706 self.assertTrue(self.handler.check('INFO',580 self.assertTrue(self.hdlr.check_inf("SyncDaemon interface started!"))
707 "SyncDaemon interface started!"))
708581
709 def test_shutdown(self):582 def test_shutdown(self):
710 """Log when SD shutdowns."""583 """Log when SD shutdowns."""
711 self.sd.shutdown()584 self.sd.shutdown()
712 self.assertTrue(self.handler.check('INFO',585 self.assertTrue(self.hdlr.check_inf("SyncDaemon interface going down"))
713 "SyncDaemon interface going down"))586
587 @defer.inlineCallbacks
588 def test_initial_value(self):
589 """Log the initial filling."""
590 yield self.sd._get_initial_data()
591 self.assertTrue(self.hdlr.check_inf("Getting initial data"))
714592
715 def test_start(self):593 def test_start(self):
716 """Log the call to start."""594 """Log the call to start."""
717 self.sd.start()595 self.sd.start()
718 self.assertTrue(self.handler.check('INFO',596 self.assertTrue(self.hdlr.check_inf("Starting u1.SD"))
719 "Starting u1.SD"))
720597
721 def test_quit(self):598 def test_quit(self):
722 """Log the call to quit."""599 """Log the call to quit."""
723 self.sd.quit()600 self.sd.quit()
724 self.assertTrue(self.handler.check('INFO',601 self.assertTrue(self.hdlr.check_inf("Stopping u1.SD"))
725 "Stopping u1.SD"))
726602
727 def test_connect(self):603 def test_connect(self):
728 """Log the call to connect."""604 """Log the call to connect."""
729 self.sd.connect()605 self.sd.connect()
730 self.assertTrue(self.handler.check('INFO',606 self.assertTrue(self.hdlr.check_inf("Telling u1.SD to connect"))
731 "Telling u1.SD to connect"))
732607
733 def test_disconnect(self):608 def test_disconnect(self):
734 """Log the call to disconnect."""609 """Log the call to disconnect."""
735 self.sd.disconnect()610 self.sd.disconnect()
736 self.assertTrue(self.handler.check('INFO',611 self.assertTrue(self.hdlr.check_inf("Telling u1.SD to disconnect"))
737 "Telling u1.SD to disconnect"))
738612
739 def test_check_mq_true(self):613 def test_check_mq_true(self):
740 """Log the MQ check when it asks for info."""614 """Log the MQ check when it asks for info."""
741 self.sd.current_state._set(name='QUEUE_MANAGER',615 self.sd.current_state._set(name='QUEUE_MANAGER',
742 queues='WORKING_ON_METADATA')616 queues='WORKING_ON_METADATA')
743 self.sd._check_mq()617 self.sd._check_mq()
744 self.assertTrue(self.handler.check('INFO',618 self.assertTrue(self.hdlr.check_inf("Asking for MQ information"))
745 "Asking for MQ information"))
746619
747 def test_check_mq_noreally(self):620 def test_check_mq_noreally(self):
748 """Log the MQ check when it should not work."""621 """Log the MQ check when it should not work."""
749 self.sd.current_state._set(name='QUEUE_MANAGER',622 self.sd.current_state._set(name='QUEUE_MANAGER',
750 queues='WORKING_ON_CONTENT')623 queues='WORKING_ON_CONTENT')
751 self.sd._check_mq()624 self.sd._check_mq()
752 self.assertTrue(self.handler.check('INFO',625 self.assertTrue(self.hdlr.check_inf(
753 "Check MQ called but States not in MQ"))626 "Check MQ called but States not in MQ"))
754627
755 def test_process_mq_called(self):628 def test_meta_queue_changed(self):
756 """Log that process_mq is called."""629 """Log that MQ has new data."""
757 self.sd._process_mq([])630 self.sd.dbus.get_meta_queue = lambda: defer.succeed(['foo'])
758 self.assertTrue(self.handler.check('INFO', "Processing MQ data"))631 self.sd.current_state._set(name='QUEUE_MANAGER',
759632 queues='WORKING_ON_METADATA')
760 def test_process_mq_new_data(self):633 self.sd._check_mq()
761 """Log that process_mq has new data."""634 self.assertTrue(self.hdlr.check_inf("SD Meta Queue changed: 1 items"))
762 self.sd._process_mq(['AccountInquiry'])635
763 self.assertTrue(self.handler.check('INFO', "New MQ data to process"))636 def test_content_queue_changed(self):
764 self.assertTrue(self.handler.check('DEBUG',
765 "Processing MQ data: u'AccountInquiry'"))
766 self.assertTrue(self.handler.check('DEBUG',
767 " parsed: QueueData(operation="
768 "'AccountInquiry', path=None, share=None, node=None)"))
769
770 def test_process_cq_called(self):
771 """Log that process_cq is called."""
772 self.sd._process_cq([])
773 self.assertTrue(self.handler.check('INFO', "Processing CQ data"))
774
775 def test_process_cq_new_data(self):
776 """Log that process_cq has new data."""637 """Log that process_cq has new data."""
777 c = dict(operation='op', path='pth', share='shr', node='n')638 self.sd.dbus.get_content_queue = lambda: defer.succeed(['foo'])
778 self.sd._process_cq([c])639 self.sd.on_sd_content_queue_changed()
779 self.assertTrue(self.handler.check('INFO', "New CQ data to process"))640 self.assertTrue(self.hdlr.check_inf("SD Content Queue changed"))
780 self.assertTrue(self.handler.check('DEBUG',641 self.assertTrue(self.hdlr.check_inf(
781 "Processing CQ data: %r" % c))642 "Content Queue info is new! 1 items"))
782643
783 def test_on_status_changed(self):644 def test_on_status_changed(self):
784 """Log status changed."""645 """Log status changed."""
785 d = dict(name='name', description='description', is_error='',646 self.sd.on_sd_status_changed('name', 'description', False, True,
786 is_connected='True', is_online='', queues='queues',647 False, 'queues', 'connection')
787 connection='connection')648 self.assertTrue(self.hdlr.check_inf("SD Status changed"))
788 self.sd._on_status_changed(d)649 self.assertTrue(self.hdlr.check_dbg(" new status: name=u'name', "
789 self.assertTrue(self.handler.check('INFO', "New status info from SD"))650 "description=u'description', is_error=False, is_connected=True, "
790 self.assertTrue(self.handler.check('DEBUG',651 "is_online=False, queues=u'queues', connection=u'connection'"))
791 "New status from SD: %r" % d))
792652
793 def test_on_content_queue_changed(self):653 def test_folders_changed(self):
794 """Log content queue changed."""654 """Log when folders changed."""
795 self.sd._on_content_queue_changed(None)655 self.sd.on_sd_folders_changed()
796 self.assertTrue(self.handler.check('INFO', "CQ changed in u1.SD!"))656 self.assertTrue(self.hdlr.check_inf("SD Folders changed"))
797657
798 def test_on_name_owner_changed(self):658 def test_on_name_owner_changed(self):
799 """Log name owner changed."""659 """Log name owner changed."""
800 self.sd._on_name_owner_changed('com.ubuntuone.SyncDaemon', 'old', '')660 self.sd.on_sd_name_owner_changed(True)
801 self.assertTrue(self.handler.check('INFO',661 self.assertTrue(self.hdlr.check_inf("SD Name Owner changed: True"))
802 "DBus informing about SD: old: u'old' new: u''"))662
663
664class FoldersTests(BaseTest):
665 """Folders checking."""
666
667 def test_foldercreated_callback(self):
668 """Gets the new data after the folders changed."""
669 # set the callback
670 called = []
671 self.sd.dbus.get_folders = lambda: called.append(True)
672
673 # they changed!
674 self.sd.on_sd_folders_changed()
675
676 # test
677 self.assertTrue(called)
678
679 @defer.inlineCallbacks
680 def test_initial_value(self):
681 """Fills the folder info initially."""
682 called = []
683 self.sd.dbus.get_folders = lambda: called.append(True)
684 yield self.sd._get_initial_data()
685 self.assertTrue(called)

Subscribers

People subscribed via source and target branches