Merge lp:~ralsina/ubuntuone-windows-installer/local-folder-fixes into lp:ubuntuone-windows-installer
- local-folder-fixes
- Merge into trunk
Proposed by
Roberto Alsina
Status: | Superseded | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~ralsina/ubuntuone-windows-installer/local-folder-fixes | ||||
Merge into: | lp:ubuntuone-windows-installer | ||||
Diff against target: |
657 lines (+356/-98) 3 files modified
data/qt/local_folders.ui (+1/-8) ubuntuone_installer/gui/qt/local_folders.py (+142/-57) ubuntuone_installer/gui/qt/tests/test_gui.py (+213/-33) |
||||
To merge this branch: | bzr merge lp:~ralsina/ubuntuone-windows-installer/local-folder-fixes | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One hackers | Pending | ||
Review via email:
|
Commit message
Implement the "Computer-to-cloud" page of the installer according to spec and discussions.
Description of the change
Implement the "Computer-to-cloud" page of the installer according to spec and discussions.
To post a comment you must log in.
- 47. By Roberto Alsina
-
merged
- 48. By Roberto Alsina
-
added tests for pre/post initializePage
- 49. By Roberto Alsina
-
more tests, lint fixes
- 50. By Roberto Alsina
-
added tests for FolderItem
- 51. By Roberto Alsina
-
added tests for FolderItem
- 52. By Roberto Alsina
-
fixes
- 53. By Roberto Alsina
-
added test for special_folders
- 54. By Roberto Alsina
-
merged trunk
- 55. By Roberto Alsina
-
fixes
- 56. By Roberto Alsina
-
add test for 'no folder selected, no quota used'
- 57. By Roberto Alsina
-
suggested fix for the while True
- 58. By Roberto Alsina
-
Separate tests for local folders
- 59. By Roberto Alsina
-
style fixes
- 60. By Roberto Alsina
-
added two suggested tests
- 61. By Roberto Alsina
-
lint
- 62. By Roberto Alsina
-
solve conflict
- 63. By Roberto Alsina
-
merge conflict fix
- 64. By Roberto Alsina
-
grmbl
- 65. By Roberto Alsina
-
resolve further
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/qt/local_folders.ui' |
2 | --- data/qt/local_folders.ui 2011-08-08 21:48:11 +0000 |
3 | +++ data/qt/local_folders.ui 2011-08-17 00:58:24 +0000 |
4 | @@ -97,7 +97,7 @@ |
5 | </spacer> |
6 | </item> |
7 | <item> |
8 | - <widget class="AddFolderButton" name="add_folder_button"> |
9 | + <widget class="QPushButton" name="add_folder_button"> |
10 | <property name="text"> |
11 | <string>Add a folder from this computer</string> |
12 | </property> |
13 | @@ -188,13 +188,6 @@ |
14 | </item> |
15 | </layout> |
16 | </widget> |
17 | - <customwidgets> |
18 | - <customwidget> |
19 | - <class>AddFolderButton</class> |
20 | - <extends>QPushButton</extends> |
21 | - <header>ubuntuone.controlpanel.gui.qt.addfolder</header> |
22 | - </customwidget> |
23 | - </customwidgets> |
24 | <resources/> |
25 | <connections/> |
26 | </ui> |
27 | |
28 | === modified file 'ubuntuone_installer/gui/qt/local_folders.py' |
29 | --- ubuntuone_installer/gui/qt/local_folders.py 2011-08-17 00:58:24 +0000 |
30 | +++ ubuntuone_installer/gui/qt/local_folders.py 2011-08-17 00:58:24 +0000 |
31 | @@ -24,9 +24,14 @@ |
32 | import threading |
33 | import Queue |
34 | |
35 | -from twisted.internet.defer import inlineCallbacks |
36 | +from twisted.internet.defer import inlineCallbacks, returnValue |
37 | from PyQt4 import QtCore, QtGui |
38 | -from ubuntuone.controlpanel.gui import humanize, sign_url |
39 | +from ubuntuone.controlpanel import backend |
40 | +from ubuntuone.controlpanel.gui import ( |
41 | + humanize, |
42 | + sign_url, |
43 | + FOLDER_INVALID_PATH |
44 | +) |
45 | from ubuntuone.platform.credentials import CredentialsManagementTool |
46 | from ubuntu_sso.qt.gui import SSOWizardPage |
47 | |
48 | @@ -49,12 +54,19 @@ |
49 | |
50 | class FolderItem(QtGui.QTreeWidgetItem): |
51 | """Class representing a folder in the folder list UI.""" |
52 | - def __init__(self, strings, path=None, queue=None): |
53 | + def __init__(self, strings, path=None, queue=None, |
54 | + calculate=True, volume_id=None): |
55 | super(FolderItem, self).__init__(strings) |
56 | - self.thread = CalculateSize(path, queue) |
57 | - self.thread.start() |
58 | - self.size = None |
59 | + if calculate: |
60 | + self.thread = CalculateSize(path, queue) |
61 | + self.thread.start() |
62 | + self.size = None |
63 | + else: |
64 | + self.thread = CalculateSize(path, queue) |
65 | + self.size = 0 |
66 | self.path = path |
67 | + self.setCheckState(0, QtCore.Qt.Unchecked) |
68 | + self.volume_id = volume_id |
69 | |
70 | |
71 | class CalculateSize(threading.Thread): |
72 | @@ -88,6 +100,9 @@ |
73 | self.queue = Queue.Queue() |
74 | self.timer = QtCore.QTimer() |
75 | self.items = {} |
76 | + self.folders_info = None |
77 | + self.account_info = None |
78 | + self.cp_backend = backend.ControlBackend() |
79 | |
80 | # initializePage is inherited |
81 | # pylint: disable=C0103 |
82 | @@ -99,16 +114,72 @@ |
83 | self.wizard()._next_id = self.wizard().SYNC_NOW_OR_LATER_PAGE |
84 | # Start with this invisible |
85 | self.ui.offer_frame.setVisible(False) |
86 | - if not self.ui.folder_list.topLevelItemCount(): |
87 | + # Block until we have server data |
88 | + self.wizard().overlay.show() |
89 | + self.get_info() |
90 | + |
91 | + @inlineCallbacks |
92 | + def get_info(self): |
93 | + """Get information from CP backend and fill folder list.""" |
94 | + try: |
95 | + volumes_info = yield self.cp_backend.volumes_info() |
96 | + self.account_info = yield self.cp_backend.account_info() |
97 | + self.folders_info = [] |
98 | + for _, _, volumes in volumes_info: |
99 | + for volume in volumes: |
100 | + if volume[u'type'] == u"UDF": |
101 | + self.folders_info.append(volume) |
102 | + self.ui.folder_list.clear() |
103 | + for folder in self.folders_info: |
104 | + item = yield self.add_folder( |
105 | + os.path.expanduser(folder['path']), |
106 | + validate=False, volume_id=folder['volume_id']) |
107 | + if item: |
108 | + if folder['subscribed']: |
109 | + item.setCheckState(0, QtCore.Qt.Checked) |
110 | + item.thread.join() |
111 | + item.size = 0 |
112 | for folder_name in self.default_folders(): |
113 | - self.add_folder(folder_name) |
114 | - self.timer.start(2000) |
115 | - self.timer.timeout.connect(self.update_sizes) |
116 | + item = yield self.add_folder(folder_name, validate=True) |
117 | + self.timer.start(2000) |
118 | + self.timer.timeout.connect(self.update_sizes) |
119 | + self.wizard().overlay.hide() |
120 | + self.wizard().currentIdChanged.connect(self.changed_page) |
121 | + except: |
122 | + logger.exception("Error getting backend info:") |
123 | + |
124 | + @QtCore.pyqtSlot("int") |
125 | + @inlineCallbacks |
126 | + def changed_page(self, page_id): |
127 | + """When moving to next page, create/[un]subscribe UDFs.""" |
128 | + self.timer.stop() |
129 | + try: |
130 | + self.wizard().currentIdChanged.disconnect(self.changed_page) |
131 | + except KeyError: |
132 | + pass |
133 | + if page_id == self.wizard().SYNC_NOW_OR_LATER_PAGE: |
134 | + # The page following this one |
135 | + self.wizard().overlay.show() |
136 | + for path, item in self.items.items(): |
137 | + if item.checkState(0) == QtCore.Qt.Checked: |
138 | + if item.volume_id: |
139 | + yield self.cp_backend.change_volume_settings( |
140 | + item.volume_id, |
141 | + dict(subscribed=True)) |
142 | + else: |
143 | + yield self.cp_backend.create_folder(path) |
144 | + else: |
145 | + if item.volume_id: |
146 | + yield self.cp_backend.change_volume_settings( |
147 | + item.volume_id, |
148 | + dict(subscribed=False)) |
149 | + self.wizard().overlay.hide() |
150 | |
151 | def default_folders(self): |
152 | """Return a list of the folders to add by default.""" |
153 | if sys.platform == 'win32': |
154 | - # Special Folder "My Documents" |
155 | + # XXXX to be replaced by calls to xdg_base_directory's |
156 | + # special_folders |
157 | dll = ctypes.windll.shell32 |
158 | buf = ctypes.create_string_buffer(300) |
159 | dll.SHGetSpecialFolderPathA(None, buf, 5, False) |
160 | @@ -122,61 +193,62 @@ |
161 | result = ['To be implemented'] |
162 | return result |
163 | |
164 | - def add_folder(self, path): |
165 | + @inlineCallbacks |
166 | + def add_folder(self, path, validate=True, volume_id=False): |
167 | """Add a folder to the list.""" |
168 | if path in self.items: |
169 | - return None |
170 | - # FIXME: the path should actually be sent to u1cp to verify as valid |
171 | - item = FolderItem([path, "", "remove"], path=path, queue=self.queue) |
172 | - self.ui.folder_list.addTopLevelItem(item) |
173 | - self.items[path] = item |
174 | - return item |
175 | + returnValue(None) |
176 | + if validate: |
177 | + is_valid = yield self.cp_backend.validate_path_for_folder(path) |
178 | + else: |
179 | + is_valid = True |
180 | + if is_valid: |
181 | + item = FolderItem([path, ""], |
182 | + path=path, queue=self.queue, volume_id=volume_id) |
183 | + self.ui.folder_list.addTopLevelItem(item) |
184 | + self.items[path] = item |
185 | + returnValue(item) |
186 | + returnValue(None) |
187 | |
188 | - @inlineCallbacks |
189 | def update_sizes(self): |
190 | """Poll the queue were the threads put the size info.""" |
191 | try: |
192 | - path, size = self.queue.get(False) |
193 | - item = self.items.get(path) |
194 | - if item: |
195 | - item.size = size |
196 | - item.setText(1, humanize(size)) |
197 | + while True: |
198 | + path, size = self.queue.get(False) |
199 | + item = self.items.get(path) |
200 | + if item: |
201 | + item.size = size |
202 | + try: |
203 | + item.setText(1, humanize(size)) |
204 | + except RuntimeError: |
205 | + del self.items[path] |
206 | except Queue.Empty: |
207 | pass |
208 | - total = 0 |
209 | + total = long(self.account_info['quota_used']) |
210 | for path, item in self.items.items(): |
211 | if item.size is None: |
212 | total = LOCAL_FOLDERS_CALCULATING |
213 | break |
214 | - total += item.size |
215 | - |
216 | + if not item.volume_id and item.checkState(0) == QtCore.Qt.Checked: |
217 | + # Existing UDFs are already accounted for, count if marked. |
218 | + total += item.size |
219 | if isinstance(total, long): |
220 | - yield self.show_hide_offer(total) |
221 | + self.show_hide_offer(total) |
222 | total = humanize(total) |
223 | else: |
224 | - yield self.show_hide_offer(0) |
225 | + self.show_hide_offer(0) |
226 | self.ui.folder_list.headerItem().setText( |
227 | 1, LOCAL_FOLDERS_SPACE_HEADER % total) |
228 | |
229 | - @inlineCallbacks |
230 | def show_hide_offer(self, cur_size): |
231 | - """Show or hide the offer to buy space according to the total size. |
232 | - |
233 | - Returns a deferred that is triggered when the update is finished. |
234 | - |
235 | - """ |
236 | - # pylint: disable=W0702 |
237 | - try: |
238 | - user_info = yield self.ui.add_folder_button.backend.account_info() |
239 | - quota = user_info['quota_total'] |
240 | - if cur_size > quota: |
241 | - self.ui.offer_frame.setVisible(True) |
242 | - else: |
243 | - self.ui.offer_frame.setVisible(False) |
244 | - self.ui.offer_label.setText(LOCAL_FOLDERS_OFFER_LABEL % |
245 | - {"quota": humanize(quota)}) |
246 | - except: |
247 | - logger.exception('Error while trying to update the quota:') |
248 | + """Show or hide the offer to buy space according to the total size.""" |
249 | + quota = self.account_info['quota_total'] |
250 | + if cur_size > quota: |
251 | + self.ui.offer_frame.setVisible(True) |
252 | + else: |
253 | + self.ui.offer_frame.setVisible(False) |
254 | + self.ui.offer_label.setText(LOCAL_FOLDERS_OFFER_LABEL % |
255 | + {"quota": humanize(quota)}) |
256 | |
257 | def stop_threads(self): |
258 | """Stop all pending threads.""" |
259 | @@ -185,31 +257,44 @@ |
260 | |
261 | # itemClicked is a Qt signal name. |
262 | # pylint: disable=C0103 |
263 | - def on_folder_list_itemClicked(self, item, column): |
264 | + def on_folder_list_itemChanged(self, item, column): |
265 | """Delete folder from the list.""" |
266 | - if column == 2: |
267 | - del(self.items[item.path]) |
268 | - item.thread._stop = True |
269 | - self.ui.folder_list.takeTopLevelItem( |
270 | - self.ui.folder_list.indexOfTopLevelItem(item)) |
271 | - self.update_sizes() |
272 | + if column == 0: |
273 | + self.update_sizes() |
274 | |
275 | @inlineCallbacks |
276 | @QtCore.pyqtSlot() |
277 | def on_add_storage_button_clicked(self): |
278 | """user clicked on the "Add more storage" button.""" |
279 | - |
280 | + # Really want to catch everything |
281 | # pylint: disable=W0702 |
282 | try: |
283 | credtool = CredentialsManagementTool() |
284 | creds = yield credtool.find_credentials() |
285 | except: |
286 | - logger.exception('Error while trying to update que quota:') |
287 | + logger.exception('Error while trying to get credentials:') |
288 | creds = {} |
289 | - |
290 | if creds: |
291 | signed_url = sign_url( |
292 | "https://one.ubuntu.com/services/#storage_panel", creds) |
293 | else: |
294 | signed_url = "https://one.ubuntu.com/services/#storage_panel" |
295 | QtGui.QDesktopServices.openUrl(QtCore.QUrl(signed_url)) |
296 | + |
297 | + @inlineCallbacks |
298 | + @QtCore.pyqtSlot() |
299 | + def on_add_folder_button_clicked(self): |
300 | + """user clicked on the "Add Folder" button.""" |
301 | + folder = QtGui.QFileDialog.getExistingDirectory(parent=self) |
302 | + folder = unicode(folder) |
303 | + if folder == '': |
304 | + return |
305 | + |
306 | + is_valid = yield self.cp_backend.validate_path_for_folder(folder) |
307 | + if not is_valid: |
308 | + user_home = os.path.expanduser('~') |
309 | + text = FOLDER_INVALID_PATH % {'folder_path': folder, |
310 | + 'home_folder': user_home} |
311 | + QtGui.QMessageBox.warning(self, '', text, QtGui.QMessageBox.Close) |
312 | + return |
313 | + yield self.add_folder(folder, validate=False, volume_id=False) |
314 | |
315 | === modified file 'ubuntuone_installer/gui/qt/tests/test_gui.py' |
316 | --- ubuntuone_installer/gui/qt/tests/test_gui.py 2011-08-17 00:58:24 +0000 |
317 | +++ ubuntuone_installer/gui/qt/tests/test_gui.py 2011-08-17 00:58:24 +0000 |
318 | @@ -529,15 +529,20 @@ |
319 | |
320 | def __init__(self, *args, **kwargs): |
321 | """Initialize.""" |
322 | - self.target = lambda *args: None |
323 | + self.target = None |
324 | |
325 | def connect(self, target): |
326 | """Fake connect.""" |
327 | self.target = target |
328 | |
329 | + def disconnect(self, *args): |
330 | + """Fake disconnect.""" |
331 | + self.target = None |
332 | + |
333 | def emit(self, *args): |
334 | """Fake emit.""" |
335 | - self.target(*args) |
336 | + if self.target: |
337 | + self.target(*args) |
338 | |
339 | |
340 | class FakeMainWindow(object): |
341 | @@ -548,7 +553,10 @@ |
342 | registrationSuccess = FakeSignal() |
343 | userCancellation = FakeSignal() |
344 | shown = False |
345 | + _buttonlayout = None |
346 | SYNC_NOW_OR_LATER_PAGE = 4 |
347 | + overlay = FakeOverlay() |
348 | + currentIdChanged = FakeSignal() |
349 | |
350 | def show(self): |
351 | """Fake method.""" |
352 | @@ -563,9 +571,71 @@ |
353 | class FakeCPBackend(object): |
354 | """Fake Control Panel backend.""" |
355 | |
356 | + def __init__(self): |
357 | + """Initialize.""" |
358 | + self._is_valid = True |
359 | + self.volume_setings_changes = [] |
360 | + self.folders_created = [] |
361 | + |
362 | def account_info(self, *args): |
363 | """Fake account info.""" |
364 | - return defer.succeed({"quota_total": 1000}) |
365 | + return defer.succeed({ |
366 | + "quota_total": 1000, |
367 | + "quota_used": 200, |
368 | + }) |
369 | + |
370 | + def volumes_info(self, *args): |
371 | + """"Fake volumes info.""" |
372 | + return defer.succeed(((None, None, |
373 | + [ |
374 | + { |
375 | + 'type': u'UDF', |
376 | + 'path': os.path.expanduser(u'~/xyzzy'), |
377 | + 'volume_id': 'asdfgh', |
378 | + 'subscribed': True |
379 | + }, |
380 | + { |
381 | + 'type': u'UDF', |
382 | + 'path': os.path.expanduser(u'~/zxyzzy'), |
383 | + 'volume_id': 'qwerty', |
384 | + 'subscribed': False |
385 | + }, |
386 | + ], |
387 | + ),)) |
388 | + |
389 | + def validate_path_for_folder(self, path): |
390 | + """Fake folder validation.""" |
391 | + return self._is_valid |
392 | + |
393 | + def change_volume_settings(self, *args): |
394 | + """Fake change volume settings.""" |
395 | + self.volume_setings_changes.append(args) |
396 | + |
397 | + def create_folder(self, *args): |
398 | + """Fake folder creation.""" |
399 | + self.folders_created.append(args) |
400 | + |
401 | + |
402 | +class FakeFileDialog(object): |
403 | + |
404 | + """A fake QFileDialog class.""" |
405 | + |
406 | + # pylint: disable=C0103 |
407 | + def getExistingDirectory(self, *args, **kwargs): |
408 | + """Fake existing folder name.""" |
409 | + return u"whatever" |
410 | + |
411 | + |
412 | +class FakeMessageBox(object): |
413 | + |
414 | + """A fake QMessageBox class.""" |
415 | + |
416 | + Close = 2 |
417 | + _warning = None |
418 | + |
419 | + def warning(self, *args, **kwargs): |
420 | + """Fake warning.""" |
421 | + self._warning = (args, kwargs) |
422 | |
423 | |
424 | class FakeFailingCPBackend(object): |
425 | @@ -598,6 +668,7 @@ |
426 | f.write(" " * 737) |
427 | f.close() |
428 | self.fake_wizard = FakeMainWindow() |
429 | + self.patch(local_folders.backend, "ControlBackend", FakeCPBackend) |
430 | super(LocalFoldersTestCase, self).setUp() |
431 | self.patch(self.ui, "wizard", lambda: self.fake_wizard) |
432 | |
433 | @@ -606,6 +677,24 @@ |
434 | shutil.rmtree(self.tmpdir) |
435 | BaseTestCase.tearDown(self) |
436 | |
437 | + @defer.inlineCallbacks |
438 | + def test_subscribed_udf_checked(self): |
439 | + """Check that subscribed UDF items are created correctly.""" |
440 | + yield self.ui.get_info() |
441 | + item = self.ui.items[os.path.expanduser(u'~/xyzzy')] |
442 | + self.assertEqual(item.checkState(0), QtCore.Qt.Checked) |
443 | + self.assertEqual(item.size, 0) |
444 | + self.assertTrue(item.volume_id) |
445 | + |
446 | + @defer.inlineCallbacks |
447 | + def test_unsubscribed_udf_checked(self): |
448 | + """Check that unsubscribed UDF items are created correctly.""" |
449 | + yield self.ui.get_info() |
450 | + item = self.ui.items[os.path.expanduser(u'~/zxyzzy')] |
451 | + self.assertEqual(item.checkState(0), QtCore.Qt.Unchecked) |
452 | + self.assertEqual(item.size, 0) |
453 | + self.assertTrue(item.volume_id) |
454 | + |
455 | def test_size_calculation(self): |
456 | """Test the recursive folder size calculation.""" |
457 | queue = Queue.Queue() |
458 | @@ -615,38 +704,77 @@ |
459 | self.assertEqual(path, self.tmpdir) |
460 | self.assertEqual(size, 1337) |
461 | |
462 | + @defer.inlineCallbacks |
463 | def test_item_addition(self): |
464 | - """Add an item (plus the default one), then remove them.""" |
465 | - self.ui.add_folder(self.tmpdir) |
466 | - self.assertEqual(4, self.ui.ui.folder_list.topLevelItemCount()) |
467 | - |
468 | + """Add a folder.""" |
469 | + self.ui.ui.folder_list.clear() |
470 | + yield self.ui.add_folder(self.tmpdir) |
471 | + self.assertEqual(1, self.ui.ui.folder_list.topLevelItemCount()) |
472 | + |
473 | + @defer.inlineCallbacks |
474 | + def test_invalid_item_addition(self): |
475 | + """Try to add an invalid folder.""" |
476 | + self.ui.ui.folder_list.clear() |
477 | + self.ui.cp_backend._is_valid = False |
478 | + yield self.ui.add_folder(self.tmpdir) |
479 | + self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount()) |
480 | + |
481 | + @defer.inlineCallbacks |
482 | def test_total_size(self): |
483 | """Test that the header reflects the change in item sizes.""" |
484 | - while self.ui.ui.folder_list.topLevelItemCount(): |
485 | - self.ui.on_folder_list_itemClicked( |
486 | - self.ui.ui.folder_list.topLevelItem(0), 2) |
487 | - self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount()) |
488 | - item = self.ui.add_folder(self.tmpdir) |
489 | - item.size = 1337 |
490 | - item.thread.run() |
491 | - item.thread.join() |
492 | - self.ui.update_sizes() |
493 | - self.assertEqual(unicode(self.ui.ui.folder_list.headerItem().text(1)), |
494 | - u"Space (1337)") |
495 | + yield self.ui.get_info() |
496 | + self.ui.ui.folder_list.clear() |
497 | + self.ui.items = {} |
498 | + item = yield self.ui.add_folder(self.tmpdir) |
499 | + item.thread.run() |
500 | + item.thread.join() |
501 | + item.size = 1337 |
502 | + item.setCheckState(0, QtCore.Qt.Checked) |
503 | + self.ui.update_sizes() |
504 | + self.assertEqual(unicode(self.ui.ui.folder_list.headerItem().text(1)), |
505 | + u"Space (1.5 KiB)") |
506 | + |
507 | + @defer.inlineCallbacks |
508 | + def test_total_size_unchecked(self): |
509 | + """Unchecked items use no space beyond quota_used.""" |
510 | + yield self.ui.get_info() |
511 | + self.ui.ui.folder_list.clear() |
512 | + self.ui.items = {} |
513 | + item = yield self.ui.add_folder(self.tmpdir) |
514 | + item.thread.run() |
515 | + item.thread.join() |
516 | + item.size = 1337 |
517 | + item.setCheckState(0, QtCore.Qt.Unchecked) |
518 | + self.ui.update_sizes() |
519 | + self.assertEqual(unicode(self.ui.ui.folder_list.headerItem().text(1)), |
520 | + u"Space (200 bytes)") |
521 | + |
522 | + @defer.inlineCallbacks |
523 | + def test_total_size_udf(self): |
524 | + """UDFs use no space beyond quota_used.""" |
525 | + yield self.ui.get_info() |
526 | + for _, item in self.ui.items.items(): |
527 | + item.thread.join() |
528 | + if item.volume_id: |
529 | + item.setCheckState(0, QtCore.Qt.Checked) |
530 | + else: |
531 | + item.setCheckState(0, QtCore.Qt.Unchecked) |
532 | + self.ui.update_sizes() |
533 | + self.assertEqual(unicode(self.ui.ui.folder_list.headerItem().text(1)), |
534 | + u"Space (200 bytes)") |
535 | |
536 | def test_add_twice(self): |
537 | """Behaviour for adding the same folder twice: |
538 | |
539 | * It's added only once. |
540 | """ |
541 | - while self.ui.ui.folder_list.topLevelItemCount(): |
542 | - self.ui.on_folder_list_itemClicked( |
543 | - self.ui.ui.folder_list.topLevelItem(0), 2) |
544 | + self.ui.ui.folder_list.clear() |
545 | self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount()) |
546 | self.ui.add_folder(self.tmpdir) |
547 | self.ui.add_folder(self.tmpdir) |
548 | self.assertEqual(1, self.ui.ui.folder_list.topLevelItemCount()) |
549 | |
550 | + @defer.inlineCallbacks |
551 | def test_add_missing_folder(self): |
552 | """Behaviour for adding a folder that doesn't exist: |
553 | |
554 | @@ -654,11 +782,11 @@ |
555 | * Has size 0. |
556 | """ |
557 | |
558 | - while self.ui.ui.folder_list.topLevelItemCount(): |
559 | - self.ui.on_folder_list_itemClicked( |
560 | - self.ui.ui.folder_list.topLevelItem(0), 2) |
561 | + yield self.ui.get_info() |
562 | + self.ui.ui.folder_list.clear() |
563 | self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount()) |
564 | - item = self.ui.add_folder(os.path.join("xyzzy", "xyzzy", "xyzzy")) |
565 | + item = yield self.ui.add_folder(os.path.join( |
566 | + "xyzzy", "xyzzy", "xyzzy")) |
567 | self.assertEqual(1, self.ui.ui.folder_list.topLevelItemCount()) |
568 | item.thread.run() |
569 | item.thread.join() |
570 | @@ -672,27 +800,79 @@ |
571 | Push the user over quota, it should be visible. |
572 | """ |
573 | self.patch(self.ui.ui.offer_frame, "setVisible", self._set_called) |
574 | - while self.ui.ui.folder_list.topLevelItemCount(): |
575 | - self.ui.on_folder_list_itemClicked( |
576 | - self.ui.ui.folder_list.topLevelItem(0), 2) |
577 | - self.assertEqual(0, self.ui.ui.folder_list.topLevelItemCount()) |
578 | + yield self.ui.get_info() |
579 | + self.ui.ui.folder_list.clear() |
580 | self.ui.update_sizes() |
581 | self.assertEqual(self._called, ((False,), {})) |
582 | self.ui.show_hide_offer(self.ui.quota() + 1) |
583 | self.assertEqual(self._called, ((True,), {})) |
584 | |
585 | + def test_add_folder_valid(self): |
586 | + """Test behaviour when adding a valid folder via the button.""" |
587 | + self.patch(QtGui, "QFileDialog", FakeFileDialog()) |
588 | + self.patch(self.ui, "add_folder", self._set_called) |
589 | + self.ui.ui.add_folder_button.click() |
590 | + self.assertEqual(self._called, |
591 | + ((u'whatever',), {'validate': False, 'volume_id': False})) |
592 | + |
593 | + def test_add_folder_invalid(self): |
594 | + """Test behaviour when adding an invalid folder via the button.""" |
595 | + self.patch(QtGui, "QFileDialog", FakeFileDialog()) |
596 | + message_box = FakeMessageBox() |
597 | + self.patch(QtGui, "QMessageBox", message_box) |
598 | + self.patch(self.ui, "add_folder", self._set_called) |
599 | + self.ui.cp_backend._is_valid = False |
600 | + self.ui.ui.add_folder_button.click() |
601 | + self.assertEqual(self._called, False) |
602 | + user_home = os.path.expanduser('~') |
603 | + text = local_folders.FOLDER_INVALID_PATH % { |
604 | + 'folder_path': "whatever", |
605 | + 'home_folder': user_home, |
606 | + } |
607 | + self.assertEqual(message_box._warning, |
608 | + ((self.ui, |
609 | + '', text, 2), {})) |
610 | + |
611 | + @defer.inlineCallbacks |
612 | + def test_changed_page_existing_udf_behaviour(self): |
613 | + """If a UDF is checked, subscribe it, if not, unsubscribe it.""" |
614 | + yield self.ui.get_info() |
615 | + self.ui.changed_page(self.ui.wizard().SYNC_NOW_OR_LATER_PAGE) |
616 | + self.assertEqual(self.ui.cp_backend.volume_setings_changes, |
617 | + [('asdfgh', {'subscribed': True}), |
618 | + ('qwerty', {'subscribed': False})]) |
619 | + |
620 | + @defer.inlineCallbacks |
621 | + def test_changed_page_new_udf_behaviour(self): |
622 | + """Create UDFs for non-existing, checked UDFs.""" |
623 | + yield self.ui.get_info() |
624 | + self.ui.ui.folder_list.clear() |
625 | + self.ui.items = {} |
626 | + item = yield self.ui.add_folder("whatever") |
627 | + item.setCheckState(0, QtCore.Qt.Checked) |
628 | + item = yield self.ui.add_folder("whatever2") |
629 | + item.setCheckState(0, QtCore.Qt.Unchecked) |
630 | + self.ui.changed_page(self.ui.wizard().SYNC_NOW_OR_LATER_PAGE) |
631 | + self.assertEqual(self.ui.cp_backend.folders_created, |
632 | + [('whatever',)]) |
633 | + |
634 | def test_exception_on_account_info(self): |
635 | """When account_info fails, nothing should happen.""" |
636 | - self.patch(self.ui.ui.add_folder_button, |
637 | - "backend", FakeFailingCPBackend()) |
638 | - self.ui.show_hide_offer(1000) |
639 | + self.patch(self.ui, |
640 | + "cp_backend", FakeFailingCPBackend()) |
641 | + self.ui.get_info() |
642 | # Still here |
643 | |
644 | def test_timer_is_started(self): |
645 | - """ When displaying the page, the timer should start.""" |
646 | + """When displaying the page, the timer should start.""" |
647 | self.ui.initializePage() |
648 | self.assertTrue(self.ui.timer.isActive()) |
649 | |
650 | + def test_timer_is_stopped(self): |
651 | + """When leaving the page, the timer should stop.""" |
652 | + self.ui.changed_page(-1) |
653 | + self.assertFalse(self.ui.timer.isActive()) |
654 | + |
655 | |
656 | class SetupAccountTestCase(BaseTestCase): |
657 | """Test the SetupAccountPage code.""" |