Merge lp:~chipaca/ubuntuone-client/devices-tab into lp:ubuntuone-client

Proposed by John Lenton
Status: Merged
Approved by: dobey
Approved revision: 409
Merged at revision: not available
Proposed branch: lp:~chipaca/ubuntuone-client/devices-tab
Merge into: lp:ubuntuone-client
Diff against target: 924 lines (+521/-216)
3 files modified
bin/ubuntuone-preferences (+378/-163)
tests/test_preferences.py (+141/-53)
ubuntuone/syncdaemon/dbus_interface.py (+2/-0)
To merge this branch: bzr merge lp:~chipaca/ubuntuone-client/devices-tab
Reviewer Review Type Date Requested Status
dobey (community) Approve
Eric Casteleijn (community) Approve
Natalia Bidart (community) Approve
Review via email: mp+20764@code.launchpad.net

This proposal supersedes a proposal from 2010-03-03.

Commit message

Update the devices tab UI to show the list of devices and allow removing them.

Description of the change

second try, now with pasing tests, heh

To post a comment you must log in.
Revision history for this message
Eric Casteleijn (thisfred) wrote : Posted in a previous version of this proposal

Getting keyring errors

Revision history for this message
Eric Casteleijn (thisfred) wrote : Posted in a previous version of this proposal
Download full text (8.5 KiB)

===============================================================================
[ERROR]: tests.test_preferences.PreferencesTests.test_bw_throttling

Traceback (most recent call last):
  File "/home/eric/canonical/ubuntuone-client/devices-tab/contrib/mocker.py", line 102, in test_method_wrapper
    result = test_method()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/tests/test_preferences.py", line 96, in test_bw_throttling
    dialog = self.u1prefs.UbuntuOneDialog()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 473, in __init__
    self.__construct()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 686, in __construct
    self.devices.get_devices()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 258, in get_devices
    token = get_access_token()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 84, in get_access_token
    'oauth-consumer-key': 'ubuntuone'})
gnomekeyring.IOError:
===============================================================================
[ERROR]: tests.test_preferences.PreferencesTests.test_quota_display

Traceback (most recent call last):
  File "/home/eric/canonical/ubuntuone-client/devices-tab/contrib/mocker.py", line 102, in test_method_wrapper
    result = test_method()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/tests/test_preferences.py", line 107, in test_quota_display
    dialog = self.u1prefs.UbuntuOneDialog()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 473, in __init__
    self.__construct()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 686, in __construct
    self.devices.get_devices()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 258, in get_devices
    token = get_access_token()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 84, in get_access_token
    'oauth-consumer-key': 'ubuntuone'})
gnomekeyring.IOError:
===============================================================================
[ERROR]: tests.test_preferences.PreferencesTests.test_request_account_info

Traceback (most recent call last):
  File "/home/eric/canonical/ubuntuone-client/devices-tab/contrib/mocker.py", line 102, in test_method_wrapper
    result = test_method()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/tests/test_preferences.py", line 135, in test_request_account_info
    dialog = self.u1prefs.UbuntuOneDialog()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 473, in __init__
    self.__construct()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 686, in __construct
    self.devices.get_devices()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 258, in get_devices
    token = get_access_token()
  File "/home/eric/canonical/ubuntuone-client/devices-tab/bin/ubuntuone-preferences", line 84, in get_access_token
    'oauth-consumer...

Read more...

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

Test pass though I'm getting this in the console:

nessita@dali:~/canonical/ubuntuone-client/review_devices-tab$ ./bin/ubuntuone-preferences
<twisted.python.failure.Failure <class 'dbus.exceptions.DBusException'>>
DBusException(dbus.String(u'Message did not receive a reply (timeout by message bus)'),)
DBusException(dbus.String(u'Message did not receive a reply (timeout by message bus)'),)

And the same error appears on the 'Devices' tab.
Please also note that the toplevel window changes size in some not-nice way to be able to display the long label with the legend "Error: org.freedesktop.DBus.Error.NoReply: Message ..."

Note that my SD won't start due to metadata corruption. I'll re-test once my SD is working.

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

> Please also note that the toplevel window changes size in some not-nice way to
> be able to display the long label with the legend "Error:
> org.freedesktop.DBus.Error.NoReply: Message ..."

As per Chipaca request:

(03:35:47 PM) Chipaca: nessita: what should I show instead?
(03:37:01 PM) nessita: Chipaca: "Sweet end user, we think you may have a problem with the underlying synching service. Please contact <bla> at <bla> or look for some online help <here>. We love you, we want to help you, please don't switch to dropbox"

406. By John Lenton

worked around a bug in the rest api

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

Approving. I opened Bug #532841 for the "ugly" error thingy.

Small fixes for docstrings:

 * First line should be next to the double-triple quotes.
 * First line should be a one-liner follow up by a blank line.
 * Line 183 says "dialo."
 * Every line should be ended with a dot.

review: Approve
Revision history for this message
dobey (dobey) wrote :

86 + self.status_label = gtk.Label("Please wait...")
87 + self.attach(self.status_label, 0, 3, 2, 3)
88 +
89 + self.description = gtk.Label("The devices connected to with your personal cloud network are listed below")
90 + self.description.set_alignment(0., .5)
91 + self.description.set_line_wrap(True)
92 + self.attach(self.description, 0, 3, 0, 1, xpadding=12, ypadding=12)

These need to be translated if they're going to be in here. However, I'd prefer to just remove them. "Please wait" should very rarely, if ever, be seen, and "The devices..." is redundant and made obvious by the contents of the tab.

245 + response = response.read() # neither shouold this

Typo.

303 + butn = gtk.Button('Remove')

Needs to be marked for translation.

330 + self.conn_btn = gtk.Button(_('_Connect'))

This creates a mnemonic key which conflicts with the _Close button of the dialog. I think we should perhaps avoid having mnemonics on the Connect/Disconnect and Restart buttons. But we should probably set them to _U and _D for the Upload/Download labels for the spin buttons (and hook the mnemonics to the widgets), as was previously done...

581 - label = gtk.Label(_("Maximum _upload speed (KB/s):"))
596 - label = gtk.Label(_("Maximum _download speed (KB/s):"))
311 + up_lbl = gtk.Label(_("Upload (kB/s):"))
318 + dn_lbl = gtk.Label(_("Download (kB/s):"))

Any reason to change these labels from what they were previously? And to change from KB to kB? This breaks the existing translations.

Also, since you added logging in this branch, is there any reason you don't log the errors when they occur, but only stick them in a status label?

review: Needs Fixing
Revision history for this message
Eric Casteleijn (thisfred) wrote :

All tests pass now.

review: Approve
407. By John Lenton

fixed issues raised by dobey

Revision history for this message
John Lenton (chipaca) wrote :

> Approving. I opened Bug #532841 for the "ugly" error thingy.
>
> Small fixes for docstrings:
>
> * First line should be next to the double-triple quotes.

I disagree; it looks ugly in the code, except for docstrings that are just one line, like

   """A docstring in a single line"""

although even there I think consistency with multi-line docstrings, plus the added readability due to the extra whitespace, makes the other form better.

WRT consistency with the PEP, PEP 257 says «The summary line may be on the same line as the opening quotes or on the next line.»

> * First line should be a one-liner follow up by a blank line.

yep, edited those down a little.

> * Line 183 says "dialo."

good catch!

> * Every line should be ended with a dot.

ok.

Revision history for this message
John Lenton (chipaca) wrote :

> 86 + self.status_label = gtk.Label("Please wait...")
> 87 + self.attach(self.status_label, 0, 3, 2, 3)
> 88 +
> 89 + self.description = gtk.Label("The devices connected to with your
> personal cloud network are listed below")
> 90 + self.description.set_alignment(0., .5)
> 91 + self.description.set_line_wrap(True)
> 92 + self.attach(self.description, 0, 3, 0, 1, xpadding=12, ypadding=12)
>
> These need to be translated if they're going to be in here. However, I'd
> prefer to just remove them. "Please wait" should very rarely, if ever, be
> seen, and "The devices..." is redundant and made obvious by the contents of
> the tab.
>
> 245 + response = response.read() # neither shouold this
>
> Typo.
>
> 303 + butn = gtk.Button('Remove')
>
> Needs to be marked for translation.
>
> 330 + self.conn_btn = gtk.Button(_('_Connect'))
>
> This creates a mnemonic key which conflicts with the _Close button of the
> dialog. I think we should perhaps avoid having mnemonics on the
> Connect/Disconnect and Restart buttons. But we should probably set them to _U
> and _D for the Upload/Download labels for the spin buttons (and hook the
> mnemonics to the widgets), as was previously done...
>
> 581 - label = gtk.Label(_("Maximum _upload speed (KB/s):"))
> 596 - label = gtk.Label(_("Maximum _download speed (KB/s):"))
> 311 + up_lbl = gtk.Label(_("Upload (kB/s):"))
> 318 + dn_lbl = gtk.Label(_("Download (kB/s):"))
>
> Any reason to change these labels from what they were previously? And to
> change from KB to kB? This breaks the existing translations.
>
> Also, since you added logging in this branch, is there any reason you don't
> log the errors when they occur, but only stick them in a status label?

I believe I've fixed all these (I left the "the devices connected ..." in because I think it's not as clear as you think it is :). Could you re-review? Tks.

408. By John Lenton

fixed issues raised by nessa

Revision history for this message
dobey (dobey) wrote :

Can we get rid of the '<b>Name</b>' label and row? I think it's a waste; it's oddly positioned, and looks weird.

The _Connect and _Disconnect labels still conflict with other mnemonics in the dialog. Please get rid of the _ in the strings, or change them to be _o in both strings (so that it doesn't change mnemonics).

You didn't add any more logger.error() calls. Please use logger.error() to log the errors you trap from DBus or elsewhere.

And I still thoroughly disagree with the "The devices blah blah" label. :)

review: Needs Fixing
Revision history for this message
John Lenton (chipaca) wrote :

> Can we get rid of the '<b>Name</b>' label and row? I think it's a waste; it's
> oddly positioned, and looks weird.

darn it, you're right. Bye bye, <b>Name</b>.

> The _Connect and _Disconnect labels still conflict with other mnemonics in the
> dialog. Please get rid of the _ in the strings, or change them to be _o in
> both strings (so that it doesn't change mnemonics).

oops, I forgot this one. Done.

> You didn't add any more logger.error() calls. Please use logger.error() to log
> the errors you trap from DBus or elsewhere.

d'oh, I used logging.error instead (let's call it a typo).

> And I still thoroughly disagree with the "The devices blah blah" label. :)

Noted.

409. By John Lenton

more changed by dobey (and some older ones)

Revision history for this message
dobey (dobey) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'bin/ubuntuone-preferences'
--- bin/ubuntuone-preferences 2010-03-01 22:10:22 +0000
+++ bin/ubuntuone-preferences 2010-03-08 19:59:28 +0000
@@ -23,6 +23,7 @@
23import pygtk23import pygtk
24pygtk.require('2.0')24pygtk.require('2.0')
25import gobject25import gobject
26import glib
26import gtk27import gtk
27import os28import os
28import gettext29import gettext
@@ -32,6 +33,11 @@
32from oauth import oauth33from oauth import oauth
33from ubuntuone import clientdefs34from ubuntuone import clientdefs
34from ubuntuone.syncdaemon.tools import SyncDaemonTool35from ubuntuone.syncdaemon.tools import SyncDaemonTool
36from ubuntuone.syncdaemon.logger import LOGFOLDER
37
38import logging
39import sys
40import httplib, urlparse, socket
3541
36import dbus.service42import dbus.service
37from ConfigParser import ConfigParser43from ConfigParser import ConfigParser
@@ -39,6 +45,11 @@
39from dbus.mainloop.glib import DBusGMainLoop45from dbus.mainloop.glib import DBusGMainLoop
40from xdg.BaseDirectory import xdg_config_home46from xdg.BaseDirectory import xdg_config_home
4147
48logging.basicConfig(
49 filename=os.path.join(LOGFOLDER, 'u1-prefs.log'),
50 level=logging.DEBUG,
51 format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
52logger = logging.getLogger("ubuntuone-preferences")
42DBusGMainLoop(set_as_default=True)53DBusGMainLoop(set_as_default=True)
4354
44_ = gettext.gettext55_ = gettext.gettext
@@ -65,10 +76,363 @@
65 pass76 pass
6677
6778
79def get_access_token(keyring):
80 items = []
81 items = keyring.find_items_sync(
82 keyring.ITEM_GENERIC_SECRET,
83 {'ubuntuone-realm': "https://ubuntuone.com",
84 'oauth-consumer-key': 'ubuntuone'})
85 secret = items[0].secret
86 return oauth.OAuthToken.from_string(secret)
87
88
89class DevicesWidget(gtk.Table):
90 """
91 the Devices tab.
92 """
93 def __init__(self,
94 bus,
95 keyring=gnomekeyring,
96 realm='https://ubuntuone.com',
97 consumer_key='ubuntuone',
98 url='https://one.ubuntu.com/api/1.0/devices/'):
99 super(DevicesWidget, self).__init__(rows=2, columns=3)
100 self.bus = bus
101 self.keyring = keyring
102 self.sdtool = SyncDaemonTool(bus)
103 self.set_border_width(6)
104 self.set_row_spacings(6)
105 self.set_col_spacings(6)
106 self.devices = None
107 self.realm = realm
108 self.consumer_key = consumer_key
109 self.base_url = url
110 self.conn = None
111 self.consumer = None
112 self.table_widgets = []
113
114 self.connected = None # i.e. unknown
115 self.conn_btn = None
116 self.up_spin = None
117 self.dn_spin = None
118 self.bw_chk = None
119 self.bw_limited = False
120 self.up_limit = 2097152
121 self.dn_limit = 2097152
122
123 self._update_id = 0
124
125 self.status_label = gtk.Label("")
126 self.attach(self.status_label, 0, 3, 2, 3)
127
128 self.description = gtk.Label(_("The devices connected to with your"
129 " personal cloud network"
130 " are listed below"))
131 self.description.set_alignment(0., .5)
132 self.description.set_line_wrap(True)
133 self.attach(self.description, 0, 3, 0, 1, xpadding=12, ypadding=12)
134
135 def update_bw_settings(self):
136 """
137 Push the bandwidth settings at syncdaemon.
138 """
139 try:
140 client = self.bus.get_object(DBUS_IFACE_NAME, "/config",
141 follow_name_owner_changes=True)
142 iface = dbus.Interface(client, DBUS_IFACE_CONFIG_NAME)
143 iface.set_throttling_limits(self.dn_limit, self.up_limit,
144 reply_handler=dbus_async,
145 error_handler=self.error)
146 if self.bw_limited:
147 iface.enable_bandwidth_throttling(reply_handler=dbus_async,
148 error_handler=self.error)
149 else:
150 iface.disable_bandwidth_throttling(reply_handler=dbus_async,
151 error_handler=self.error)
152 except DBusException, e:
153 self.error(str(e))
154
155 def handle_bw_controls_changed(self, *a):
156 """
157 Sync the bandwidth throttling model with the view.
158
159 Start a timer to sync with syncdaemon too.
160 """
161 # Remove the timeout ...
162 if self._update_id != 0:
163 gobject.source_remove(self._update_id)
164
165 # sync the model ...
166 self.bw_limited = self.bw_chk.get_active()
167 self.up_limit = self.up_spin.get_value_as_int() * 1024
168 self.dn_limit = self.dn_spin.get_value_as_int() * 1024
169
170 # ... and add the timeout back
171 self._update_id = gobject.timeout_add_seconds(
172 1, self.update_bw_settings)
173
174 def handle_bw_checkbox_toggled(self, checkbox, *widgets):
175 """
176 Callback for the bandwidth togglebutton.
177 """
178 active = checkbox.get_active()
179 for widget in widgets:
180 widget.set_sensitive(active)
181 self.handle_bw_controls_changed()
182
183 def handle_limits(self, limits):
184 """
185 Callback for when syncdaemon tells us its throttling limits.
186 """
187 self.up_limit = int(limits['upload'])
188 self.dn_limit = int(limits['download'])
189 if self.up_spin is not None and self.dn_spin is not None:
190 self.up_spin.set_value(self.up_limit / 1024)
191 self.dn_spin.set_value(self.dn_limit / 1024)
192
193 def handle_throttling_enabled(self, enabled):
194 """
195 Callback for when syncdaemon tells us whether throttling is enabled.
196 """
197 self.bw_limited = enabled
198 if self.bw_chk is not None:
199 self.bw_chk.set_active(enabled)
200
201 def handle_state_change(self, new_state):
202 """
203 Callback for when syncdaemon's state changes.
204 """
205 if new_state['is_error']:
206 # this syncdaemon isn't going to connect no more
207 self.connected = None
208 else:
209 self.connected = new_state['is_connected']
210 if self.conn_btn is not None:
211 if self.connected:
212 self.conn_btn.set_label(_("Disconnect"))
213 else:
214 self.conn_btn.set_label(_("Connect"))
215 if self.connected is None:
216 self.conn_btn.set_sensitive(False)
217 else:
218 self.conn_btn.set_sensitive(True)
219
220 def error(self, msg):
221 """
222 Clear the table and show the error message in its place.
223
224 This might be better as an error dialog.
225 """
226 self.clear_devices_view()
227 self.status_label.set_markup("<b>Error:</b> %s" % msg)
228 logger.error(msg)
229
230 def request(self, path='', method='GET'):
231 """
232 Helper that makes an oauth-wrapped rest request.
233
234 XXX duplication with request_REST_info (but this one should be async).
235 """
236 url = self.base_url + path
237
238 token = get_access_token(self.keyring)
239
240 oauth_request = oauth.OAuthRequest.from_consumer_and_token(
241 http_url=url,
242 http_method=method,
243 oauth_consumer=self.consumer,
244 token=token,
245 parameters='')
246 oauth_request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(),
247 self.consumer, token)
248
249 scheme, netloc, path, query, fragment = urlparse.urlsplit(url)
250
251 conn = httplib.HTTPSConnection(netloc)
252 try:
253 conn.request(method, path, headers=oauth_request.to_header())
254 except socket.error:
255 return None
256 return conn
257
258 def get_devices(self):
259 """
260 Ask the server for a list of devices
261
262 Hook up parse_devices to run on the result (when it gets here).
263 """
264 try:
265 token = get_access_token(self.keyring)
266 except gnomekeyring.NoMatchError:
267 self.error("No token in the keyring")
268 self.devices = []
269 else:
270 self.consumer = oauth.OAuthConsumer("ubuntuone", "hammertime")
271
272 self.conn = self.request()
273 if self.conn is None:
274 self.clear_devices_view()
275 self.error('Unable to connect')
276 else:
277 glib.io_add_watch(
278 self.conn.sock,
279 glib.IO_IN | glib.IO_PRI | glib.IO_ERR | glib.IO_HUP,
280 self.parse_devices)
281
282 def parse_devices(self, *a):
283 """
284 Parse the list of devices, and hook up list_devices if it worked.
285 """
286 response = self.conn.getresponse() # shouldn't block
287 if response.status == 200:
288 response = response.read() # neither should this
289 self.devices = simplejson.loads(response)
290 gobject.idle_add(self.list_devices)
291 else:
292 self.clear_devices_view()
293 self.error(response.reason)
294 return False
295
296 def clear_devices_view(self):
297 """
298 Clear out almost all the widgets.
299
300 All except from the table, the description and the
301 status_label get destroyed.
302 """
303 for i in self.get_children():
304 if i not in (self.description, self.status_label):
305 i.destroy()
306 self.conn_btn = None
307 self.up_spin = None
308 self.dn_spin = None
309 self.bw_chk = None
310
311 def list_devices(self):
312 """
313 Populate the table with the list of devices.
314
315 If the list of devices is empty, make a fake one that refers
316 to the local machine (to get the connect/restart buttons).
317 """
318 self.resize(len(self.devices)+1, 3)
319
320 self.clear_devices_view()
321
322 token = get_access_token(self.keyring)
323
324 if not self.devices:
325 # a stopgap device so you can at least try to connect
326 self.devices = [{'kind': 'Computer',
327 'description': _("<LOCAL MACHINE>"),
328 'token': token.key,
329 'FAKE': 'YES'}]
330
331 self.status_label.set_label("")
332
333 i = 0
334 for row in self.devices:
335 i += 1
336 img = gtk.Image()
337 img.set_from_icon_name(row['kind'].lower(), gtk.ICON_SIZE_DND)
338 desc = gtk.Label(row['description'])
339 desc.set_alignment(0., .5)
340 self.attach(img, 0, 1, i, i+1)
341 self.attach(desc, 1, 2, i, i+1)
342 if 'FAKE' not in row:
343 # we don't include the "Remove" button for the fake entry :)
344 butn = gtk.Button(_('Remove'))
345 butn.connect('clicked', self.remove,
346 row['kind'], row.get('token'))
347 self.attach(butn, 2, 3, i, i+1, xoptions=0, yoptions=0)
348 if row.get('token') == token.key:
349 self.bw_chk = ck_btn = gtk.CheckButton(
350 _("_Limit Bandwidth Usage"))
351 ck_btn.set_active(self.bw_limited)
352 up_lbl = gtk.Label(_("Maximum _upload speed (KB/s):"))
353 up_lbl.set_alignment(0., .5)
354 adj = gtk.Adjustment(value=self.up_limit/1024.,
355 lower=0.0, upper=4096.0,
356 step_incr=1.0, page_incr=16.0)
357 self.up_spin = up_btn = gtk.SpinButton(adj)
358 up_btn.connect("value-changed", self.handle_bw_controls_changed)
359 up_lbl.set_mnemonic_widget(up_btn)
360 dn_lbl = gtk.Label(_("Maximum _download speed (KB/s):"))
361 dn_lbl.set_alignment(0., .5)
362 adj = gtk.Adjustment(value=self.dn_limit/1024.,
363 lower=0.0, upper=4096.0,
364 step_incr=1.0, page_incr=16.0)
365 self.dn_spin = dn_btn = gtk.SpinButton(adj)
366 dn_btn.connect("value-changed", self.handle_bw_controls_changed)
367 dn_lbl.set_mnemonic_widget(dn_btn)
368 ck_btn.connect('toggled', self.handle_bw_checkbox_toggled,
369 up_lbl, up_btn, dn_lbl, dn_btn)
370 self.handle_bw_checkbox_toggled(ck_btn,
371 up_lbl, up_btn, dn_lbl, dn_btn)
372
373 self.conn_btn = gtk.Button(_('Connect'))
374 if self.connected is None:
375 self.conn_btn.set_sensitive(False)
376 elif self.connected:
377 self.conn_btn.set_label(_('Disconnect'))
378 self.conn_btn.connect('clicked', self.handle_connect_button)
379 restart_btn = gtk.Button(_('Restart'))
380 restart_btn.connect('clicked', self.handle_restart_button)
381 btn_box = gtk.HButtonBox()
382 btn_box.add(self.conn_btn)
383 btn_box.add(restart_btn)
384
385 i += 1
386 self.attach(ck_btn, 1, 3, i, i+1)
387 i += 1
388 self.attach(up_lbl, 1, 2, i, i+1)
389 self.attach(up_btn, 2, 3, i, i+1)
390 i += 1
391 self.attach(dn_lbl, 1, 2, i, i+1)
392 self.attach(dn_btn, 2, 3, i, i+1)
393 i += 1
394 self.attach(btn_box, 1, 3, i, i+1)
395 i += 2
396 self.show_all()
397
398 def handle_connect_button(self, *a):
399 """
400 Callback for the Connect/Disconnect button.
401 """
402 self.conn_btn.set_sensitive(False)
403 if self.connected:
404 d = self.sdtool.disconnect()
405 else:
406 d = self.sdtool.connect()
407
408 def handle_restart_button(self, *a):
409 """
410 Callback for the Restart button.
411 """
412 self.sdtool.quit().addCallbacks(lambda _: self.sdtool.start())
413
414 def remove(self, button, kind, token):
415 """
416 Callback for the Remove button.
417
418 Starts an async request to remove a device.
419 """
420 self.conn = self.request('remove/%s/%s' % (kind.lower(), token))
421 if self.conn is None:
422 self.clear_devices_view()
423 self.error('Unable to connect')
424 else:
425 glib.io_add_watch(
426 self.conn.sock,
427 glib.IO_IN | glib.IO_PRI | glib.IO_ERR | glib.IO_HUP,
428 self.parse_devices)
429
430
431
68class UbuntuOneDialog(gtk.Dialog):432class UbuntuOneDialog(gtk.Dialog):
69 """Preferences dialog."""433 """Preferences dialog."""
70434
71 def __init__(self, config=None, *args, **kw):435 def __init__(self, config=None, keyring=gnomekeyring, *args, **kw):
72 """Initializes our config dialog."""436 """Initializes our config dialog."""
73 super(UbuntuOneDialog, self).__init__(*args, **kw)437 super(UbuntuOneDialog, self).__init__(*args, **kw)
74 self.set_title(_("Ubuntu One Preferences"))438 self.set_title(_("Ubuntu One Preferences"))
@@ -80,12 +444,8 @@
80 self.connect("close", self.__handle_response, gtk.RESPONSE_CLOSE)444 self.connect("close", self.__handle_response, gtk.RESPONSE_CLOSE)
81 self.connect("response", self.__handle_response)445 self.connect("response", self.__handle_response)
82446
83 self.bw_enabled = False
84 self.up_limit = 2097152
85 self.dn_limit = 2097152
86
87 self.__bus = dbus.SessionBus()447 self.__bus = dbus.SessionBus()
88 self.keyring = gnomekeyring448 self.keyring = keyring
89449
90 self.__bus.add_signal_receiver(450 self.__bus.add_signal_receiver(
91 handler_function=self.__got_state,451 handler_function=self.__got_state,
@@ -108,15 +468,13 @@
108 # Timeout ID to avoid spamming DBus from spinbutton changes468 # Timeout ID to avoid spamming DBus from spinbutton changes
109 self.__update_id = 0469 self.__update_id = 0
110470
111 # Connectivity status
112 self.connected = False
113
114 # SD Tool object471 # SD Tool object
115 self.sdtool = SyncDaemonTool(self.__bus)472 self.sdtool = SyncDaemonTool(self.__bus)
116 self.sdtool.get_status().addCallbacks(lambda _: self.__got_state,473 self.sdtool.get_status().addCallbacks(lambda _: self.__got_state,
117 self.__sd_error)474 self.__sd_error)
118 # Build the dialog475 # Build the dialog
119 self.__construct()476 self.__construct()
477 logger.debug("starting")
120478
121 def quit(self):479 def quit(self):
122 """Exit the main loop."""480 """Exit the main loop."""
@@ -132,97 +490,23 @@
132490
133 def __got_state(self, state):491 def __got_state(self, state):
134 """Got the state of syncdaemon."""492 """Got the state of syncdaemon."""
135 self.connected = bool(state['is_connected'])493 self.devices.handle_state_change(state)
136 if self.connected:
137 self.conn_btn.set_label(_("Disconnect"))
138 else:
139 self.conn_btn.set_label(_("Connect"))
140 self.conn_btn.set_sensitive(True)
141494
142 def __got_limits(self, limits):495 def __got_limits(self, limits):
143 """Got the throttling limits."""496 """Got the throttling limits."""
144 self.up_limit = int(limits['upload'])497 logger.debug("got limits: %s" % (limits,))
145 self.dn_limit = int(limits['download'])498 self.devices.handle_limits(limits)
146 self.up_spin.set_value(self.up_limit / 1024)
147 self.dn_spin.set_value(self.dn_limit / 1024)
148499
149 def __got_enabled(self, enabled):500 def __got_enabled(self, enabled):
150 """Got the throttling enabled config."""501 """Got the throttling enabled config."""
151 self.bw_enabled = bool(enabled)502 self.devices.handle_throttling_enabled(enabled)
152 self.limit_check.set_active(self.bw_enabled)
153
154 def __update_bw_settings(self):
155 """Update the bandwidth throttling config in syncdaemon."""
156 self.bw_enabled = self.limit_check.get_active()
157 self.up_limit = self.up_spin.get_value_as_int() * 1024
158 self.dn_limit = self.dn_spin.get_value_as_int() * 1024
159
160 try:
161 client = self.__bus.get_object(DBUS_IFACE_NAME, "/config",
162 follow_name_owner_changes=True)
163 iface = dbus.Interface(client, DBUS_IFACE_CONFIG_NAME)
164 iface.set_throttling_limits(self.dn_limit, self.up_limit,
165 reply_handler=dbus_async,
166 error_handler=self.__dbus_error)
167 if self.bw_enabled:
168 iface.enable_bandwidth_throttling(
169 reply_handler=dbus_async,
170 error_handler=self.__dbus_error)
171 else:
172 iface.disable_bandwidth_throttling(
173 reply_handler=dbus_async,
174 error_handler=self.__dbus_error)
175 except DBusException, e:
176 self.__dbus_error(e)
177503
178 def __handle_response(self, dialog, response):504 def __handle_response(self, dialog, response):
179 """Handle the dialog's response."""505 """Handle the dialog's response."""
180 self.hide()506 self.hide()
181 self.__update_bw_settings()507 self.devices.update_bw_settings()
182 gtk.main_quit()508 gtk.main_quit()
183509
184 def __bw_limit_toggled(self, button, data=None):
185 """Toggle the bw limit panel."""
186 self.bw_enabled = self.limit_check.get_active()
187 self.bw_table.set_sensitive(self.bw_enabled)
188 try:
189 client = self.__bus.get_object(DBUS_IFACE_NAME, "/config",
190 follow_name_owner_changes=True)
191 iface = dbus.Interface(client, DBUS_IFACE_CONFIG_NAME)
192 iface.set_throttling_limits(self.dn_limit, self.up_limit,
193 reply_handler=dbus_async,
194 error_handler=self.__dbus_error)
195 if self.bw_enabled:
196 iface.enable_bandwidth_throttling(
197 reply_handler=dbus_async,
198 error_handler=self.__dbus_error)
199 else:
200 iface.disable_bandwidth_throttling(
201 reply_handler=dbus_async,
202 error_handler=self.__dbus_error)
203 except DBusException, e:
204 self.__dbus_error(e)
205
206 def __spinner_changed(self, button, data=None):
207 """Remove timeout and add anew."""
208 if self.__update_id != 0:
209 gobject.source_remove(self.__update_id)
210
211 self.__update_id = gobject.timeout_add_seconds(
212 1, self.__update_bw_settings)
213
214 def __connect_toggled(self, button, data=None):
215 """Toggle the connection state..."""
216 self.conn_btn.set_sensitive(False)
217 if self.connected:
218 self.sdtool.start().addCallbacks(
219 lambda _: self.sdtool.disconnect(),
220 self.__sd_error)
221 else:
222 self.sdtool.start().addCallbacks(
223 lambda _: self.sdtool.connect(),
224 self.__sd_error)
225
226 def _format_for_gb_display(self, bytes):510 def _format_for_gb_display(self, bytes):
227 """Format bytes into reasonable gb display."""511 """Format bytes into reasonable gb display."""
228 gb = bytes / 1024 / 1024 / 1024512 gb = bytes / 1024 / 1024 / 1024
@@ -247,12 +531,7 @@
247 def request_REST_info(self, url, method):531 def request_REST_info(self, url, method):
248 """Make a REST request and return the resulting dict, or None."""532 """Make a REST request and return the resulting dict, or None."""
249 consumer = oauth.OAuthConsumer("ubuntuone", "hammertime")533 consumer = oauth.OAuthConsumer("ubuntuone", "hammertime")
250 items = []534 token = get_access_token(self.keyring)
251 items = self.keyring.find_items_sync(
252 gnomekeyring.ITEM_GENERIC_SECRET,
253 {'ubuntuone-realm': "https://ubuntuone.com",
254 'oauth-consumer-key': consumer.key})
255 token = oauth.OAuthToken.from_string(items[0].secret)
256 request = oauth.OAuthRequest.from_consumer_and_token(535 request = oauth.OAuthRequest.from_consumer_and_token(
257 http_url=url, http_method=method, oauth_consumer=consumer,536 http_url=url, http_method=method, oauth_consumer=consumer,
258 token=token)537 token=token)
@@ -403,75 +682,11 @@
403 self.mail_label.show()682 self.mail_label.show()
404683
405 # Devices tab684 # Devices tab
406 devices = gtk.VBox(spacing=12)685 self.devices = DevicesWidget(self.__bus, self.keyring)
407 devices.set_border_width(6)686 self.notebook.append_page(self.devices)
408 self.notebook.append_page(devices)687 self.notebook.set_tab_label_text(self.devices, _("Devices"))
409 self.notebook.set_tab_label_text(devices, _("Devices"))688 self.devices.show_all()
410 devices.show()689 self.devices.get_devices()
411
412 # Bandwidth limiting
413 self.limit_check = gtk.CheckButton(_("_Limit Bandwidth Usage"))
414 self.limit_check.connect("toggled", self.__bw_limit_toggled)
415 devices.pack_start(self.limit_check, False, False)
416 self.limit_check.show()
417
418 hbox = gtk.HBox(spacing=12)
419 devices.pack_start(hbox, False, False)
420 hbox.show()
421
422 label = gtk.Label()
423 hbox.pack_start(label, False, False)
424 label.show()
425
426 rbox = gtk.VBox(spacing=12)
427 hbox.pack_start(rbox, False, False)
428 rbox.show()
429
430 # Now put the bw limit bits in a table too
431 self.bw_table = gtk.Table(rows=2, columns=2)
432 self.bw_table.set_row_spacings(6)
433 self.bw_table.set_col_spacings(6)
434 self.bw_table.set_sensitive(False)
435 rbox.pack_start(self.bw_table, False, False)
436 self.bw_table.show()
437
438 # Upload speed
439 label = gtk.Label(_("Maximum _upload speed (KB/s):"))
440 label.set_use_underline(True)
441 label.set_alignment(0, 0.5)
442 self.bw_table.attach(label, 0, 1, 0, 1)
443 label.show()
444
445 adjustment = gtk.Adjustment(value=2048.0, lower=0.0, upper=4096.0,
446 step_incr=64.0, page_incr=128.0)
447 self.up_spin = gtk.SpinButton(adjustment)
448 self.up_spin.connect("value-changed", self.__spinner_changed)
449 label.set_mnemonic_widget(self.up_spin)
450 self.bw_table.attach(self.up_spin, 1, 2, 0, 1)
451 self.up_spin.show()
452
453 # Download speed
454 label = gtk.Label(_("Maximum _download speed (KB/s):"))
455 label.set_use_underline(True)
456 label.set_alignment(0, 0.5)
457 self.bw_table.attach(label, 0, 1, 1, 2)
458 label.show()
459 adjustment = gtk.Adjustment(value=2048.0, lower=64.0, upper=8192.0,
460 step_incr=64.0, page_incr=128.0)
461 self.dn_spin = gtk.SpinButton(adjustment)
462 self.dn_spin.connect("value-changed", self.__spinner_changed)
463 label.set_mnemonic_widget(self.dn_spin)
464 self.bw_table.attach(self.dn_spin, 1, 2, 1, 2)
465 self.dn_spin.show()
466
467 alignment = gtk.Alignment(1.0, 0.5)
468 rbox.pack_end(alignment, False, False)
469 alignment.show()
470
471 self.conn_btn = gtk.Button(_("Connect"))
472 self.conn_btn.connect('clicked', self.__connect_toggled)
473 alignment.add(self.conn_btn)
474 self.conn_btn.show()
475690
476 # Services tab691 # Services tab
477 services = gtk.VBox(spacing=12)692 services = gtk.VBox(spacing=12)
478693
=== modified file 'tests/test_preferences.py'
--- tests/test_preferences.py 2010-02-18 16:02:23 +0000
+++ tests/test_preferences.py 2010-03-08 19:59:28 +0000
@@ -53,26 +53,24 @@
5353
54 self.item_id = 99954 self.item_id = 999
5555
56 ex = self.expect(self.item.item_id)56 self.item.item_id
57 ex.result(self.item_id)57 self.mocker.result(self.item_id)
58 ex.count(0, None)58 self.mocker.count(0, None)
5959
60 ex = self.expect(self.item.secret)60 self.item.secret
61 ex.result('oauth_token=access_key&oauth_token_secret=access_secret')61 self.mocker.result('oauth_token=access_key'
62 ex.count(0, None)62 '&oauth_token_secret=access_secret')
6363 self.mocker.count(0, None)
64 def expect_token_query(self):64
65 """Expects the keyring to be queried for a token."""65 self.keyring.find_items_sync(
66 return self.expect(66 None,
67 self.keyring.find_items_sync(67 {'ubuntuone-realm': 'https://ubuntuone.com',
68 gnomekeyring.ITEM_GENERIC_SECRET,68 'oauth-consumer-key': 'ubuntuone'})
69 {'ubuntuone-realm': 'https://ubuntuone.com',69 self.mocker.count(0, None)
70 'oauth-consumer-key': 'ubuntuone'})70 self.mocker.result([self.item])
71 )71 self.keyring.ITEM_GENERIC_SECRET
7272 self.mocker.count(0, None)
73 def mock_has_token(self):73 self.mocker.result(None)
74 """Mocks a cached token in the keyring."""
75 self.expect_token_query().result([self.item])
7674
77 def tearDown(self):75 def tearDown(self):
78 # collect all signal receivers registered during the test76 # collect all signal receivers registered during the test
@@ -93,18 +91,110 @@
93 def test_bw_throttling(self):91 def test_bw_throttling(self):
94 """Test that toggling bw throttling works correctly."""92 """Test that toggling bw throttling works correctly."""
95 self.mocker.replay()93 self.mocker.replay()
96 dialog = self.u1prefs.UbuntuOneDialog()94 widget = self.u1prefs.DevicesWidget(None, keyring=self.keyring)
97 self.assertTrue(dialog is not None)95 try:
98 dialog.notebook.set_current_page(1)96 widget.devices = []
99 self.assertFalse(dialog.bw_table.get_property('sensitive'))97 widget.list_devices()
100 dialog.limit_check.set_active(True)98 self.assertFalse(widget.bw_limited,
101 self.assertTrue(dialog.bw_table.get_property('sensitive'))99 "the bandwidth should start out not limited")
102 dialog.destroy()100 self.assertTrue(widget.bw_chk,
101 "the checkbox should be present")
102 self.assertFalse(widget.bw_chk.get_active(),
103 "the checkbox should start out unchecked")
104 self.assertFalse(widget.up_spin.get_property('sensitive') or
105 widget.dn_spin.get_property('sensitive'),
106 "the spinbuttons should start out unsensitive")
107 widget.bw_chk.set_active(True)
108 self.assertTrue(widget.bw_chk.get_active(),
109 "the checkbox should now be checked")
110 self.assertTrue(widget.up_spin.get_property('sensitive') and
111 widget.dn_spin.get_property('sensitive'),
112 "the spinbuttons should now be sensitive")
113 finally:
114 widget.destroy()
115
116 def test_list_devices_fills_devices_list_with_fake_result_when_empty(self):
117 self.mocker.replay()
118 widget = self.u1prefs.DevicesWidget(None, keyring=self.keyring)
119 try:
120 widget.devices = []
121 widget.list_devices()
122 # the devices list is no longer empty
123 self.assertTrue(widget.devices)
124 # it has 'fake' data (referring to the local machine)
125 self.assertTrue('FAKE' in widget.devices[0])
126 finally:
127 widget.destroy()
128
129 def test_list_devices_shows_devices_list(self):
130 self.mocker.replay()
131 widget = self.u1prefs.DevicesWidget(None, keyring=self.keyring)
132 try:
133 widget.devices = []
134 widget.list_devices()
135 # fake data now in devices
136 interesting = []
137 for i in widget.get_children():
138 clsname = i.__class__.__name__
139 if clsname == 'Image':
140 interesting.append((clsname, i.get_icon_name()[0]))
141 if clsname in ('Label', 'Button', 'CheckButton'):
142 interesting.append((clsname, i.get_label()))
143 # check there is an image of a computer in there
144 self.assertTrue(('Image', 'computer') in interesting)
145 # check a placeholder for the local machine description is there
146 self.assertTrue(('Label', '<LOCAL MACHINE>') in interesting)
147 # check the bw limitation stuff is there
148 self.assertTrue(('CheckButton', '_Limit Bandwidth Usage')
149 in interesting)
150 self.assertTrue(('Label', 'Maximum _download speed (KB/s):')
151 in interesting)
152 self.assertTrue(('Label', 'Maximum _upload speed (KB/s):')
153 in interesting)
154 # check the 'Remove' button is *not* there
155 self.assertTrue(('Button', 'Remove') not in interesting)
156 finally:
157 widget.destroy()
158
159 def test_list_devices_shows_real_devices_list(self):
160 self.mocker.replay()
161 widget = self.u1prefs.DevicesWidget(None, keyring=self.keyring)
162 try:
163 widget.devices = [{'kind': 'Computer',
164 'description': 'xyzzy',
165 'token': 'blah'},
166 {'kind': 'Phone',
167 'description': 'quux',
168 'token': '1234'}]
169 widget.list_devices()
170 # fake data now in devices
171 interesting = []
172 for i in widget.get_children():
173 clsname = i.__class__.__name__
174 if clsname == 'Image':
175 interesting.append((clsname, i.get_icon_name()[0]))
176 if clsname in ('Label', 'Button', 'CheckButton'):
177 interesting.append((clsname, i.get_label()))
178 # check there is an image of a computer in there
179 self.assertTrue(('Image', 'computer') in interesting)
180 # and of a phone
181 self.assertTrue(('Image', 'phone') in interesting)
182 # check a label of the local machine description is there
183 self.assertTrue(('Label', 'xyzzy') in interesting)
184 # check the bw limitation stuff is not there (no local machine)
185 self.assertTrue(('CheckButton', '_Limit Bandwidth Usage')
186 not in interesting)
187 self.assertTrue(('Label', 'Download (kB/s):') not in interesting)
188 self.assertTrue(('Label', 'Upload (kB/s):') not in interesting)
189 # check the 'Remove' button is there
190 self.assertTrue(('Button', 'Remove') in interesting)
191 finally:
192 widget.destroy()
103193
104 def test_quota_display(self):194 def test_quota_display(self):
105 """Test that quota display works correctly."""195 """Test that quota display works correctly."""
106 self.mocker.replay()196 self.mocker.replay()
107 dialog = self.u1prefs.UbuntuOneDialog()197 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
108 self.assertTrue(dialog is not None)198 self.assertTrue(dialog is not None)
109 self.assertEqual(dialog.usage_graph.get_fraction(), 0.0)199 self.assertEqual(dialog.usage_graph.get_fraction(), 0.0)
110 dialog.update_quota_display(1024, 2048)200 dialog.update_quota_display(1024, 2048)
@@ -113,11 +203,6 @@
113203
114 def test_request_quota_info(self):204 def test_request_quota_info(self):
115 """Test that we can request the quota info properly."""205 """Test that we can request the quota info properly."""
116 self.mock_has_token()
117 dialog = self.u1prefs.UbuntuOneDialog()
118 self.assertTrue(dialog is not None)
119 dialog.keyring = self.keyring
120 self.assertEqual(dialog.usage_graph.get_fraction(), 0.0)
121 response = { 'status' : '200' }206 response = { 'status' : '200' }
122 content = '{"total":2048, "used":1024}'207 content = '{"total":2048, "used":1024}'
123 client = self.mocker.mock()208 client = self.mocker.mock()
@@ -125,16 +210,15 @@
125 self.expect(client.request('https://one.ubuntu.com/api/quota/',210 self.expect(client.request('https://one.ubuntu.com/api/quota/',
126 'GET', KWARGS)).result((response, content))211 'GET', KWARGS)).result((response, content))
127 self.mocker.replay()212 self.mocker.replay()
213 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
214 self.assertTrue(dialog is not None)
215 self.assertEqual(dialog.usage_graph.get_fraction(), 0.0)
128 dialog.request_quota_info()216 dialog.request_quota_info()
129 self.assertEqual(dialog.usage_graph.get_fraction(), 0.5)217 self.assertEqual(dialog.usage_graph.get_fraction(), 0.5)
130 dialog.destroy()218 dialog.destroy()
131219
132 def test_request_account_info(self):220 def test_request_account_info(self):
133 """Test that we can request the account info properly."""221 """Test that we can request the account info properly."""
134 self.mock_has_token()
135 dialog = self.u1prefs.UbuntuOneDialog()
136 self.assertTrue(dialog is not None)
137 dialog.keyring = self.keyring
138 response = { 'status' : '200' }222 response = { 'status' : '200' }
139 content = '''{"username": "ubuntuone", "nickname": "Ubuntu One",223 content = '''{"username": "ubuntuone", "nickname": "Ubuntu One",
140 "email": "uone@example.com"}224 "email": "uone@example.com"}
@@ -144,6 +228,8 @@
144 self.expect(client.request('https://one.ubuntu.com/api/account/',228 self.expect(client.request('https://one.ubuntu.com/api/account/',
145 'GET', KWARGS)).result((response, content))229 'GET', KWARGS)).result((response, content))
146 self.mocker.replay()230 self.mocker.replay()
231 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
232 self.assertTrue(dialog is not None)
147 dialog.request_account_info()233 dialog.request_account_info()
148 self.assertEqual(dialog.name_label.get_text(), 'Ubuntu One')234 self.assertEqual(dialog.name_label.get_text(), 'Ubuntu One')
149 self.assertEqual(dialog.user_label.get_text(), 'ubuntuone')235 self.assertEqual(dialog.user_label.get_text(), 'ubuntuone')
@@ -152,13 +238,14 @@
152238
153 def test_toggle_bookmarks(self):239 def test_toggle_bookmarks(self):
154 """Test toggling the bookmarks service on/off."""240 """Test toggling the bookmarks service on/off."""
155 dialog = self.u1prefs.UbuntuOneDialog()241 toggle_db_sync = self.mocker.mock()
242 self.expect(toggle_db_sync('bookmarks', False))
243 self.expect(toggle_db_sync('bookmarks', True))
244 self.expect(toggle_db_sync('bookmarks', False))
245 self.mocker.replay()
246 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
156 self.assertTrue(dialog is not None)247 self.assertTrue(dialog is not None)
157 dialog.toggle_db_sync = self.mocker.mock()248 dialog.toggle_db_sync = toggle_db_sync
158 self.expect(dialog.toggle_db_sync('bookmarks', False))
159 self.expect(dialog.toggle_db_sync('bookmarks', True))
160 self.expect(dialog.toggle_db_sync('bookmarks', False))
161 self.mocker.replay()
162 dialog.bookmarks_check.set_active(True)249 dialog.bookmarks_check.set_active(True)
163 self.assertTrue(dialog.bookmarks_check.get_active())250 self.assertTrue(dialog.bookmarks_check.get_active())
164 dialog.bookmarks_check.set_active(False)251 dialog.bookmarks_check.set_active(False)
@@ -168,13 +255,14 @@
168255
169 def test_toggle_contacts(self):256 def test_toggle_contacts(self):
170 """Test toggling the contacts service on/off."""257 """Test toggling the contacts service on/off."""
171 dialog = self.u1prefs.UbuntuOneDialog()258 toggle_db_sync = self.mocker.mock()
259 self.expect(toggle_db_sync('contacts', False))
260 self.expect(toggle_db_sync('contacts', True))
261 self.expect(toggle_db_sync('contacts', False))
262 self.mocker.replay()
263 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
172 self.assertTrue(dialog is not None)264 self.assertTrue(dialog is not None)
173 dialog.toggle_db_sync = self.mocker.mock()265 dialog.toggle_db_sync = toggle_db_sync
174 self.expect(dialog.toggle_db_sync('contacts', False))
175 self.expect(dialog.toggle_db_sync('contacts', True))
176 self.expect(dialog.toggle_db_sync('contacts', False))
177 self.mocker.replay()
178 dialog.abook_check.set_active(True)266 dialog.abook_check.set_active(True)
179 self.assertTrue(dialog.abook_check.get_active())267 self.assertTrue(dialog.abook_check.get_active())
180 dialog.abook_check.set_active(False)268 dialog.abook_check.set_active(False)
@@ -184,9 +272,9 @@
184272
185 def test_toggle_files(self):273 def test_toggle_files(self):
186 """Test toggling the files service on/off."""274 """Test toggling the files service on/off."""
187 dialog = self.u1prefs.UbuntuOneDialog()275 self.mocker.replay()
276 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
188 self.assertTrue(dialog is not None)277 self.assertTrue(dialog is not None)
189 self.mocker.replay()
190 dialog.files_check.set_active(True)278 dialog.files_check.set_active(True)
191 self.assertTrue(dialog.files_check.get_active())279 self.assertTrue(dialog.files_check.get_active())
192 dialog.files_check.set_active(False)280 dialog.files_check.set_active(False)
@@ -196,9 +284,9 @@
196284
197 def test_toggle_files_and_music(self):285 def test_toggle_files_and_music(self):
198 """Test toggling the files and music services on/off."""286 """Test toggling the files and music services on/off."""
199 dialog = self.u1prefs.UbuntuOneDialog()287 self.mocker.replay()
288 dialog = self.u1prefs.UbuntuOneDialog(keyring=self.keyring)
200 self.assertTrue(dialog is not None)289 self.assertTrue(dialog is not None)
201 self.mocker.replay()
202 dialog.files_check.set_active(False)290 dialog.files_check.set_active(False)
203 self.assertFalse(dialog.files_check.get_active())291 self.assertFalse(dialog.files_check.get_active())
204 self.assertFalse(dialog.music_check.props.sensitive)292 self.assertFalse(dialog.music_check.props.sensitive)
205293
=== modified file 'ubuntuone/syncdaemon/dbus_interface.py'
--- ubuntuone/syncdaemon/dbus_interface.py 2010-03-05 20:32:42 +0000
+++ ubuntuone/syncdaemon/dbus_interface.py 2010-03-08 19:59:28 +0000
@@ -1025,6 +1025,7 @@
1025 configured.1025 configured.
1026 The values are bytes/second1026 The values are bytes/second
1027 """1027 """
1028 logger.debug("called get_throttling_limits")
1028 try:1029 try:
1029 aq = self.dbus_iface.action_queue1030 aq = self.dbus_iface.action_queue
1030 download = -11031 download = -1
@@ -1052,6 +1053,7 @@
1052 def set_throttling_limits(self, download, upload,1053 def set_throttling_limits(self, download, upload,
1053 reply_handler=None, error_handler=None):1054 reply_handler=None, error_handler=None):
1054 """Set the read and write limits. The expected values are bytes/sec."""1055 """Set the read and write limits. The expected values are bytes/sec."""
1056 logger.debug("called set_throttling_limits")
1055 try:1057 try:
1056 # modify and save the config file1058 # modify and save the config file
1057 user_config = config.get_user_config()1059 user_config = config.get_user_config()

Subscribers

People subscribed via source and target branches