Merge lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 into lp:ubuntu/natty/ubuntuone-control-panel
- Natty (11.04)
- ubuntuone-control-panel-0.9.6
- Merge into natty
Proposed by
Natalia Bidart
Status: | Merged |
---|---|
Merged at revision: | 21 |
Proposed branch: | lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 |
Merge into: | lp:ubuntu/natty/ubuntuone-control-panel |
Diff against target: |
590 lines (+250/-37) 12 files modified
PKG-INFO (+1/-1) debian/changelog (+20/-0) debian/control (+6/-6) setup.py (+1/-1) ubuntuone/controlpanel/backend.py (+25/-8) ubuntuone/controlpanel/gtk/gui.py (+24/-6) ubuntuone/controlpanel/gtk/tests/__init__.py (+11/-2) ubuntuone/controlpanel/gtk/tests/test_gui.py (+61/-1) ubuntuone/controlpanel/gtk/tests/test_gui_basic.py (+1/-1) ubuntuone/controlpanel/gtk/tests/test_widgets.py (+8/-0) ubuntuone/controlpanel/gtk/widgets.py (+2/-0) ubuntuone/controlpanel/tests/test_backend.py (+90/-11) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntu/natty/ubuntuone-control-panel/ubuntuone-control-panel-0.9.6 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Sponsors | Pending | ||
Review via email: mp+57347@code.launchpad.net |
Commit message
Description of the change
* New upstream release.
[ Natalia B. Bidart <email address hidden> ]
- Free bytes will not be displayed in the UI for read-only shares.
Also, backend now handles quota info not available for the root folder
(LP: #726580).
- Setting the unity's urgent prop only if available (LP: #755185).
- Made panel title selectable. Tab messages are now also selectable
(LP: #757543).
- Highlight with red and bold when free space available is very little
(either in own volumes or shares) (LP: #753989).
* debian/control:
- bump depends versions for ubuntuone-client (>= 1.6.0) and
ubuntu-
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'PKG-INFO' |
2 | --- PKG-INFO 2011-04-08 16:07:22 +0000 |
3 | +++ PKG-INFO 2011-04-12 16:04:35 +0000 |
4 | @@ -1,6 +1,6 @@ |
5 | Metadata-Version: 1.1 |
6 | Name: ubuntuone-control-panel |
7 | -Version: 0.9.5 |
8 | +Version: 0.9.6 |
9 | Summary: Ubuntu One Control Panel |
10 | Home-page: https://launchpad.net/ubuntuone-control-panel |
11 | Author: Natalia Bidart |
12 | |
13 | === modified file 'debian/changelog' |
14 | --- debian/changelog 2011-04-08 20:23:32 +0000 |
15 | +++ debian/changelog 2011-04-12 16:04:35 +0000 |
16 | @@ -1,3 +1,23 @@ |
17 | +ubuntuone-control-panel (0.9.6-0ubuntu1) UNRELEASED; urgency=low |
18 | + |
19 | + * New upstream release. |
20 | + |
21 | + [ Natalia B. Bidart <natalia.bidart@canonical.com> ] |
22 | + - Free bytes will not be displayed in the UI for read-only shares. |
23 | + Also, backend now handles quota info not available for the root folder |
24 | + (LP: #726580). |
25 | + - Setting the unity's urgent prop only if available (LP: #755185). |
26 | + - Made panel title selectable. Tab messages are now also selectable |
27 | + (LP: #757543). |
28 | + - Highlight with red and bold when free space available is very little |
29 | + (either in own volumes or shares) (LP: #753989). |
30 | + |
31 | + * debian/control: |
32 | + - bump depends versions for ubuntuone-client (>= 1.6.0) and |
33 | + ubuntu-sso-client (>= 1.2.0). |
34 | + |
35 | + -- Natalia Bidart (nessita) <nataliabidart@gmail.com> Tue, 12 Apr 2011 12:11:11 -0300 |
36 | + |
37 | ubuntuone-control-panel (0.9.5-0ubuntu1) natty; urgency=low |
38 | |
39 | * New upstream release: |
40 | |
41 | === modified file 'debian/control' |
42 | --- debian/control 2011-03-10 03:09:16 +0000 |
43 | +++ debian/control 2011-04-12 16:04:35 +0000 |
44 | @@ -17,7 +17,7 @@ |
45 | ${python:Depends}, |
46 | python, |
47 | python-ubuntuone-control-panel (= ${binary:Version}), |
48 | - ubuntuone-client (>= 1.5.6), |
49 | + ubuntuone-client (>= 1.6.0), |
50 | Recommends: ubuntuone-control-panel-gui |
51 | Description: Ubuntu One Control Panel |
52 | Desktop application to manage a Ubuntu One account. |
53 | @@ -37,8 +37,8 @@ |
54 | python-simplejson, |
55 | python-twisted-core, |
56 | python-twisted-web, |
57 | - python-ubuntuone-client (>= 1.5.6), |
58 | - ubuntu-sso-client (>= 1.1.11), |
59 | + python-ubuntuone-client (>= 1.6.0), |
60 | + ubuntu-sso-client (>= 1.2.0), |
61 | Description: Ubuntu One Control Panel Python Libraries |
62 | Ubuntu One Control Panel provides a Python library to manage an Ubuntu One |
63 | account. |
64 | @@ -54,9 +54,9 @@ |
65 | python-defer, |
66 | python-gobject, |
67 | python-gtk2, |
68 | - python-ubuntuone-client (>= 1.5.6), |
69 | - ubuntu-sso-client (>= 1.1.11), |
70 | - ubuntuone-client (>= 1.5.6), |
71 | + python-ubuntuone-client (>= 1.6.0), |
72 | + ubuntu-sso-client (>= 1.2.0), |
73 | + ubuntuone-client (>= 1.6.0), |
74 | ubuntuone-control-panel (= ${binary:Version}), |
75 | Provides: ubuntuone-control-panel-gui |
76 | Description: Ubuntu One Control Panel |
77 | |
78 | === modified file 'setup.py' |
79 | --- setup.py 2011-04-08 16:07:22 +0000 |
80 | +++ setup.py 2011-04-12 16:04:35 +0000 |
81 | @@ -79,7 +79,7 @@ |
82 | |
83 | DistUtilsExtra.auto.setup( |
84 | name='ubuntuone-control-panel', |
85 | - version='0.9.5', |
86 | + version='0.9.6', |
87 | license='GPL v3', |
88 | author='Natalia Bidart', |
89 | author_email='natalia.bidart@canonical.com', |
90 | |
91 | === modified file 'ubuntuone/controlpanel/backend.py' |
92 | --- ubuntuone/controlpanel/backend.py 2011-04-08 16:07:22 +0000 |
93 | +++ ubuntuone/controlpanel/backend.py 2011-04-12 16:04:35 +0000 |
94 | @@ -100,6 +100,7 @@ |
95 | FOLDER_TYPE = u'UDF' |
96 | SHARE_TYPE = u'SHARE' |
97 | NAME_NOT_SET = u'ENAMENOTSET' |
98 | + FREE_BYTES_NOT_AVAILABLE = u'EFREEBYTESNOTAVAILABLE' |
99 | STATUS_DISABLED = {MSG_KEY: '', STATUS_KEY: FILE_SYNC_DISABLED} |
100 | |
101 | def __init__(self, shutdown_func=None): |
102 | @@ -450,14 +451,21 @@ |
103 | """Get the volumes info.""" |
104 | self._volumes = {} |
105 | |
106 | - account = yield self.account_info() |
107 | + try: |
108 | + account = yield self.account_info() |
109 | + except Exception: # pylint: disable=W0703 |
110 | + logger.exception('volumes_info: quota could not be retrieved:') |
111 | + free_bytes = self.FREE_BYTES_NOT_AVAILABLE |
112 | + else: |
113 | + free_bytes = int(account['quota_total']) - \ |
114 | + int(account['quota_used']) |
115 | + |
116 | root_dir = yield dbus_client.get_root_dir() |
117 | shares_dir = yield dbus_client.get_shares_dir() |
118 | shares_dir_link = yield dbus_client.get_shares_dir_link() |
119 | folders = yield dbus_client.get_folders() |
120 | shares = yield dbus_client.get_shares() |
121 | |
122 | - free_bytes = int(account['quota_total']) - int(account['quota_used']) |
123 | root_volume = {u'volume_id': u'', u'path': root_dir, |
124 | u'subscribed': 'True', u'type': self.ROOT_TYPE} |
125 | self._volumes[u''] = root_volume |
126 | @@ -465,15 +473,17 @@ |
127 | # group shares by the offering user |
128 | shares_result = defaultdict(list) |
129 | for share in shares: |
130 | + if not bool(share['accepted']): |
131 | + continue |
132 | + |
133 | share[u'type'] = self.SHARE_TYPE |
134 | |
135 | vid = share['volume_id'] |
136 | - assert vid not in self._volumes |
137 | + if vid in self._volumes: |
138 | + logger.warning('volumes_info: share %r already in the volumes ' |
139 | + 'list (%r).', vid, self._volumes[vid]) |
140 | self._volumes[vid] = share |
141 | |
142 | - if not bool(share['accepted']): |
143 | - continue |
144 | - |
145 | nicer_path = share[u'path'].replace(shares_dir, shares_dir_link) |
146 | share[u'path'] = nicer_path |
147 | |
148 | @@ -488,13 +498,20 @@ |
149 | folder[u'type'] = self.FOLDER_TYPE |
150 | |
151 | vid = folder['volume_id'] |
152 | - assert vid not in self._volumes |
153 | + if vid in self._volumes: |
154 | + logger.warning('volumes_info: udf %r already in the volumes ' |
155 | + 'list (%r).', vid, self._volumes[vid]) |
156 | self._volumes[vid] = folder |
157 | |
158 | result = [(u'', unicode(free_bytes), [root_volume] + folders)] |
159 | |
160 | for other_username, shares in shares_result.iteritems(): |
161 | - result.append((other_username, shares[0][u'free_bytes'], shares)) |
162 | + send_freebytes = any(s['access_level'] == 'Modify' for s in shares) |
163 | + if send_freebytes: |
164 | + free_bytes = shares[0][u'free_bytes'] |
165 | + else: |
166 | + free_bytes = self.FREE_BYTES_NOT_AVAILABLE |
167 | + result.append((other_username, free_bytes, shares)) |
168 | |
169 | returnValue(result) |
170 | |
171 | |
172 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' |
173 | --- ubuntuone/controlpanel/gtk/gui.py 2011-04-08 16:07:22 +0000 |
174 | +++ ubuntuone/controlpanel/gtk/gui.py 2011-04-12 16:04:35 +0000 |
175 | @@ -456,7 +456,7 @@ |
176 | 'this computer') |
177 | MY_FOLDERS = _('My folders') |
178 | ALWAYS_SUBSCRIBED = _('Always in sync!') |
179 | - FREE_SPACE = _('%(free_space)s available storage') |
180 | + FREE_SPACE_TEXT = _('%(free_space)s available storage') |
181 | NO_VOLUMES = _('No folders to show.') |
182 | NAME_NOT_SET = _('[unknown user name]') |
183 | CONFIRM_MERGE = _('The contents of your cloud folder will be merged with ' |
184 | @@ -466,13 +466,15 @@ |
185 | MUSIC_REAL_PATH = '~/.ubuntuone/Purchased from Ubuntu One' |
186 | |
187 | MAX_COLS = 8 |
188 | + MIN_SIZE_FULL = 1048576 |
189 | |
190 | CONTACT_ICON_NAME = 'avatar-default' |
191 | FOLDER_ICON_NAME = 'folder' |
192 | SHARE_ICON_NAME = 'folder-remote' |
193 | MUSIC_ICON_NAME = 'audio-x-generic' |
194 | - ROW_HEADER = '<span font_size="large"><b>%s</b></span> ' \ |
195 | - '<span foreground="grey">%s</span>' |
196 | + FREE_SPACE = '<span foreground="grey">%s</span>' % FREE_SPACE_TEXT |
197 | + NO_FREE_SPACE = '<span foreground="red"><b>%s</b></span>' % FREE_SPACE_TEXT |
198 | + ROW_HEADER = '<span font_size="large"><b>%s</b></span> %s' |
199 | ROOT = '%s - <span foreground="%s" font_size="small">%s</span>' |
200 | |
201 | def __init__(self, main_window=None): |
202 | @@ -534,12 +536,28 @@ |
203 | else: |
204 | name = self.MY_FOLDERS |
205 | |
206 | - free_bytes_args = {'free_space': self.humanize(int(free_bytes))} |
207 | - row = (self.ROW_HEADER % (name, self.FREE_SPACE % free_bytes_args), |
208 | + scroll_to_cell = False |
209 | + if free_bytes == backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE: |
210 | + free_bytes = '' |
211 | + else: |
212 | + free_bytes = int(free_bytes) |
213 | + if free_bytes < self.MIN_SIZE_FULL: |
214 | + free_bytes_str = self.NO_FREE_SPACE |
215 | + scroll_to_cell = True |
216 | + else: |
217 | + free_bytes_str = self.FREE_SPACE |
218 | + free_bytes_args = {'free_space': self.humanize(free_bytes)} |
219 | + free_bytes = free_bytes_str % free_bytes_args |
220 | + |
221 | + row = (self.ROW_HEADER % (name, free_bytes), |
222 | True, self.CONTACT_ICON_NAME, False, False, |
223 | gtk.ICON_SIZE_LARGE_TOOLBAR, None, None) |
224 | treeiter = self.volumes_store.append(None, row) |
225 | |
226 | + if scroll_to_cell: |
227 | + path = self.volumes_store.get_string_from_iter(treeiter) |
228 | + self.volumes_view.scroll_to_cell(path) |
229 | + |
230 | volumes.sort(key=operator.itemgetter('path')) |
231 | for volume in volumes: |
232 | sensitive = True |
233 | @@ -1722,7 +1740,7 @@ |
234 | if not USE_LIBUNITY: |
235 | return |
236 | entry = Unity.LauncherEntry.get_for_desktop_id(U1_DOTDESKTOP) |
237 | - if entry.props.urgent: |
238 | + if getattr(entry.props, 'urgent', False): |
239 | self.switch_to('volumes') |
240 | entry.props.urgent = False |
241 | |
242 | |
243 | === modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py' |
244 | --- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-04-08 16:07:22 +0000 |
245 | +++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-04-12 16:04:35 +0000 |
246 | @@ -68,7 +68,6 @@ |
247 | {u'volume_id': u'1234', u'name': u'do', |
248 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', |
249 | u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}, |
250 | - |
251 | {u'volume_id': u'5678', u'name': u're', |
252 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', |
253 | u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE}, |
254 | @@ -76,7 +75,17 @@ |
255 | |
256 | FAKE_VOLUMES_INFO = [ |
257 | (u'', u'147852369', [ROOT] + FAKE_FOLDERS_INFO), |
258 | - (u'Other User', u'985674', FAKE_SHARES_INFO), |
259 | + (u'Other User', gui.VolumesPanel.MIN_SIZE_FULL, FAKE_SHARES_INFO), |
260 | +] |
261 | + |
262 | +FAKE_VOLUMES_NO_FREE_SPACE_INFO = [ |
263 | + (u'', u'500', [ROOT]), |
264 | + (u'No free space', u'0', |
265 | + [{u'volume_id': u'0', u'name': u'full', u'path': u'full-share', |
266 | + u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}]), |
267 | + (u'Almost no free space', gui.VolumesPanel.MIN_SIZE_FULL - 1, |
268 | + [{u'volume_id': u'1', u'name': u'almostfull', u'path': u'almost-full', |
269 | + u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE}]), |
270 | ] |
271 | |
272 | FAKE_DEVICE_INFO = { |
273 | |
274 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' |
275 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-04-08 16:07:22 +0000 |
276 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-04-12 16:04:35 +0000 |
277 | @@ -23,7 +23,7 @@ |
278 | from ubuntuone.controlpanel.gtk import gui |
279 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, |
280 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, FAKE_FOLDERS_INFO, |
281 | - FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, |
282 | + FAKE_VOLUMES_INFO, FAKE_VOLUMES_NO_FREE_SPACE_INFO, FAKE_REPLICATIONS_INFO, |
283 | MUSIC_FOLDER, ROOT, USER_HOME, |
284 | FakedConfirmDialog, |
285 | ) |
286 | @@ -260,6 +260,66 @@ |
287 | |
288 | self.assertEqual(len(self.ui.volumes_store), 0) |
289 | |
290 | + def test_on_volumes_info_ready_highlights_little_free_space(self): |
291 | + """The free space is red if is zero (or close to 0).""" |
292 | + self.ui.on_volumes_info_ready(FAKE_VOLUMES_NO_FREE_SPACE_INFO) |
293 | + |
294 | + treeiter = self.ui.volumes_store.get_iter_root() |
295 | + for name, free_bytes, volumes in FAKE_VOLUMES_NO_FREE_SPACE_INFO: |
296 | + name = "%s's" % name if name else self.ui.MY_FOLDERS |
297 | + free_bytes = self.ui.humanize(int(free_bytes)) |
298 | + free_bytes = self.ui.NO_FREE_SPACE % {'free_space': free_bytes} |
299 | + |
300 | + # check parent row |
301 | + row = self.ui.volumes_store.get(treeiter, |
302 | + *xrange(self.ui.MAX_COLS)) |
303 | + |
304 | + self.assertEqual(row[0], self.ui.ROW_HEADER % (name, free_bytes)) |
305 | + |
306 | + treeiter = self.ui.volumes_store.iter_next(treeiter) |
307 | + |
308 | + if treeiter is not None: |
309 | + # skip the empty row |
310 | + row = self.ui.volumes_store.get(treeiter, |
311 | + *xrange(self.ui.MAX_COLS)) |
312 | + self.assertEqual(row, self.ui._empty_row) |
313 | + |
314 | + # grab next non-empty row |
315 | + treeiter = self.ui.volumes_store.iter_next(treeiter) |
316 | + |
317 | + def test_on_volumes_info_ready_handles_no_quota_info(self): |
318 | + """The lack of free space is handled.""" |
319 | + info = [ |
320 | + (u'', gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE, [ROOT]), |
321 | + (u'No free space available', |
322 | + gui.backend.ControlBackend.FREE_BYTES_NOT_AVAILABLE, |
323 | + [{u'volume_id': u'0', u'name': u'full', |
324 | + u'path': u'full-share', u'subscribed': u'', |
325 | + u'type': gui.backend.ControlBackend.SHARE_TYPE}]), |
326 | + ] |
327 | + self.ui.on_volumes_info_ready(info) |
328 | + |
329 | + treeiter = self.ui.volumes_store.get_iter_root() |
330 | + for name, free_bytes, volumes in info: |
331 | + name = "%s's" % name if name else self.ui.MY_FOLDERS |
332 | + |
333 | + # check parent row |
334 | + row = self.ui.volumes_store.get(treeiter, |
335 | + *xrange(self.ui.MAX_COLS)) |
336 | + |
337 | + self.assertEqual(row[0], self.ui.ROW_HEADER % (name, '')) |
338 | + |
339 | + treeiter = self.ui.volumes_store.iter_next(treeiter) |
340 | + |
341 | + if treeiter is not None: |
342 | + # skip the empty row |
343 | + row = self.ui.volumes_store.get(treeiter, |
344 | + *xrange(self.ui.MAX_COLS)) |
345 | + self.assertEqual(row, self.ui._empty_row) |
346 | + |
347 | + # grab next non-empty row |
348 | + treeiter = self.ui.volumes_store.iter_next(treeiter) |
349 | + |
350 | def test_on_volumes_info_error(self): |
351 | """The volumes info couldn't be retrieved.""" |
352 | self.ui.on_volumes_info_error() |
353 | |
354 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui_basic.py' |
355 | --- ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 2011-04-08 16:07:22 +0000 |
356 | +++ ubuntuone/controlpanel/gtk/tests/test_gui_basic.py 2011-04-12 16:04:35 +0000 |
357 | @@ -143,7 +143,7 @@ |
358 | THE_FLEP.urgent = True |
359 | self.patch(gui.Unity, "LauncherEntry", FakeLauncherEntry) |
360 | cp = gui.ControlPanelWindow() |
361 | - cp.emit('focus-in-event', None) |
362 | + cp.emit('focus-in-event', gui.gtk.gdk.Event(gui.gtk.gdk.FOCUS_CHANGE)) |
363 | self.assertEqual( |
364 | False, THE_FLEP.urgent, 'remove_urgency should have been called.') |
365 | |
366 | |
367 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_widgets.py' |
368 | --- ubuntuone/controlpanel/gtk/tests/test_widgets.py 2011-03-23 16:06:41 +0000 |
369 | +++ ubuntuone/controlpanel/gtk/tests/test_widgets.py 2011-04-12 16:04:35 +0000 |
370 | @@ -148,6 +148,10 @@ |
371 | actual = widget.loading.spinner.style.fg[widgets.gtk.STATE_NORMAL] |
372 | self.assertEqual(actual, widgets.gtk.gdk.Color(expected)) |
373 | |
374 | + def test_selectable(self): |
375 | + """The widget is selectable.""" |
376 | + self.assertTrue(self.widget.label.get_selectable()) |
377 | + |
378 | |
379 | class PanelTitleTestCase(TestCase): |
380 | """Tets case for a special title for each management panel.""" |
381 | @@ -186,3 +190,7 @@ |
382 | """The label padding is correct.""" |
383 | self.assertEqual(self.widget.get_padding(), |
384 | widgets.DEFAULT_PADDING) |
385 | + |
386 | + def test_selectable(self): |
387 | + """The widget is selectable.""" |
388 | + self.assertTrue(self.widget.get_selectable()) |
389 | |
390 | === modified file 'ubuntuone/controlpanel/gtk/widgets.py' |
391 | --- ubuntuone/controlpanel/gtk/widgets.py 2011-03-23 16:06:41 +0000 |
392 | +++ ubuntuone/controlpanel/gtk/widgets.py 2011-04-12 16:04:35 +0000 |
393 | @@ -55,6 +55,7 @@ |
394 | self.loading = Loading(loading_label, fg_color=fg_color) |
395 | |
396 | self.label = gtk.Label() |
397 | + self.label.set_selectable(True) |
398 | self.label.show() |
399 | if fg_color is not None: |
400 | self.label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.Color(fg_color)) |
401 | @@ -113,6 +114,7 @@ |
402 | self.set_property('xalign', 0.0) |
403 | self.set_line_wrap(True) |
404 | self.set_line_wrap_mode(pango.WRAP_WORD) |
405 | + self.set_selectable(True) |
406 | self.show_all() |
407 | |
408 | |
409 | |
410 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' |
411 | --- ubuntuone/controlpanel/tests/test_backend.py 2011-04-08 16:07:22 +0000 |
412 | +++ ubuntuone/controlpanel/tests/test_backend.py 2011-04-12 16:04:35 +0000 |
413 | @@ -24,7 +24,7 @@ |
414 | import simplejson |
415 | |
416 | from twisted.internet import defer |
417 | -from twisted.internet.defer import inlineCallbacks |
418 | +from twisted.internet.defer import inlineCallbacks, returnValue |
419 | from ubuntuone.devtools.handlers import MementoHandler |
420 | |
421 | from ubuntuone.controlpanel import backend, replication_client |
422 | @@ -98,6 +98,8 @@ |
423 | subscribed_folders = [] |
424 | subscribed_shares = [] |
425 | actions = [] |
426 | + shares = [] |
427 | + folders = [] |
428 | |
429 | def get_credentials(self): |
430 | """Return the mock credentials.""" |
431 | @@ -179,7 +181,7 @@ |
432 | |
433 | def get_folders(self): |
434 | """Grab list of folders.""" |
435 | - return SAMPLE_FOLDERS |
436 | + return MockDBusClient.folders |
437 | |
438 | def subscribe_folder(self, volume_id): |
439 | """Subcribe to 'volume_id'.""" |
440 | @@ -191,7 +193,7 @@ |
441 | |
442 | def get_shares(self): |
443 | """Grab list of shares.""" |
444 | - return SAMPLE_SHARES |
445 | + return MockDBusClient.shares |
446 | |
447 | def subscribe_share(self, volume_id): |
448 | """Subcribe to 'volume_id'.""" |
449 | @@ -563,10 +565,14 @@ |
450 | self.be.wc.results[QUOTA_API] = SAMPLE_QUOTA_JSON |
451 | |
452 | @inlineCallbacks |
453 | - def test_volumes_info(self): |
454 | - """The volumes_info method exercises its callback.""" |
455 | - result = yield self.be.account_info() |
456 | - free_bytes = int(result['quota_total']) - int(result['quota_used']) |
457 | + def expected_volumes(self, sample_shares, sample_folders): |
458 | + """Get shares and group by sharing user, get folders and free space.""" |
459 | + try: |
460 | + result = yield self.be.account_info() |
461 | + except Exception: # pylint: disable=W0703 |
462 | + free_bytes = self.be.FREE_BYTES_NOT_AVAILABLE |
463 | + else: |
464 | + free_bytes = int(result['quota_total']) - int(result['quota_used']) |
465 | |
466 | # get root dir info |
467 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, |
468 | @@ -574,7 +580,7 @@ |
469 | |
470 | # get shares and group by sharing user |
471 | shares = defaultdict(list) |
472 | - for share in SAMPLE_SHARES: |
473 | + for share in sample_shares: |
474 | # filter out non accepted values |
475 | if not bool(share['accepted']): |
476 | continue |
477 | @@ -593,15 +599,29 @@ |
478 | shares[username].append(share) |
479 | |
480 | folders = [] |
481 | - for folder in SAMPLE_FOLDERS: |
482 | + for folder in sample_folders: |
483 | folder = folder.copy() |
484 | folder[u'type'] = self.be.FOLDER_TYPE |
485 | folders.append(folder) |
486 | |
487 | expected = [(u'', unicode(free_bytes), [root_volume] + folders)] |
488 | for other_user, data in shares.iteritems(): |
489 | - expected.append((other_user, data[0][u'free_bytes'], data)) |
490 | - |
491 | + send_freebytes = any(d['access_level'] == 'Modify' for d in data) |
492 | + if send_freebytes: |
493 | + free_bytes = data[0][u'free_bytes'] |
494 | + else: |
495 | + free_bytes = self.be.FREE_BYTES_NOT_AVAILABLE |
496 | + expected.append((other_user, free_bytes, data)) |
497 | + |
498 | + returnValue(expected) |
499 | + |
500 | + @inlineCallbacks |
501 | + def test_volumes_info(self): |
502 | + """The volumes_info method exercises its callback.""" |
503 | + self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) |
504 | + self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) |
505 | + |
506 | + expected = yield self.expected_volumes(SAMPLE_SHARES, SAMPLE_FOLDERS) |
507 | result = yield self.be.volumes_info() |
508 | self.assertEqual(result, expected) |
509 | |
510 | @@ -614,14 +634,23 @@ |
511 | @inlineCallbacks |
512 | def test_volumes_are_cached(self): |
513 | """The volume list is cached.""" |
514 | + self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) |
515 | + self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) |
516 | + |
517 | # get root dir info |
518 | root_volume = {u'volume_id': u'', u'path': ROOT_PATH, |
519 | u'subscribed': 'True', u'type': self.be.ROOT_TYPE} |
520 | expected = {u'': root_volume} |
521 | for volume in SAMPLE_SHARES + SAMPLE_FOLDERS: |
522 | + volume = volume.copy() |
523 | if volume[u'type'] == u'UDF': |
524 | volume[u'type'] = self.be.FOLDER_TYPE |
525 | else: |
526 | + if not bool(volume[u'accepted']): |
527 | + continue |
528 | + path = volume[u'path'] |
529 | + nicer_path = path.replace(SHARES_PATH, SHARES_PATH_LINK) |
530 | + volume[u'path'] = nicer_path |
531 | volume[u'type'] = self.be.SHARE_TYPE |
532 | |
533 | sid = volume['volume_id'] |
534 | @@ -639,6 +668,56 @@ |
535 | yield self.test_volumes_are_cached() |
536 | |
537 | @inlineCallbacks |
538 | + def test_volumes_info_no_quota_for_read_onlys(self): |
539 | + """The volumes_info does not send qupota info for RO shares.""" |
540 | + read_only_shares = [ |
541 | + {u'accepted': u'True', |
542 | + u'subscribed': u'True', |
543 | + u'access_level': u'View', |
544 | + u'free_bytes': u'39892622746', |
545 | + u'generation': u'2704', |
546 | + u'name': u're', |
547 | + u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', |
548 | + u'other_username': u'otheruser', |
549 | + u'other_visible_name': u'Other User', |
550 | + u'path': SHARES_PATH + u'/re from Other User', |
551 | + u'type': u'Share', |
552 | + u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, |
553 | + {u'accepted': u'True', |
554 | + u'subscribed': u'True', |
555 | + u'access_level': u'View', |
556 | + u'free_bytes': u'39892622746', |
557 | + u'generation': u'2704', |
558 | + u'name': u'do', |
559 | + u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', |
560 | + u'other_username': u'otheruser', |
561 | + u'other_visible_name': u'Other User', |
562 | + u'path': SHARES_PATH + u'/do from Other User', |
563 | + u'type': u'Share', |
564 | + u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, |
565 | + ] |
566 | + |
567 | + self.patch(MockDBusClient, 'shares', read_only_shares) |
568 | + self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) |
569 | + |
570 | + expected = yield self.expected_volumes(read_only_shares, |
571 | + SAMPLE_FOLDERS) |
572 | + result = yield self.be.volumes_info() |
573 | + self.assertEqual(result, expected) |
574 | + |
575 | + @inlineCallbacks |
576 | + def test_volumes_info_no_quota_for_root(self): |
577 | + """The volumes_info returns info even if quota call fails.""" |
578 | + # pylint: disable=E1101 |
579 | + self.be.wc.failure = 500 |
580 | + self.patch(MockDBusClient, 'shares', SAMPLE_SHARES) |
581 | + self.patch(MockDBusClient, 'folders', SAMPLE_FOLDERS) |
582 | + |
583 | + expected = yield self.expected_volumes(SAMPLE_SHARES, SAMPLE_FOLDERS) |
584 | + result = yield self.be.volumes_info() |
585 | + self.assertEqual(result, expected) |
586 | + |
587 | + @inlineCallbacks |
588 | def test_subscribe_volume_folder(self): |
589 | """The subscribe_volume method subscribes a folder.""" |
590 | fid = '0123-4567' |