Merge lp:~nataliabidart/ubuntuone-control-panel/simpler-devices-backend into lp:ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 168
Merged at revision: 167
Proposed branch: lp:~nataliabidart/ubuntuone-control-panel/simpler-devices-backend
Merge into: lp:ubuntuone-control-panel
Diff against target: 391 lines (+192/-55)
3 files modified
ubuntuone/controlpanel/backend.py (+86/-45)
ubuntuone/controlpanel/tests/__init__.py (+28/-2)
ubuntuone/controlpanel/tests/test_backend.py (+78/-8)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-control-panel/simpler-devices-backend
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
John Lenton (community) Approve
Review via email: mp+65368@code.launchpad.net

Commit message

- Backend now provides a simpler device query method: device_names_info (LP: #798413).

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) :
review: Approve
168. By Natalia Bidart

Merged trunk in.

Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve

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-06-17 21:11:45 +0000
3+++ ubuntuone/controlpanel/backend.py 2011-06-21 16:37:25 +0000
4@@ -46,6 +46,7 @@
5 SHOW_ALL_NOTIFICATIONS_KEY = 'show_all_notifications'
6 SHARE_AUTOSUBSCRIBE_KEY = 'share_autosubscribe'
7 UDF_AUTOSUBSCRIBE_KEY = 'udf_autosubscribe'
8+LIMIT_BW_KEY = 'limit_bandwidth'
9 UPLOAD_KEY = "max_upload_speed"
10 DOWNLOAD_KEY = "max_download_speed"
11
12@@ -191,17 +192,20 @@
13 _set_status_changed_handler)
14
15 @inlineCallbacks
16- def _process_device_web_info(self, devices, enabled, limit_bw, limits,
17- autoconnect, show_notifs,
18- share_autosubscribe, udf_autosubscribe):
19- """Return a lis of processed devices."""
20+ def _process_device_web_info(self, devices,
21+ enabled=None, limit_bw=None, limits=None, autoconnect=None,
22+ show_notifs=None, share_autosubscribe=None, udf_autosubscribe=None):
23+ """Return a lis of processed devices.
24+
25+ If all the file sync settings are None, do not attach that info.
26+
27+ """
28 result = []
29 for d in devices:
30 di = {}
31 di["type"] = d["kind"]
32 di["name"] = d["description"] if d["description"] \
33 else self.NAME_NOT_SET
34- di["configurable"] = False
35 if di["type"] == DEVICE_TYPE_COMPUTER:
36 di["device_id"] = di["type"] + d["token"]
37 if di["type"] == DEVICE_TYPE_PHONE:
38@@ -209,12 +213,22 @@
39
40 is_local = yield self.device_is_local(di["device_id"])
41 di["is_local"] = is_local
42+
43+ if is_local: # prepend the local device!
44+ result.insert(0, di)
45+ else:
46+ result.append(di)
47+
48+ if enabled is None:
49+ # without knowing if file sync is enabled or not,
50+ # we can't add any extra info about the device.
51+ continue
52+
53 # currently, only local devices are configurable.
54- # eventually, more devices will be configurable.
55 di["configurable"] = is_local and enabled
56
57 if di["configurable"]:
58- di["limit_bandwidth"] = limit_bw
59+ di[LIMIT_BW_KEY] = limit_bw
60 di[AUTOCONNECT_KEY] = autoconnect
61 di[SHOW_ALL_NOTIFICATIONS_KEY] = show_notifs
62 di[SHARE_AUTOSUBSCRIBE_KEY] = share_autosubscribe
63@@ -222,20 +236,41 @@
64 di[UPLOAD_KEY] = limits["upload"]
65 di[DOWNLOAD_KEY] = limits["download"]
66
67- # date_added is not in the webservice yet (LP: #673668)
68- # di["date_added"] = ""
69-
70- # missing values (LP: #673668)
71- # di["available_services"] = ""
72- # di["enabled_services"] = ""
73-
74- if is_local: # prepend the local device!
75- result.insert(0, di)
76- else:
77- result.append(di)
78-
79 returnValue(result)
80
81+ @inlineCallbacks
82+ def _process_device_local_info(self,
83+ enabled=None, limit_bw=None, limits=None, autoconnect=None,
84+ show_notifs=None, share_autosubscribe=None, udf_autosubscribe=None):
85+ """Return the information for the local device.
86+
87+ If all the file sync settings are None, do not attach that info.
88+
89+ """
90+ credentials = yield login_client.get_credentials()
91+
92+ local_device = {}
93+ local_device["type"] = DEVICE_TYPE_COMPUTER
94+ local_device["name"] = credentials['name']
95+ device_id = local_device["type"] + credentials["token"]
96+ local_device["device_id"] = device_id
97+ local_device["is_local"] = True
98+
99+ if enabled is not None:
100+ local_device["configurable"] = enabled
101+ if local_device["configurable"]:
102+ local_device[LIMIT_BW_KEY] = limit_bw
103+ local_device[AUTOCONNECT_KEY] = autoconnect
104+ local_device[SHOW_ALL_NOTIFICATIONS_KEY] = show_notifs
105+ local_device[SHARE_AUTOSUBSCRIBE_KEY] = share_autosubscribe
106+ local_device[UDF_AUTOSUBSCRIBE_KEY] = udf_autosubscribe
107+ upload = limits["upload"]
108+ download = limits["download"]
109+ local_device[UPLOAD_KEY] = upload
110+ local_device[DOWNLOAD_KEY] = download
111+
112+ returnValue(local_device)
113+
114 def _process_path(self, path):
115 """Trim 'path' so the '~' is removed."""
116 home = os.path.expanduser('~')
117@@ -329,33 +364,39 @@
118 result = yield self._process_device_web_info(devices, enabled,
119 limit_bw, limits, autoconnect, show_notifs,
120 share_autosubscribe, udf_autosubscribe)
121+
122 if result is None:
123- logger.info('devices_info: result is None after calling '
124- 'devices/ API, building the local device.')
125- credentials = yield login_client.get_credentials()
126- local_device = {}
127- local_device["type"] = DEVICE_TYPE_COMPUTER
128- local_device["name"] = credentials['name']
129- device_id = local_device["type"] + credentials["token"]
130- local_device["device_id"] = device_id
131- local_device["is_local"] = True
132- local_device["configurable"] = enabled
133- if local_device["configurable"]:
134- local_device["limit_bandwidth"] = limit_bw
135- local_device[AUTOCONNECT_KEY] = autoconnect
136- local_device[SHOW_ALL_NOTIFICATIONS_KEY] = show_notifs
137- local_device[SHARE_AUTOSUBSCRIBE_KEY] = share_autosubscribe
138- local_device[UDF_AUTOSUBSCRIBE_KEY] = udf_autosubscribe
139- upload = limits["upload"]
140- download = limits["download"]
141- local_device[UPLOAD_KEY] = upload
142- local_device[DOWNLOAD_KEY] = download
143- logger.debug('devices_info: local device built: %r.', local_device)
144+ local_device = yield self._process_device_local_info(enabled,
145+ limit_bw, limits, autoconnect, show_notifs,
146+ share_autosubscribe, udf_autosubscribe)
147 result = [local_device]
148+
149+ logger.info('devices_info: result is %r',
150+ filter_field(result, field='device_id'))
151+
152+ returnValue(result)
153+
154+ @log_call(logger.debug)
155+ @process_unauthorized
156+ @inlineCallbacks
157+ def device_names_info(self):
158+ """Get the user devices info, only list names and kind."""
159+ result = None
160+ try:
161+ devices = yield self.wc.call_api(DEVICES_API)
162+ except UnauthorizedError:
163+ raise
164+ except WebClientError:
165+ logger.exception('device_names_info: web client failure:')
166 else:
167- logger.info('devices_info: result is not None after calling '
168- 'devices/ API: %r',
169- filter_field(result, field='device_id'))
170+ result = yield self._process_device_web_info(devices)
171+
172+ if result is None:
173+ local_device = yield self._process_device_local_info()
174+ result = [local_device]
175+
176+ logger.info('device_names_info: result is %r',
177+ filter_field(result, field='device_id'))
178
179 returnValue(result)
180
181@@ -379,8 +420,8 @@
182 else:
183 yield sd_client.enable_show_all_notifications()
184
185- if is_local and "limit_bandwidth" in settings:
186- if not settings["limit_bandwidth"]:
187+ if is_local and LIMIT_BW_KEY in settings:
188+ if not settings[LIMIT_BW_KEY]:
189 yield sd_client.disable_bandwidth_throttling()
190 else:
191 yield sd_client.enable_bandwidth_throttling()
192
193=== modified file 'ubuntuone/controlpanel/tests/__init__.py'
194--- ubuntuone/controlpanel/tests/__init__.py 2011-06-14 20:18:30 +0000
195+++ ubuntuone/controlpanel/tests/__init__.py 2011-06-21 16:37:25 +0000
196@@ -20,6 +20,10 @@
197
198 from ubuntuone.devtools.testcase import TestCase as BaseTestCase
199
200+from ubuntuone.controlpanel.backend import (
201+ DEVICE_TYPE_COMPUTER, DEVICE_TYPE_PHONE,
202+)
203+
204
205 TOKEN = {u'consumer_key': u'xQ7xDAz',
206 u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy',
207@@ -141,19 +145,41 @@
208 {
209 "device_id": "ComputerABCDEF01234token",
210 "name": "Ubuntu One @ darkstar",
211- "type": "Computer",
212+ "type": DEVICE_TYPE_COMPUTER,
213 "is_local": False,
214 "configurable": False,
215 },
216 {
217 "device_id": "Phone1000",
218 "name": "Nokia E65",
219- "type": "Phone",
220+ "type": DEVICE_TYPE_PHONE,
221 "configurable": False,
222 "is_local": False,
223 },
224 ]
225
226+# note that local computer should be first, do not change!
227+EXPECTED_DEVICE_NAMES_INFO = [
228+ {
229+ 'device_id': 'ComputerABCDEF01234-localtoken',
230+ 'name': 'Ubuntu One @ localhost',
231+ 'type': DEVICE_TYPE_COMPUTER,
232+ 'is_local': True,
233+ },
234+ {
235+ 'device_id': 'ComputerABCDEF01234token',
236+ 'name': 'Ubuntu One @ darkstar',
237+ 'type': DEVICE_TYPE_COMPUTER,
238+ 'is_local': False,
239+ },
240+ {
241+ 'device_id': 'Phone1000',
242+ 'name': 'Nokia E65',
243+ 'type': DEVICE_TYPE_PHONE,
244+ 'is_local': False,
245+ },
246+]
247+
248 SAMPLE_FOLDERS = [
249 {u'generation': u'2',
250 u'node_id': u'341da068-81d8-437a-8f75-5bb9d86455ba',
251
252=== modified file 'ubuntuone/controlpanel/tests/test_backend.py'
253--- ubuntuone/controlpanel/tests/test_backend.py 2011-06-17 21:11:45 +0000
254+++ ubuntuone/controlpanel/tests/test_backend.py 2011-06-21 16:37:25 +0000
255@@ -48,6 +48,7 @@
256 EMPTY_DESCRIPTION_JSON,
257 EXPECTED_ACCOUNT_INFO,
258 EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN,
259+ EXPECTED_DEVICE_NAMES_INFO,
260 EXPECTED_DEVICES_INFO,
261 LOCAL_DEVICE,
262 ROOT_PATH,
263@@ -440,7 +441,7 @@
264 yield d
265
266 @inlineCallbacks
267- def test_devices_info_if_files_disable(self):
268+ def test_devices_info_if_files_disabled(self):
269 """The devices_info returns device only info if files is disabled."""
270 yield self.be.disable_files()
271 status = yield self.be.file_sync_status()
272@@ -485,6 +486,75 @@
273 self.assertTrue(device_id_logged)
274
275 @inlineCallbacks
276+ def test_device_names_info(self):
277+ """The device_names_info returns the correct info."""
278+ self.be.wc.results[DEVICES_API] = SAMPLE_DEVICES_JSON
279+ result = yield self.be.device_names_info()
280+ self.assertEqual(result, EXPECTED_DEVICE_NAMES_INFO)
281+
282+ @inlineCallbacks
283+ def test_device_names_info_fails(self):
284+ """The device_names_info method exercises its errback."""
285+ def fail(*args, **kwargs):
286+ """Raise any error other than WebClientError."""
287+ raise ValueError(args)
288+
289+ self.patch(self.be.wc, 'call_api', fail)
290+ yield self.assertFailure(self.be.device_names_info(), ValueError)
291+
292+ @inlineCallbacks
293+ def test_device_names_info_with_webclient_error(self):
294+ """The device_names_info returns local info if webclient error."""
295+ MockWebClient.failure = 404
296+ result = yield self.be.device_names_info()
297+
298+ device = LOCAL_DEVICE.copy()
299+ device.pop('configurable', None)
300+ device.pop('limit_bandwidth', None)
301+ device.pop(backend.DOWNLOAD_KEY, None)
302+ device.pop(backend.UPLOAD_KEY, None)
303+ device.pop(backend.AUTOCONNECT_KEY, None)
304+ device.pop(backend.SHOW_ALL_NOTIFICATIONS_KEY, None)
305+ device.pop(backend.SHARE_AUTOSUBSCRIBE_KEY, None)
306+ device.pop(backend.UDF_AUTOSUBSCRIBE_KEY, None)
307+ self.assertEqual(result, [device])
308+ self.assertTrue(self.memento.check_error('device_names_info',
309+ 'web client failure'))
310+
311+ @inlineCallbacks
312+ def test_device_names_info_fails_with_unauthorized(self):
313+ """The device_names_info clears the credentials on unauthorized."""
314+ MockWebClient.failure = 401
315+ d = defer.Deferred()
316+ self.patch(backend.login_client, 'clear_credentials',
317+ lambda: d.callback('called'))
318+ yield self.assertFailure(self.be.device_names_info(),
319+ backend.UnauthorizedError)
320+ yield d
321+
322+ @inlineCallbacks
323+ def test_device_names_info_when_token_name_is_empty(self):
324+ """The device_names_info can handle empty token names."""
325+ self.be.wc.results[DEVICES_API] = EMPTY_DESCRIPTION_JSON
326+ result = yield self.be.device_names_info()
327+ expected = {'device_id': 'ComputerABCDEF01234token',
328+ 'is_local': False, 'name': self.be.NAME_NOT_SET,
329+ 'type': DEVICE_TYPE_COMPUTER}
330+ self.assertEqual(result, [expected])
331+
332+ @inlineCallbacks
333+ def test_device_names_info_does_not_log_device_id(self):
334+ """The device_names_info does not log the device_id."""
335+ self.be.wc.results[DEVICES_API] = SAMPLE_DEVICES_JSON
336+ yield self.be.device_names_info()
337+
338+ dids = (d['device_id'] for d in EXPECTED_DEVICES_INFO)
339+ device_id_logged = all(all(did not in r.getMessage()
340+ for r in self.memento.records)
341+ for did in dids)
342+ self.assertTrue(device_id_logged)
343+
344+ @inlineCallbacks
345 def test_remove_device(self):
346 """The remove_device method calls the right api."""
347 dtype, did = DEVICE_TYPE_COMPUTER, "SAMPLE-TOKEN"
348@@ -549,10 +619,10 @@
349 """The device settings are updated."""
350 backend.sd_client.throttling = False
351 yield self.be.change_device_settings(self.local_token,
352- {"limit_bandwidth": True})
353+ {backend.LIMIT_BW_KEY: True})
354 self.assertEqual(backend.sd_client.throttling, True)
355 yield self.be.change_device_settings(self.local_token,
356- {"limit_bandwidth": False})
357+ {backend.LIMIT_BW_KEY: False})
358 self.assertEqual(backend.sd_client.throttling, False)
359
360 @inlineCallbacks
361@@ -560,7 +630,7 @@
362 """The device settings are updated."""
363 backend.sd_client.limits = {"download": -1, "upload": -1}
364 yield self.be.change_device_settings(self.local_token,
365- {"max_upload_speed": 1111})
366+ {backend.UPLOAD_KEY: 1111})
367 self.assertEqual(backend.sd_client.limits["upload"], 1111)
368 self.assertEqual(backend.sd_client.limits["download"], -1)
369
370@@ -569,7 +639,7 @@
371 """The device settings are updated."""
372 backend.sd_client.limits = {"download": -1, "upload": -1}
373 yield self.be.change_device_settings(self.local_token,
374- {"max_download_speed": 99})
375+ {backend.DOWNLOAD_KEY: 99})
376 self.assertEqual(backend.sd_client.limits["upload"], -1)
377 self.assertEqual(backend.sd_client.limits["download"], 99)
378
379@@ -579,9 +649,9 @@
380 backend.sd_client.throttling = False
381 backend.sd_client.limits = {"download": -1, "upload": -1}
382 new_settings = {
383- "max_download_speed": 99,
384- "max_upload_speed": 99,
385- "limit_bandwidth": True,
386+ backend.DOWNLOAD_KEY: 99,
387+ backend.UPLOAD_KEY: 99,
388+ backend.LIMIT_BW_KEY: True,
389 }
390 yield self.be.change_device_settings("wrong token!", new_settings)
391 self.assertEqual(backend.sd_client.throttling, False)

Subscribers

People subscribed via source and target branches