Merge lp:~nataliabidart/ubuntuone-control-panel/add-file-sync-buttons into lp:ubuntuone-control-panel
- add-file-sync-buttons
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Natalia Bidart | ||||
Approved revision: | 58 | ||||
Merged at revision: | 47 | ||||
Proposed branch: | lp:~nataliabidart/ubuntuone-control-panel/add-file-sync-buttons | ||||
Merge into: | lp:ubuntuone-control-panel | ||||
Diff against target: |
1129 lines (+724/-161) 9 files modified
ubuntuone/controlpanel/backend.py (+38/-2) ubuntuone/controlpanel/dbus_client.py (+24/-0) ubuntuone/controlpanel/dbus_service.py (+109/-1) ubuntuone/controlpanel/gtk/gui.py (+160/-65) ubuntuone/controlpanel/gtk/tests/__init__.py (+2/-0) ubuntuone/controlpanel/gtk/tests/test_gui.py (+191/-85) ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py (+33/-1) ubuntuone/controlpanel/integrationtests/test_dbus_service.py (+80/-0) ubuntuone/controlpanel/tests/test_backend.py (+87/-7) |
||||
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-control-panel/add-file-sync-buttons | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Roman Yepishev (community) | fieldtest | Approve | |
Review via email: mp+46681@code.launchpad.net |
Commit message
Added a button to file sync status to manage the files service (LP: #693373).
Description of the change
To test, open 2 terminals pointing to this branch and run:
terminal 1: DEBUG=True PYTHONPATH=. ./bin/ubuntuone
terminal 2: DEBUG=True PYTHONPATH=. ./bin/ubuntuone
And play with the top right corner, you'll get syncdaemon status and buttons to manage the service.
NOTE: if you stop syncdaemon from the "outside" (u1sdtool -q), you need to run this branch as syncdaemon to be able to grab the quiting state change from it: lp:~nataliabidart/ubuntuone-client/send-status-changed-when-quitting
To post a comment you must log in.
- 57. By Natalia Bidart
-
WAITING is actually disconnected.
- 58. By Natalia Bidart
-
Added tests for file sync button sensitivity.
Revision history for this message
Roman Yepishev (rye) wrote : | # |
Ok, approving since we need to have these buttons, filed LP:704895
review:
Approve
(fieldtest)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'ubuntuone/controlpanel/backend.py' |
2 | --- ubuntuone/controlpanel/backend.py 2011-01-06 20:33:15 +0000 |
3 | +++ ubuntuone/controlpanel/backend.py 2011-01-19 12:21:44 +0000 |
4 | @@ -43,6 +43,7 @@ |
5 | FILE_SYNC_ERROR = 'file-sync-error' |
6 | FILE_SYNC_IDLE = 'file-sync-idle' |
7 | FILE_SYNC_STARTING = 'file-sync-starting' |
8 | +FILE_SYNC_STOPPED = 'file-sync-stopped' |
9 | FILE_SYNC_SYNCING = 'file-sync-syncing' |
10 | FILE_SYNC_UNKNOWN = 'file-sync-unknown' |
11 | |
12 | @@ -88,9 +89,11 @@ |
13 | is_error = bool(status['is_error']) |
14 | is_synching = bool(status['is_connected']) |
15 | is_idle = bool(status['is_online']) and status['queues'] == 'IDLE' |
16 | - is_disconnected = status['name'] == 'READY' and \ |
17 | - 'Not User' in status['connection'] |
18 | + is_disconnected = status['name'] == 'WAITING' or \ |
19 | + (status['name'] == 'READY' and \ |
20 | + 'Not User' in status['connection']) |
21 | is_starting = status['name'] in ('INIT', 'LOCAL_RESCAN', 'READY') |
22 | + is_stopped = status['name'] == 'SHUTDOWN' |
23 | |
24 | if is_error: |
25 | result[STATUS_KEY] = FILE_SYNC_ERROR |
26 | @@ -102,6 +105,8 @@ |
27 | result[STATUS_KEY] = FILE_SYNC_DISCONNECTED |
28 | elif is_starting: |
29 | result[STATUS_KEY] = FILE_SYNC_STARTING |
30 | + elif is_stopped: |
31 | + result[STATUS_KEY] = FILE_SYNC_STOPPED |
32 | else: |
33 | logger.warning('file_sync_status: unknown (got %r)', status) |
34 | result[STATUS_KEY] = FILE_SYNC_UNKNOWN |
35 | @@ -289,6 +294,37 @@ |
36 | |
37 | @log_call(logger.debug) |
38 | @inlineCallbacks |
39 | + def connect_files(self): |
40 | + """Connect the files service.""" |
41 | + yield dbus_client.connect_file_sync() |
42 | + |
43 | + @log_call(logger.debug) |
44 | + @inlineCallbacks |
45 | + def disconnect_files(self): |
46 | + """Disconnect the files service.""" |
47 | + yield dbus_client.disconnect_file_sync() |
48 | + |
49 | + @log_call(logger.debug) |
50 | + @inlineCallbacks |
51 | + def restart_files(self): |
52 | + """restart the files service.""" |
53 | + yield dbus_client.stop_file_sync() |
54 | + yield dbus_client.start_file_sync() |
55 | + |
56 | + @log_call(logger.debug) |
57 | + @inlineCallbacks |
58 | + def start_files(self): |
59 | + """start the files service.""" |
60 | + yield dbus_client.start_file_sync() |
61 | + |
62 | + @log_call(logger.debug) |
63 | + @inlineCallbacks |
64 | + def stop_files(self): |
65 | + """stop the files service.""" |
66 | + yield dbus_client.stop_file_sync() |
67 | + |
68 | + @log_call(logger.debug) |
69 | + @inlineCallbacks |
70 | def volumes_info(self): |
71 | """Get the volumes info.""" |
72 | result = yield dbus_client.get_folders() |
73 | |
74 | === modified file 'ubuntuone/controlpanel/dbus_client.py' |
75 | --- ubuntuone/controlpanel/dbus_client.py 2011-01-04 21:28:51 +0000 |
76 | +++ ubuntuone/controlpanel/dbus_client.py 2011-01-19 12:21:44 +0000 |
77 | @@ -309,3 +309,27 @@ |
78 | def set_files_sync_enabled(enabled): |
79 | """Set the file sync service to be 'enabled'.""" |
80 | yield SyncDaemonTool(bus=dbus.SessionBus()).enable_files_sync(enabled) |
81 | + |
82 | + |
83 | +@defer.inlineCallbacks |
84 | +def connect_file_sync(): |
85 | + """Connect the file sync service.""" |
86 | + yield SyncDaemonTool(bus=dbus.SessionBus()).connect() |
87 | + |
88 | + |
89 | +@defer.inlineCallbacks |
90 | +def disconnect_file_sync(): |
91 | + """Disconnect the file sync service.""" |
92 | + yield SyncDaemonTool(bus=dbus.SessionBus()).disconnect() |
93 | + |
94 | + |
95 | +@defer.inlineCallbacks |
96 | +def start_file_sync(): |
97 | + """Start the file sync service.""" |
98 | + yield SyncDaemonTool(bus=dbus.SessionBus()).start() |
99 | + |
100 | + |
101 | +@defer.inlineCallbacks |
102 | +def stop_file_sync(): |
103 | + """Stop the file sync service.""" |
104 | + yield SyncDaemonTool(bus=dbus.SessionBus()).quit() |
105 | |
106 | === modified file 'ubuntuone/controlpanel/dbus_service.py' |
107 | --- ubuntuone/controlpanel/dbus_service.py 2011-01-06 20:33:15 +0000 |
108 | +++ ubuntuone/controlpanel/dbus_service.py 2011-01-19 12:21:44 +0000 |
109 | @@ -31,7 +31,8 @@ |
110 | DBUS_PREFERENCES_IFACE) |
111 | from ubuntuone.controlpanel.backend import ( |
112 | ControlBackend, FILE_SYNC_DISABLED, FILE_SYNC_DISCONNECTED, |
113 | - FILE_SYNC_ERROR, FILE_SYNC_IDLE, FILE_SYNC_STARTING, FILE_SYNC_SYNCING, |
114 | + FILE_SYNC_ERROR, FILE_SYNC_IDLE, FILE_SYNC_STARTING, FILE_SYNC_STOPPED, |
115 | + FILE_SYNC_SYNCING, |
116 | MSG_KEY, STATUS_KEY, |
117 | ) |
118 | from ubuntuone.controlpanel.logger import setup_logging, log_call |
119 | @@ -196,6 +197,8 @@ |
120 | self.FileSyncStatusDisabled(msg) |
121 | elif status == FILE_SYNC_STARTING: |
122 | self.FileSyncStatusStarting(msg) |
123 | + elif status == FILE_SYNC_STOPPED: |
124 | + self.FileSyncStatusStopped(msg) |
125 | elif status == FILE_SYNC_DISCONNECTED: |
126 | self.FileSyncStatusDisconnected(msg) |
127 | elif status == FILE_SYNC_SYNCING: |
128 | @@ -231,6 +234,11 @@ |
129 | |
130 | @log_call(logger.debug) |
131 | @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="s") |
132 | + def FileSyncStatusStopped(self, msg): |
133 | + """The file sync service is stopped.""" |
134 | + |
135 | + @log_call(logger.debug) |
136 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="s") |
137 | def FileSyncStatusDisconnected(self, msg): |
138 | """The file sync service is waiting for user to request connection.""" |
139 | |
140 | @@ -298,6 +306,106 @@ |
141 | |
142 | @log_call(logger.debug) |
143 | @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
144 | + def connect_files(self): |
145 | + """Connect the files service.""" |
146 | + d = self.backend.connect_files() |
147 | + d.addCallback(lambda _: self.FilesConnected()) |
148 | + d.addErrback(transform_failure(self.FilesConnectError)) |
149 | + |
150 | + @log_call(logger.debug) |
151 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE) |
152 | + def FilesConnected(self): |
153 | + """The files service is connected.""" |
154 | + |
155 | + @log_call(logger.error) |
156 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") |
157 | + def FilesConnectError(self, error): |
158 | + """Problem connecting the files service.""" |
159 | + |
160 | + #--- |
161 | + |
162 | + @log_call(logger.debug) |
163 | + @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
164 | + def disconnect_files(self): |
165 | + """Disconnect the files service.""" |
166 | + d = self.backend.disconnect_files() |
167 | + d.addCallback(lambda _: self.FilesDisconnected()) |
168 | + d.addErrback(transform_failure(self.FilesDisconnectError)) |
169 | + |
170 | + @log_call(logger.debug) |
171 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE) |
172 | + def FilesDisconnected(self): |
173 | + """The files service is disconnected.""" |
174 | + |
175 | + @log_call(logger.error) |
176 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") |
177 | + def FilesDisconnectError(self, error): |
178 | + """Problem disconnecting the files service.""" |
179 | + |
180 | + #--- |
181 | + |
182 | + @log_call(logger.debug) |
183 | + @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
184 | + def restart_files(self): |
185 | + """Restart the files service.""" |
186 | + d = self.backend.restart_files() |
187 | + d.addCallback(lambda _: self.FilesRestarted()) |
188 | + d.addErrback(transform_failure(self.FilesRestartError)) |
189 | + |
190 | + @log_call(logger.debug) |
191 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE) |
192 | + def FilesRestarted(self): |
193 | + """The files service is restarted.""" |
194 | + |
195 | + @log_call(logger.error) |
196 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") |
197 | + def FilesRestartError(self, error): |
198 | + """Problem restarting the files service.""" |
199 | + |
200 | + #--- |
201 | + |
202 | + @log_call(logger.debug) |
203 | + @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
204 | + def start_files(self): |
205 | + """Start the files service.""" |
206 | + d = self.backend.start_files() |
207 | + d.addCallback(lambda _: self.FilesStarted()) |
208 | + d.addErrback(transform_failure(self.FilesStartError)) |
209 | + |
210 | + @log_call(logger.debug) |
211 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE) |
212 | + def FilesStarted(self): |
213 | + """The files service is started.""" |
214 | + |
215 | + @log_call(logger.error) |
216 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") |
217 | + def FilesStartError(self, error): |
218 | + """Problem starting the files service.""" |
219 | + |
220 | + #--- |
221 | + |
222 | + @log_call(logger.debug) |
223 | + @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
224 | + def stop_files(self): |
225 | + """Stop the files service.""" |
226 | + d = self.backend.stop_files() |
227 | + d.addCallback(lambda _: self.FilesStopped()) |
228 | + d.addErrback(transform_failure(self.FilesStopError)) |
229 | + |
230 | + @log_call(logger.debug) |
231 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE) |
232 | + def FilesStopped(self): |
233 | + """The files service is stopped.""" |
234 | + |
235 | + @log_call(logger.error) |
236 | + @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") |
237 | + def FilesStopError(self, error): |
238 | + """Problem stopping the files service.""" |
239 | + |
240 | + #--- |
241 | + |
242 | + @log_call(logger.debug) |
243 | + @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
244 | def volumes_info(self): |
245 | """Find out the volumes info for the logged in user.""" |
246 | d = self.backend.volumes_info() |
247 | |
248 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' |
249 | --- ubuntuone/controlpanel/gtk/gui.py 2011-01-06 20:18:29 +0000 |
250 | +++ ubuntuone/controlpanel/gtk/gui.py 2011-01-19 12:21:44 +0000 |
251 | @@ -1048,40 +1048,41 @@ |
252 | self.on_error() |
253 | |
254 | |
255 | -class ManagementPanel(gtk.VBox, ControlPanelMixin): |
256 | - """The management panel. |
257 | - |
258 | - The user can manage dashboard, folders, devices and services. |
259 | - |
260 | - """ |
261 | - |
262 | - QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)') |
263 | - FILE_SYNC_DISABLED = _('File synchronization service is not enabled.') |
264 | - FILE_SYNC_STARTING = _('File synchronization service is starting,\n' |
265 | - 'please wait...') |
266 | - FILE_SYNC_DISCONNECTED = _('File synchronization service is ready,\nplease' |
267 | - ' connect it to access your personal cloud. ') |
268 | - FILE_SYNC_SYNCING = _('File synchronization service is fully functional,\n' |
269 | - 'performing synchronization now...') |
270 | - FILE_SYNC_IDLE = _('File synchronization service is idle,\n' |
271 | - 'all the files are synchronized.') |
272 | - FILE_SYNC_ERROR = _('File synchronization status can not be retrieved.') |
273 | +class FileSyncStatus(gtk.HBox, ControlPanelMixin): |
274 | + """A file sync status widget.""" |
275 | + |
276 | + FILE_SYNC_DISABLED = _('File synchronization is disabled.') |
277 | + FILE_SYNC_STARTING = _('File synchronization starting...') |
278 | + FILE_SYNC_STOPPED = _('File synchronization is stopped.') |
279 | + FILE_SYNC_DISCONNECTED = _('File synchronization is disconnected.') |
280 | + FILE_SYNC_SYNCING = _('Synchronization in progress...') |
281 | + FILE_SYNC_IDLE = _('All files up-to-date.') |
282 | + FILE_SYNC_ERROR = _('File synchronization error.') |
283 | + |
284 | + CONNECT = _('Connect') |
285 | + DISCONNECT = _('Disconnect') |
286 | + ENABLE = _('Enable') |
287 | + RESTART = _('Restart') |
288 | + START = _('Start') |
289 | + STOP = _('Stop') |
290 | |
291 | def __init__(self): |
292 | - gtk.VBox.__init__(self) |
293 | - ControlPanelMixin.__init__(self, filename='management.ui') |
294 | - self.add(self.itself) |
295 | - self.show() |
296 | - |
297 | - self.backend.connect_to_signal('AccountInfoReady', |
298 | - self.on_account_info_ready) |
299 | - self.backend.connect_to_signal('AccountInfoError', |
300 | - self.on_account_info_error) |
301 | + gtk.HBox.__init__(self) |
302 | + ControlPanelMixin.__init__(self) |
303 | + |
304 | + self.label = LabelLoading(LOADING, fg_color=DEFAULT_FG) |
305 | + self.pack_start(self.label, expand=False) |
306 | + |
307 | + self.button = gtk.LinkButton(uri='') |
308 | + self.button.connect('clicked', self._on_button_clicked) |
309 | + self.pack_start(self.button, expand=False) |
310 | |
311 | self.backend.connect_to_signal('FileSyncStatusDisabled', |
312 | self.on_file_sync_status_disabled) |
313 | self.backend.connect_to_signal('FileSyncStatusStarting', |
314 | self.on_file_sync_status_starting) |
315 | + self.backend.connect_to_signal('FileSyncStatusStopped', |
316 | + self.on_file_sync_status_stopped) |
317 | self.backend.connect_to_signal('FileSyncStatusDisconnected', |
318 | self.on_file_sync_status_disconnected) |
319 | self.backend.connect_to_signal('FileSyncStatusSyncing', |
320 | @@ -1090,13 +1091,144 @@ |
321 | self.on_file_sync_status_idle) |
322 | self.backend.connect_to_signal('FileSyncStatusError', |
323 | self.on_file_sync_status_error) |
324 | + self.backend.connect_to_signal('FilesStartError', |
325 | + self.on_files_start_error) |
326 | + |
327 | + self.backend.file_sync_status(reply_handler=NO_OP, |
328 | + error_handler=error_handler) |
329 | + self.show_all() |
330 | + |
331 | + def _update_status(self, msg, action, callback, icon=None, color=None): |
332 | + """Update the status info.""" |
333 | + if icon is not None: |
334 | + foreground = '' if color is None else 'foreground="%s"' % color |
335 | + msg = '<span %s>%s</span> %s' % (foreground, icon, msg) |
336 | + self.label.set_markup(msg) |
337 | + self.label.stop() |
338 | + |
339 | + self.button.set_label(action) |
340 | + self.button.set_sensitive(True) |
341 | + self.button.set_data('callback', callback) |
342 | + |
343 | + def _on_button_clicked(self, button): |
344 | + """Button was clicked, act accordingly the label.""" |
345 | + button.set_visited(False) |
346 | + button.set_sensitive(False) |
347 | + button.get_data('callback')(button) |
348 | + |
349 | + @log_call(logger.info) |
350 | + def on_file_sync_status_disabled(self, msg): |
351 | + """Backend notifies of file sync status being disabled.""" |
352 | + self._update_status(self.FILE_SYNC_DISABLED, |
353 | + self.ENABLE, self.on_enable_clicked, |
354 | + '✘', 'red') |
355 | + |
356 | + @log_call(logger.info) |
357 | + def on_file_sync_status_starting(self, msg): |
358 | + """Backend notifies of file sync status being starting.""" |
359 | + self._update_status(self.FILE_SYNC_STARTING, |
360 | + self.STOP, self.on_stop_clicked, |
361 | + '⇅', ORANGE) |
362 | + |
363 | + @log_call(logger.info) |
364 | + def on_file_sync_status_stopped(self, msg): |
365 | + """Backend notifies of file sync being stopped.""" |
366 | + self._update_status(self.FILE_SYNC_STOPPED, |
367 | + self.START, self.on_start_clicked, |
368 | + '✘', 'red') |
369 | + |
370 | + @log_call(logger.info) |
371 | + def on_file_sync_status_disconnected(self, msg): |
372 | + """Backend notifies of file sync status being ready.""" |
373 | + self._update_status(self.FILE_SYNC_DISCONNECTED, |
374 | + self.CONNECT, self.on_connect_clicked, |
375 | + '✘', 'red') |
376 | + |
377 | + @log_call(logger.info) |
378 | + def on_file_sync_status_syncing(self, msg): |
379 | + """Backend notifies of file sync status being syncing.""" |
380 | + self._update_status(self.FILE_SYNC_SYNCING, |
381 | + self.DISCONNECT, self.on_disconnect_clicked, |
382 | + '⇅', ORANGE) |
383 | + |
384 | + @log_call(logger.info) |
385 | + def on_file_sync_status_idle(self, msg): |
386 | + """Backend notifies of file sync status being idle.""" |
387 | + self._update_status(self.FILE_SYNC_IDLE, |
388 | + self.DISCONNECT, self.on_disconnect_clicked, |
389 | + '✔', 'green') |
390 | + |
391 | + @log_call(logger.error) |
392 | + def on_file_sync_status_error(self, error_dict=None): |
393 | + """Backend notifies of an error when fetching file sync status.""" |
394 | + self._update_status(WARNING_MARKUP % self.FILE_SYNC_ERROR, |
395 | + self.RESTART, self.on_restart_clicked) |
396 | + |
397 | + @log_call(logger.error) |
398 | + def on_files_start_error(self, error_dict=None): |
399 | + """Backend notifies of an error when starting the files service.""" |
400 | + # service is probably disabled, ask for status to backend |
401 | + self.backend.file_sync_status(reply_handler=NO_OP, |
402 | + error_handler=error_handler) |
403 | + |
404 | + def on_connect_clicked(self, button=None): |
405 | + """User requested connection.""" |
406 | + self.backend.connect_files(reply_handler=NO_OP, |
407 | + error_handler=error_handler) |
408 | + |
409 | + def on_disconnect_clicked(self, button=None): |
410 | + """User requested disconnection.""" |
411 | + self.backend.disconnect_files(reply_handler=NO_OP, |
412 | + error_handler=error_handler) |
413 | + |
414 | + def on_enable_clicked(self, button=None): |
415 | + """User requested enable the service.""" |
416 | + self.backend.enable_files(reply_handler=NO_OP, |
417 | + error_handler=error_handler) |
418 | + |
419 | + def on_restart_clicked(self, button=None): |
420 | + """User requested restart the service.""" |
421 | + self.backend.restart_files(reply_handler=NO_OP, |
422 | + error_handler=error_handler) |
423 | + |
424 | + def on_start_clicked(self, button=None): |
425 | + """User requested start the service.""" |
426 | + self.backend.start_files(reply_handler=NO_OP, |
427 | + error_handler=error_handler) |
428 | + |
429 | + def on_stop_clicked(self, button=None): |
430 | + """User requested stop the service.""" |
431 | + self.backend.stop_files(reply_handler=NO_OP, |
432 | + error_handler=error_handler) |
433 | + |
434 | + |
435 | +class ManagementPanel(gtk.VBox, ControlPanelMixin): |
436 | + """The management panel. |
437 | + |
438 | + The user can manage dashboard, folders, devices and services. |
439 | + |
440 | + """ |
441 | + |
442 | + QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)') |
443 | + |
444 | + def __init__(self): |
445 | + gtk.VBox.__init__(self) |
446 | + ControlPanelMixin.__init__(self, filename='management.ui') |
447 | + self.add(self.itself) |
448 | + self.show() |
449 | + |
450 | + self.backend.connect_to_signal('AccountInfoReady', |
451 | + self.on_account_info_ready) |
452 | + self.backend.connect_to_signal('AccountInfoError', |
453 | + self.on_account_info_error) |
454 | |
455 | self.header.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(DEFAULT_BG)) |
456 | |
457 | + self.quota_progressbar.set_sensitive(False) |
458 | self.quota_label = LabelLoading(LOADING, fg_color=DEFAULT_FG) |
459 | self.quota_box.pack_start(self.quota_label, expand=False) |
460 | |
461 | - self.status_label = LabelLoading(LOADING, fg_color=DEFAULT_FG) |
462 | + self.status_label = FileSyncStatus() |
463 | self.status_box.pack_end(self.status_label, expand=False) |
464 | |
465 | self.dashboard = DashboardPanel() |
466 | @@ -1131,17 +1263,10 @@ |
467 | fraction = data.get('percentage', 0.0) / 100 |
468 | self.quota_progressbar.set_fraction(fraction) |
469 | |
470 | - def _update_status(self, msg): |
471 | - """Update the status info.""" |
472 | - self.status_label.set_markup(msg) |
473 | - self.status_label.stop() |
474 | - |
475 | def load(self): |
476 | """Load the account info and file sync status list.""" |
477 | self.backend.account_info(reply_handler=NO_OP, |
478 | error_handler=error_handler) |
479 | - self.backend.file_sync_status(reply_handler=NO_OP, |
480 | - error_handler=error_handler) |
481 | self.dashboard_button.clicked() |
482 | |
483 | @log_call(logger.debug) |
484 | @@ -1158,36 +1283,6 @@ |
485 | """Backend notifies of an error when fetching account info.""" |
486 | self._update_quota(WARNING_MARKUP % VALUE_ERROR) |
487 | |
488 | - @log_call(logger.info) |
489 | - def on_file_sync_status_disabled(self, msg): |
490 | - """Backend notifies of file sync status being disabled.""" |
491 | - self._update_status(self.FILE_SYNC_DISABLED) |
492 | - |
493 | - @log_call(logger.info) |
494 | - def on_file_sync_status_starting(self, msg): |
495 | - """Backend notifies of file sync status being starting.""" |
496 | - self._update_status(self.FILE_SYNC_STARTING) |
497 | - |
498 | - @log_call(logger.info) |
499 | - def on_file_sync_status_disconnected(self, msg): |
500 | - """Backend notifies of file sync status being ready.""" |
501 | - self._update_status(self.FILE_SYNC_DISCONNECTED) |
502 | - |
503 | - @log_call(logger.info) |
504 | - def on_file_sync_status_syncing(self, msg): |
505 | - """Backend notifies of file sync status being syncing.""" |
506 | - self._update_status(self.FILE_SYNC_SYNCING) |
507 | - |
508 | - @log_call(logger.info) |
509 | - def on_file_sync_status_idle(self, msg): |
510 | - """Backend notifies of file sync status being idle.""" |
511 | - self._update_status(self.FILE_SYNC_IDLE) |
512 | - |
513 | - @log_call(logger.error) |
514 | - def on_file_sync_status_error(self, error_dict=None): |
515 | - """Backend notifies of an error when fetching file sync status.""" |
516 | - self._update_status(WARNING_MARKUP % self.FILE_SYNC_ERROR) |
517 | - |
518 | |
519 | gobject.signal_new('credentials-found', OverviewPanel, |
520 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, |
521 | |
522 | === modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py' |
523 | --- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-05 21:04:07 +0000 |
524 | +++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-19 12:21:44 +0000 |
525 | @@ -131,6 +131,8 @@ |
526 | 'volumes_info', 'change_volume_settings', # volumes |
527 | 'replications_info', 'change_replication_settings', # replications |
528 | 'file_sync_status', 'enable_files', 'disable_files', # files |
529 | + 'connect_files', 'disconnect_files', |
530 | + 'restart_files', 'start_files', 'stop_files', |
531 | ] |
532 | |
533 | |
534 | |
535 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' |
536 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-06 20:18:29 +0000 |
537 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-19 12:21:44 +0000 |
538 | @@ -1795,6 +1795,179 @@ |
539 | self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR) |
540 | |
541 | |
542 | +class FileSyncStatusTestCase(ControlPanelMixinTestCase): |
543 | + """Test case for a file sync status widget.""" |
544 | + |
545 | + klass = gui.FileSyncStatus |
546 | + |
547 | + def assert_status_correct(self, status, action=None, callback=None): |
548 | + """The shown status is correct. |
549 | + |
550 | + * The ui's label shows 'status'. |
551 | + * If action is not None, the ui's button shows that 'action' as label |
552 | + and when clicking it, 'self._set_called' gets executed. |
553 | + * If action is None, the ui's button should be hidden. |
554 | + |
555 | + """ |
556 | + self.assertTrue(self.ui.label.get_visible()) |
557 | + self.assertFalse(self.ui.label.active) |
558 | + self.assertTrue(self.ui.label.get_label().endswith(status)) |
559 | + |
560 | + self.assertTrue(self.ui.button.is_sensitive()) |
561 | + self.assertFalse(self.ui.button.get_visited()) |
562 | + |
563 | + if action is not None: |
564 | + self.assertTrue(self.ui.button.get_visible()) |
565 | + self.assertTrue(self.ui.button.get_sensitive()) |
566 | + self.assertEqual(self.ui.button.get_label(), action) |
567 | + |
568 | + self.ui.button.clicked() |
569 | + self.assertFalse(self.ui.button.get_visited()) |
570 | + self.assertFalse(self.ui.button.get_sensitive()) |
571 | + self.assertEqual(self._called, ((self.ui.button,), {})) |
572 | + else: |
573 | + self.assertFalse(self.ui.button.get_visible()) |
574 | + |
575 | + def test_is_a_box(self): |
576 | + """Inherits from gtk.Box.""" |
577 | + self.assertIsInstance(self.ui, gui.gtk.Box) |
578 | + |
579 | + def test_startup_visibility(self): |
580 | + """The widget is visible at startup.""" |
581 | + self.assertTrue(self.ui.get_visible(), |
582 | + 'must be visible at startup.') |
583 | + |
584 | + def test_label(self): |
585 | + """The label is packed.""" |
586 | + self.assertIsInstance(self.ui.label, gui.LabelLoading) |
587 | + self.assertTrue(self.ui.label.active) |
588 | + self.assertIn(self.ui.label, self.ui.get_children()) |
589 | + |
590 | + def test_button(self): |
591 | + """The button is packed.""" |
592 | + self.assertIn(self.ui.button, self.ui.get_children()) |
593 | + |
594 | + def test_backend_file_sync_signals(self): |
595 | + """The proper signals are connected to the backend.""" |
596 | + matches = ( |
597 | + # status |
598 | + ('FileSyncStatusDisabled', [self.ui.on_file_sync_status_disabled]), |
599 | + ('FileSyncStatusStarting', [self.ui.on_file_sync_status_starting]), |
600 | + ('FileSyncStatusStopped', [self.ui.on_file_sync_status_stopped]), |
601 | + ('FileSyncStatusDisconnected', |
602 | + [self.ui.on_file_sync_status_disconnected]), |
603 | + ('FileSyncStatusSyncing', [self.ui.on_file_sync_status_syncing]), |
604 | + ('FileSyncStatusIdle', [self.ui.on_file_sync_status_idle]), |
605 | + ('FileSyncStatusError', [self.ui.on_file_sync_status_error]), |
606 | + ('FilesStartError', [self.ui.on_files_start_error]), |
607 | + ) |
608 | + for sig, handlers in matches: |
609 | + self.assertEqual(self.ui.backend._signals[sig], handlers) |
610 | + |
611 | + def test_file_sync_status_is_requested(self): |
612 | + """The file sync status is requested to the backend.""" |
613 | + self.assert_backend_called('file_sync_status', ()) |
614 | + |
615 | + def test_on_file_sync_status_disabled(self): |
616 | + """The file sync is disabled.""" |
617 | + self.patch(self.ui, 'on_enable_clicked', self._set_called) |
618 | + self.ui.on_file_sync_status_disabled('msg') |
619 | + |
620 | + self.assert_status_correct(self.ui.FILE_SYNC_DISABLED, |
621 | + action=self.ui.ENABLE) |
622 | + |
623 | + def test_on_file_sync_status_starting(self): |
624 | + """The file sync status is starting.""" |
625 | + self.patch(self.ui, 'on_stop_clicked', self._set_called) |
626 | + self.ui.on_file_sync_status_starting('msg') |
627 | + |
628 | + self.assert_status_correct(self.ui.FILE_SYNC_STARTING, |
629 | + action=self.ui.STOP) |
630 | + |
631 | + def test_on_file_sync_status_stopped(self): |
632 | + """The file sync is stopped.""" |
633 | + self.patch(self.ui, 'on_start_clicked', self._set_called) |
634 | + self.ui.on_file_sync_status_stopped('msg') |
635 | + |
636 | + self.assert_status_correct(self.ui.FILE_SYNC_STOPPED, |
637 | + action=self.ui.START) |
638 | + |
639 | + def test_on_file_sync_status_disconnected(self): |
640 | + """The file sync status is disconnected.""" |
641 | + self.patch(self.ui, 'on_connect_clicked', self._set_called) |
642 | + self.ui.on_file_sync_status_disconnected('msg') |
643 | + |
644 | + self.assert_status_correct(self.ui.FILE_SYNC_DISCONNECTED, |
645 | + action=self.ui.CONNECT) |
646 | + |
647 | + def test_on_file_sync_status_syncing(self): |
648 | + """The file sync status is syncing.""" |
649 | + self.patch(self.ui, 'on_disconnect_clicked', self._set_called) |
650 | + self.ui.on_file_sync_status_syncing('msg') |
651 | + |
652 | + self.assert_status_correct(self.ui.FILE_SYNC_SYNCING, |
653 | + action=self.ui.DISCONNECT) |
654 | + |
655 | + def test_on_file_sync_status_idle(self): |
656 | + """The file sync status is idle.""" |
657 | + self.patch(self.ui, 'on_disconnect_clicked', self._set_called) |
658 | + self.ui.on_file_sync_status_idle('msg') |
659 | + |
660 | + self.assert_status_correct(self.ui.FILE_SYNC_IDLE, |
661 | + action=self.ui.DISCONNECT) |
662 | + |
663 | + def test_on_file_sync_status_error(self): |
664 | + """The file sync status couldn't be retrieved.""" |
665 | + self.patch(self.ui, 'on_restart_clicked', self._set_called) |
666 | + self.ui.on_file_sync_status_error({'error_msg': 'error msg'}) |
667 | + |
668 | + msg = gui.WARNING_MARKUP % self.ui.FILE_SYNC_ERROR |
669 | + self.assert_status_correct(msg, action=self.ui.RESTART) |
670 | + |
671 | + def test_on_files_start_error(self): |
672 | + """The files service could not be started.""" |
673 | + self.ui.backend._called.clear() |
674 | + self.ui.on_files_start_error({'error_msg': 'error msg'}) |
675 | + |
676 | + self.assert_backend_called('file_sync_status', ()) |
677 | + |
678 | + def test_on_connect_clicked(self): |
679 | + """User requested connection.""" |
680 | + self.ui.on_connect_clicked(self.ui.button) |
681 | + |
682 | + self.assert_backend_called('connect_files', ()) |
683 | + |
684 | + def test_on_disconnect_clicked(self): |
685 | + """User requested disconnection.""" |
686 | + self.ui.on_disconnect_clicked(self.ui.button) |
687 | + |
688 | + self.assert_backend_called('disconnect_files', ()) |
689 | + |
690 | + def test_on_enable_clicked(self): |
691 | + """User requested enable the service.""" |
692 | + self.ui.on_enable_clicked(self.ui.button) |
693 | + |
694 | + self.assert_backend_called('enable_files', ()) |
695 | + |
696 | + def test_on_restart_clicked(self): |
697 | + """User requested restart the service.""" |
698 | + self.ui.on_restart_clicked(self.ui.button) |
699 | + |
700 | + self.assert_backend_called('restart_files', ()) |
701 | + |
702 | + def test_on_start_clicked(self): |
703 | + """User requested start the service.""" |
704 | + self.ui.on_start_clicked(self.ui.button) |
705 | + |
706 | + self.assert_backend_called('start_files', ()) |
707 | + |
708 | + def test_on_stop_clicked(self): |
709 | + """User requested stop the service.""" |
710 | + self.ui.on_stop_clicked(self.ui.button) |
711 | + |
712 | + self.assert_backend_called('stop_files', ()) |
713 | + |
714 | + |
715 | class ManagementPanelTestCase(ControlPanelMixinTestCase): |
716 | """The test suite for the management panel.""" |
717 | |
718 | @@ -1925,93 +2098,26 @@ |
719 | self.assertIsInstance(self.ui.quota_label, gui.LabelLoading) |
720 | self.assertIn(self.ui.quota_label, self.ui.quota_box.get_children()) |
721 | |
722 | - def test_file_sync_status_placeholder_is_loading(self): |
723 | - """Placeholders for file sync label is a Loading widget.""" |
724 | - self.assertIsInstance(self.ui.status_label, gui.LabelLoading) |
725 | + def test_on_account_info_ready(self): |
726 | + """The account info is processed when ready.""" |
727 | + self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO) |
728 | + self.assert_account_info_correct(FAKE_ACCOUNT_INFO) |
729 | + |
730 | + for widget in (self.ui.quota_label,): |
731 | + self.assertFalse(widget.active) |
732 | + |
733 | + def test_on_account_info_error(self): |
734 | + """The account info couldn't be retrieved.""" |
735 | + self.ui.on_account_info_error() |
736 | + for widget in (self.ui.quota_label,): |
737 | + self.assert_warning_correct(widget, gui.VALUE_ERROR) |
738 | + self.assertFalse(widget.active) |
739 | + |
740 | + def test_file_sync_status(self): |
741 | + """The file sync status is shown correctly.""" |
742 | + self.assertIsInstance(self.ui.status_label, gui.FileSyncStatus) |
743 | self.assertIn(self.ui.status_label, self.ui.status_box.get_children()) |
744 | |
745 | - def test_on_account_info_ready(self): |
746 | - """The account info is processed when ready.""" |
747 | - self.ui.on_account_info_ready(FAKE_ACCOUNT_INFO) |
748 | - self.assert_account_info_correct(FAKE_ACCOUNT_INFO) |
749 | - |
750 | - for widget in (self.ui.quota_label,): |
751 | - self.assertFalse(widget.active) |
752 | - |
753 | - def test_on_account_info_error(self): |
754 | - """The account info couldn't be retrieved.""" |
755 | - self.ui.on_account_info_error() |
756 | - for widget in (self.ui.quota_label,): |
757 | - self.assert_warning_correct(widget, gui.VALUE_ERROR) |
758 | - self.assertFalse(widget.active) |
759 | - |
760 | - def test_backend_file_sync_signals(self): |
761 | - """The proper signals are connected to the backend.""" |
762 | - matches = ( |
763 | - ('FileSyncStatusDisabled', [self.ui.on_file_sync_status_disabled]), |
764 | - ('FileSyncStatusStarting', [self.ui.on_file_sync_status_starting]), |
765 | - ('FileSyncStatusDisconnected', |
766 | - [self.ui.on_file_sync_status_disconnected]), |
767 | - ('FileSyncStatusSyncing', [self.ui.on_file_sync_status_syncing]), |
768 | - ('FileSyncStatusIdle', [self.ui.on_file_sync_status_idle]), |
769 | - ('FileSyncStatusError', [self.ui.on_file_sync_status_error]), |
770 | - ) |
771 | - for sig, handlers in matches: |
772 | - self.assertEqual(self.ui.backend._signals[sig], handlers) |
773 | - |
774 | - def test_file_sync_status_is_requested_on_load(self): |
775 | - """The file sync status is requested to the backend.""" |
776 | - self.ui.load() |
777 | - self.assert_backend_called('file_sync_status', ()) |
778 | - |
779 | - def test_on_file_sync_status_disabled(self): |
780 | - """The file sync is disabled.""" |
781 | - self.ui.on_file_sync_status_disabled('msg') |
782 | - |
783 | - self.assertFalse(self.ui.status_label.active) |
784 | - self.assertEqual(self.ui.status_label.get_text(), |
785 | - self.ui.FILE_SYNC_DISABLED) |
786 | - |
787 | - def test_on_file_sync_status_starting(self): |
788 | - """The file sync status is starting.""" |
789 | - self.ui.on_file_sync_status_starting('msg') |
790 | - |
791 | - self.assertFalse(self.ui.status_label.active) |
792 | - self.assertEqual(self.ui.status_label.get_text(), |
793 | - self.ui.FILE_SYNC_STARTING) |
794 | - |
795 | - def test_on_file_sync_status_disconnected(self): |
796 | - """The file sync status is disconnected.""" |
797 | - self.ui.on_file_sync_status_disconnected('msg') |
798 | - |
799 | - self.assertFalse(self.ui.status_label.active) |
800 | - self.assertEqual(self.ui.status_label.get_text(), |
801 | - self.ui.FILE_SYNC_DISCONNECTED) |
802 | - |
803 | - def test_on_file_sync_status_syncing(self): |
804 | - """The file sync status is syncing.""" |
805 | - self.ui.on_file_sync_status_syncing('msg') |
806 | - |
807 | - self.assertFalse(self.ui.status_label.active) |
808 | - self.assertEqual(self.ui.status_label.get_text(), |
809 | - self.ui.FILE_SYNC_SYNCING) |
810 | - |
811 | - def test_on_file_sync_status_idle(self): |
812 | - """The file sync status is idle.""" |
813 | - self.ui.on_file_sync_status_idle('msg') |
814 | - |
815 | - self.assertFalse(self.ui.status_label.active) |
816 | - self.assertEqual(self.ui.status_label.get_text(), |
817 | - self.ui.FILE_SYNC_IDLE) |
818 | - |
819 | - def test_on_file_sync_status_error(self): |
820 | - """The file sync status couldn't be retrieved.""" |
821 | - self.ui.on_file_sync_status_error({'error_msg': 'error msg'}) |
822 | - |
823 | - self.assert_warning_correct(self.ui.status_label, |
824 | - self.ui.FILE_SYNC_ERROR) |
825 | - self.assertFalse(self.ui.status_label.active) |
826 | - |
827 | def test_local_device_removed_is_emitted(self): |
828 | """Signal local-device-removed is sent when DevicesPanel emits it.""" |
829 | self.ui.connect('local-device-removed', self._set_called) |
830 | |
831 | === modified file 'ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py' |
832 | --- ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py 2010-12-13 22:13:05 +0000 |
833 | +++ ubuntuone/controlpanel/integrationtests/test_dbus_client_sd.py 2011-01-19 12:21:44 +0000 |
834 | @@ -507,7 +507,39 @@ |
835 | self.patch(dbus_client.SyncDaemonTool, 'enable_files_sync', |
836 | self._set_called) |
837 | expected = object() |
838 | - # set the opposite value |
839 | + # set some unique value |
840 | yield dbus_client.set_files_sync_enabled(expected) |
841 | |
842 | self.assertEqual(self._called, ((expected,), {})) |
843 | + |
844 | + @inlineCallbacks |
845 | + def test_connect_file_sync(self): |
846 | + """Set if file sync is enabled or not.""" |
847 | + self.patch(dbus_client.SyncDaemonTool, 'connect', self._set_called) |
848 | + yield dbus_client.connect_file_sync() |
849 | + |
850 | + self.assertEqual(self._called, ((), {})) |
851 | + |
852 | + @inlineCallbacks |
853 | + def test_disconnect_file_sync(self): |
854 | + """Set if file sync is enabled or not.""" |
855 | + self.patch(dbus_client.SyncDaemonTool, 'disconnect', self._set_called) |
856 | + yield dbus_client.disconnect_file_sync() |
857 | + |
858 | + self.assertEqual(self._called, ((), {})) |
859 | + |
860 | + @inlineCallbacks |
861 | + def test_start_file_sync(self): |
862 | + """Set if file sync is enabled or not.""" |
863 | + self.patch(dbus_client.SyncDaemonTool, 'start', self._set_called) |
864 | + yield dbus_client.start_file_sync() |
865 | + |
866 | + self.assertEqual(self._called, ((), {})) |
867 | + |
868 | + @inlineCallbacks |
869 | + def test_stop_file_sync(self): |
870 | + """Set if file sync is enabled or not.""" |
871 | + self.patch(dbus_client.SyncDaemonTool, 'quit', self._set_called) |
872 | + yield dbus_client.stop_file_sync() |
873 | + |
874 | + self.assertEqual(self._called, ((), {})) |
875 | |
876 | === modified file 'ubuntuone/controlpanel/integrationtests/test_dbus_service.py' |
877 | --- ubuntuone/controlpanel/integrationtests/test_dbus_service.py 2011-01-06 20:33:15 +0000 |
878 | +++ ubuntuone/controlpanel/integrationtests/test_dbus_service.py 2011-01-19 12:21:44 +0000 |
879 | @@ -163,6 +163,26 @@ |
880 | """Disable files service.""" |
881 | return self._process(None) |
882 | |
883 | + def connect_files(self): |
884 | + """Connect files service.""" |
885 | + return self._process(None) |
886 | + |
887 | + def disconnect_files(self): |
888 | + """Disconnect files service.""" |
889 | + return self._process(None) |
890 | + |
891 | + def restart_files(self): |
892 | + """Restart the files service.""" |
893 | + return self._process(None) |
894 | + |
895 | + def start_files(self): |
896 | + """Start the files service.""" |
897 | + return self._process(None) |
898 | + |
899 | + def stop_files(self): |
900 | + """Stop the files service.""" |
901 | + return self._process(None) |
902 | + |
903 | def volumes_info(self): |
904 | """Get the user volumes info.""" |
905 | return self._process(SAMPLE_VOLUMES_INFO) |
906 | @@ -435,6 +455,61 @@ |
907 | self.backend.disable_files) |
908 | return self.assert_correct_method_call(*args) |
909 | |
910 | + def test_connect_files(self): |
911 | + """Connect files service.""" |
912 | + |
913 | + def got_signal(): |
914 | + """The correct signal was received.""" |
915 | + self.deferred.callback("success") |
916 | + |
917 | + args = ("FilesConnected", "FilesConnectError", got_signal, |
918 | + self.backend.connect_files) |
919 | + return self.assert_correct_method_call(*args) |
920 | + |
921 | + def test_disconnect_files(self): |
922 | + """Disconnect files service.""" |
923 | + |
924 | + def got_signal(): |
925 | + """The correct signal was received.""" |
926 | + self.deferred.callback("success") |
927 | + |
928 | + args = ("FilesDisconnected", "FilesDisconnectError", got_signal, |
929 | + self.backend.disconnect_files) |
930 | + return self.assert_correct_method_call(*args) |
931 | + |
932 | + def test_restart_files(self): |
933 | + """Restart files service.""" |
934 | + |
935 | + def got_signal(): |
936 | + """The correct signal was received.""" |
937 | + self.deferred.callback("success") |
938 | + |
939 | + args = ("FilesRestarted", "FilesRestartError", got_signal, |
940 | + self.backend.restart_files) |
941 | + return self.assert_correct_method_call(*args) |
942 | + |
943 | + def test_start_files(self): |
944 | + """Start files service.""" |
945 | + |
946 | + def got_signal(): |
947 | + """The correct signal was received.""" |
948 | + self.deferred.callback("success") |
949 | + |
950 | + args = ("FilesStarted", "FilesStartError", got_signal, |
951 | + self.backend.start_files) |
952 | + return self.assert_correct_method_call(*args) |
953 | + |
954 | + def test_stop_files(self): |
955 | + """Stop files service.""" |
956 | + |
957 | + def got_signal(): |
958 | + """The correct signal was received.""" |
959 | + self.deferred.callback("success") |
960 | + |
961 | + args = ("FilesStopped", "FilesStopError", got_signal, |
962 | + self.backend.stop_files) |
963 | + return self.assert_correct_method_call(*args) |
964 | + |
965 | def test_volumes_info(self): |
966 | """The volumes info is reported.""" |
967 | |
968 | @@ -589,6 +664,11 @@ |
969 | args = (dbus_service.FILE_SYNC_STARTING, "FileSyncStatusStarting") |
970 | return self.assert_correct_status_signal(*args) |
971 | |
972 | + def test_file_sync_status_stopped(self): |
973 | + """The file sync status is reported properly.""" |
974 | + args = (dbus_service.FILE_SYNC_STOPPED, "FileSyncStatusStopped") |
975 | + return self.assert_correct_status_signal(*args) |
976 | + |
977 | def test_file_sync_status_disconnected(self): |
978 | """The file sync status is reported properly.""" |
979 | args = (dbus_service.FILE_SYNC_DISCONNECTED, |
980 | |
981 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' |
982 | --- ubuntuone/controlpanel/tests/test_backend.py 2011-01-06 20:33:15 +0000 |
983 | +++ ubuntuone/controlpanel/tests/test_backend.py 2011-01-19 12:21:44 +0000 |
984 | @@ -33,6 +33,7 @@ |
985 | FILE_SYNC_ERROR, |
986 | FILE_SYNC_IDLE, |
987 | FILE_SYNC_STARTING, |
988 | + FILE_SYNC_STOPPED, |
989 | FILE_SYNC_SYNCING, |
990 | FILE_SYNC_UNKNOWN, |
991 | MSG_KEY, STATUS_KEY, |
992 | @@ -85,6 +86,7 @@ |
993 | } |
994 | status_changed_handler = None |
995 | subscribed_folders = [] |
996 | + actions = [] |
997 | |
998 | def get_credentials(self): |
999 | """Return the mock credentials.""" |
1000 | @@ -124,6 +126,22 @@ |
1001 | """Set the file sync service to be 'enabled'.""" |
1002 | MockDBusClient.file_sync = enabled |
1003 | |
1004 | + def connect_file_sync(self): |
1005 | + """Connect files service.""" |
1006 | + MockDBusClient.actions.append('connect') |
1007 | + |
1008 | + def disconnect_file_sync(self): |
1009 | + """Disconnect file_sync service.""" |
1010 | + MockDBusClient.actions.append('disconnect') |
1011 | + |
1012 | + def start_file_sync(self): |
1013 | + """Start the file_sync service.""" |
1014 | + MockDBusClient.actions.append('start') |
1015 | + |
1016 | + def stop_file_sync(self): |
1017 | + """Stop the file_sync service.""" |
1018 | + MockDBusClient.actions.append('stop') |
1019 | + |
1020 | def get_folders(self): |
1021 | """Grab list of folders.""" |
1022 | return SAMPLE_FOLDERS |
1023 | @@ -487,6 +505,16 @@ |
1024 | yield self.assert_correct_status(FILE_SYNC_DISCONNECTED) |
1025 | |
1026 | @inlineCallbacks |
1027 | + def test_disconnected_when_waiting(self): |
1028 | + """The syncdaemon status is processed and emitted.""" |
1029 | + MockDBusClient.status = { |
1030 | + 'is_error': '', 'is_online': '', 'is_connected': '', |
1031 | + 'connection': 'With User With Network', 'queues': '', |
1032 | + 'name': 'WAITING', 'description': 'what a long wait!', |
1033 | + } |
1034 | + yield self.assert_correct_status(FILE_SYNC_DISCONNECTED) |
1035 | + |
1036 | + @inlineCallbacks |
1037 | def test_syncing_if_online(self): |
1038 | """The syncdaemon status is processed and emitted.""" |
1039 | MockDBusClient.status = { |
1040 | @@ -520,6 +548,17 @@ |
1041 | yield self.assert_correct_status(FILE_SYNC_IDLE) |
1042 | |
1043 | @inlineCallbacks |
1044 | + def test_stopped(self): |
1045 | + """The syncdaemon status is processed and emitted.""" |
1046 | + MockDBusClient.status = { |
1047 | + 'is_error': '', 'is_online': '', 'is_connected': '', |
1048 | + 'name': 'SHUTDOWN', 'connection': '', |
1049 | + 'queues': 'IDLE', |
1050 | + 'description': 'something nice', |
1051 | + } |
1052 | + yield self.assert_correct_status(FILE_SYNC_STOPPED) |
1053 | + |
1054 | + @inlineCallbacks |
1055 | def test_unknown(self): |
1056 | """The syncdaemon status is processed and emitted.""" |
1057 | MockDBusClient.status = { |
1058 | @@ -547,23 +586,64 @@ |
1059 | self.assertEqual(self._called, ((expected_status,), {})) |
1060 | |
1061 | |
1062 | -class BackendSyncEnabledTestCase(BackendBasicTestCase): |
1063 | - """Syncdaemon enable/disable for the backend.""" |
1064 | - |
1065 | +class BackendFileSyncOpsTestCase(BackendBasicTestCase): |
1066 | + """Syncdaemon operations for the backend.""" |
1067 | + |
1068 | + def setUp(self): |
1069 | + super(BackendFileSyncOpsTestCase, self).setUp() |
1070 | + MockDBusClient.actions = [] |
1071 | + |
1072 | + @inlineCallbacks |
1073 | def test_enable_files(self): |
1074 | """Files service is enabled.""" |
1075 | - self.be.disable_files() |
1076 | + yield self.be.disable_files() |
1077 | |
1078 | - self.be.enable_files() |
1079 | + yield self.be.enable_files() |
1080 | self.assertTrue(MockDBusClient.file_sync) |
1081 | |
1082 | + @inlineCallbacks |
1083 | def test_disable_files(self): |
1084 | """Files service is disabled.""" |
1085 | - self.be.enable_files() |
1086 | + yield self.be.enable_files() |
1087 | |
1088 | - self.be.disable_files() |
1089 | + yield self.be.disable_files() |
1090 | self.assertFalse(MockDBusClient.file_sync) |
1091 | |
1092 | + @inlineCallbacks |
1093 | + def test_connect_files(self): |
1094 | + """Connect files service.""" |
1095 | + yield self.be.connect_files() |
1096 | + |
1097 | + self.assertEqual(MockDBusClient.actions, ['connect']) |
1098 | + |
1099 | + @inlineCallbacks |
1100 | + def test_disconnect_files(self): |
1101 | + """Disconnect files service.""" |
1102 | + yield self.be.disconnect_files() |
1103 | + |
1104 | + self.assertEqual(MockDBusClient.actions, ['disconnect']) |
1105 | + |
1106 | + @inlineCallbacks |
1107 | + def test_restart_files(self): |
1108 | + """Restart the files service.""" |
1109 | + yield self.be.restart_files() |
1110 | + |
1111 | + self.assertEqual(MockDBusClient.actions, ['stop', 'start']) |
1112 | + |
1113 | + @inlineCallbacks |
1114 | + def test_start_files(self): |
1115 | + """Start the files service.""" |
1116 | + yield self.be.start_files() |
1117 | + |
1118 | + self.assertEqual(MockDBusClient.actions, ['start']) |
1119 | + |
1120 | + @inlineCallbacks |
1121 | + def test_stop_files(self): |
1122 | + """Stop the files service.""" |
1123 | + yield self.be.stop_files() |
1124 | + |
1125 | + self.assertEqual(MockDBusClient.actions, ['stop']) |
1126 | + |
1127 | |
1128 | class BackendReplicationsTestCase(BackendBasicTestCase): |
1129 | """Replications tests for the backend.""" |
<rye> nessita, i mean why an "Action" is tied to the "Link" presentation? It's like if we had a music player with Stop, Play, Pause underlined labels instead of buttons... ubuntuone. com/p/Z3a/
<nessita> rye: is a design thing, putting a raw button calls too much user attention and that button is not 'important', since the user should almost never require using them
<nessita> rye: also, a button there gets mixed (in the eye) with the buttons in the tab bar
<nessita> (Dashboard, Folders, etc)
<nessita> rye: all the sync actions are links
<rye> nessita, blank tooltips that causes - http://
<nessita> rye: that's the button uri :-/
<nessita> rye: maybe I can set the name of the button as uri... not sure how much that can break
<nessita> rye: let me investigate a bit