Merge lp:~nataliabidart/ubuntuone-control-panel/update-file-sync-status into lp:ubuntuone-control-panel
- update-file-sync-status
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Natalia Bidart |
Approved revision: | 159 |
Merged at revision: | 155 |
Proposed branch: | lp:~nataliabidart/ubuntuone-control-panel/update-file-sync-status |
Merge into: | lp:ubuntuone-control-panel |
Prerequisite: | lp:~nataliabidart/ubuntuone-control-panel/use-sdtool |
Diff against target: |
1187 lines (+647/-246) 17 files modified
.bzrignore (+1/-0) data/qt/controlpanel.ui (+41/-32) data/qt/filesyncstatus.ui (+45/-0) data/qt/images.qrc (+6/-0) data/qt/mainwindow.ui (+1/-1) run-tests (+2/-1) ubuntuone/controlpanel/backend.py (+2/-0) ubuntuone/controlpanel/gui/__init__.py (+5/-0) ubuntuone/controlpanel/gui/gtk/gui.py (+8/-6) ubuntuone/controlpanel/gui/gtk/tests/__init__.py (+15/-108) ubuntuone/controlpanel/gui/qt/controlpanel.py (+6/-41) ubuntuone/controlpanel/gui/qt/filesyncstatus.py (+151/-0) ubuntuone/controlpanel/gui/qt/gui.py (+34/-0) ubuntuone/controlpanel/gui/qt/tests/__init__.py (+38/-15) ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py (+0/-42) ubuntuone/controlpanel/gui/qt/tests/test_filesyncstatus.py (+159/-0) ubuntuone/controlpanel/gui/tests/__init__.py (+133/-0) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-control-panel/update-file-sync-status |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Manuel de la Peña (community) | Approve | ||
Alejandro J. Cura (community) | Approve | ||
Shane Fagan (community) | Approve | ||
Review via email: mp+62575@code.launchpad.net |
Commit message
- File Sync status is now updated using symbols and colours, and the action button is properly updated as well.
Description of the change
To test this branch, you need to have latest nightlies installed and updated.
To run the test suites, do:
./run-tests
./run-tests -qt
To test IRL, open the QT UI with:
DEBUG=True PYTHONPATH=. ./bin/ubuntuone
and modify syncdaemon "state on the side" (u1sdtool -d on the terminal). You will see how the file sync status is updated, and how the button next to the status offers different actions according to the status. You can click on the buttons and modify syncdaemon status.
Shane Fagan (shanepatrickfagan) : | # |
Alejandro J. Cura (alecu) wrote : | # |
Running on Natty, I'm only getting the REQUEST_
Natalia Bidart (nataliabidart) wrote : | # |
Manuel,
I'm guessing you have an old version of QT? The files where you're having errors on are those generated by QT, for example:
File "/home/
We're working with code for QT 4.4 or higher, what version are you running?
Manuel de la Peña (mandel) wrote : | # |
I'm using Qt 4.7.4 I really don't understand why would that be happening, I'll take a look at the Qt state of my test vm.
Manuel de la Peña (mandel) : | # |
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
The attempt to merge lp:~nataliabidart/ubuntuone-control-panel/update-file-sync-status into lp:ubuntuone-control-panel failed. Below is the output from the failed tests.
running build
Compiled data/qt/
Compiled data/qt/
Compiled data/qt/folders.ui into ubuntuone/
Compiled data/qt/devices.ui into ubuntuone/
Compiled data/qt/
/usr/lib/
warnings.
ERROR: Python module aptdaemon.defer not found
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module qtreactor not found
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
ERROR: Python module ubuntuone.
/home/otto/
kwargs = {'main_window': gui.gtk.Window()}
/home/otto/
kwargs = {'main_window': gui.gtk.Window()}
sh: pyrcc4: not found
Traceback (most recent call last):
File "./setup.py", line 246, in <module>
'clean': ControlPanelClean,
File "/usr/lib/
distutils.
File "/usr/lib/
dist.
File "/usr/lib/
self.
File "/usr/lib/
cmd_obj.run()
File "./setup.py", line 169, in run
self.
File "./setup.py", line 119, in compile_rc
+ 'for resource file %s', py_file, qrc_file)
TypeError: warn() takes exactly 2 arguments (4 given)
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-05-24 14:20:18 +0000 |
3 | +++ .bzrignore 2011-05-31 18:28:26 +0000 |
4 | @@ -6,4 +6,5 @@ |
5 | po/ubuntuone-control-panel.pot |
6 | ubuntuone/controlpanel/constants.py |
7 | ubuntuone/controlpanel/gui/qt/ui/*_ui.py |
8 | +ubuntuone/controlpanel/gui/qt/ui/*_rc.py |
9 | qtreactor/ |
10 | \ No newline at end of file |
11 | |
12 | === modified file 'data/qt/controlpanel.ui' |
13 | --- data/qt/controlpanel.ui 2011-05-24 14:20:18 +0000 |
14 | +++ data/qt/controlpanel.ui 2011-05-31 18:28:26 +0000 |
15 | @@ -7,7 +7,7 @@ |
16 | <x>0</x> |
17 | <y>0</y> |
18 | <width>646</width> |
19 | - <height>421</height> |
20 | + <height>487</height> |
21 | </rect> |
22 | </property> |
23 | <property name="sizePolicy"> |
24 | @@ -74,21 +74,7 @@ |
25 | </spacer> |
26 | </item> |
27 | <item> |
28 | - <widget class="QLabel" name="sync_status_label"> |
29 | - <property name="text"> |
30 | - <string>Sync in progress...</string> |
31 | - </property> |
32 | - <property name="buddy"> |
33 | - <cstring>change_sync_status_button</cstring> |
34 | - </property> |
35 | - </widget> |
36 | - </item> |
37 | - <item> |
38 | - <widget class="QPushButton" name="change_sync_status_button"> |
39 | - <property name="text"> |
40 | - <string>Stop Syncing</string> |
41 | - </property> |
42 | - </widget> |
43 | + <widget class="FileSyncStatus" name="file_sync_status" native="true"/> |
44 | </item> |
45 | <item> |
46 | <spacer name="horizontalSpacer_2"> |
47 | @@ -178,30 +164,46 @@ |
48 | <item> |
49 | <widget class="QPushButton" name="twitter_button"> |
50 | <property name="styleSheet"> |
51 | - <string notr="true">color: #fff; |
52 | -background-color: rgb(0, 170, 255); |
53 | -width: 1em; |
54 | -height: 1em; |
55 | -spacing: 0px; |
56 | -font: 18pt "Ubuntu" bold;</string> |
57 | + <string notr="true"/> |
58 | </property> |
59 | <property name="text"> |
60 | - <string>t</string> |
61 | + <string/> |
62 | + </property> |
63 | + <property name="icon"> |
64 | + <iconset resource="images.qrc"> |
65 | + <normaloff>:/twitter.png</normaloff>:/twitter.png</iconset> |
66 | + </property> |
67 | + <property name="iconSize"> |
68 | + <size> |
69 | + <width>32</width> |
70 | + <height>32</height> |
71 | + </size> |
72 | + </property> |
73 | + <property name="flat"> |
74 | + <bool>true</bool> |
75 | </property> |
76 | </widget> |
77 | </item> |
78 | <item> |
79 | <widget class="QPushButton" name="facebook_button"> |
80 | <property name="styleSheet"> |
81 | - <string notr="true">color: #fff; |
82 | -background-color: rgb(0, 0, 128); |
83 | -width: 1em; |
84 | -height: 1em; |
85 | -spacing: 0px; |
86 | -font: 18pt "Ubuntu" bold;</string> |
87 | + <string notr="true"/> |
88 | </property> |
89 | <property name="text"> |
90 | - <string>f</string> |
91 | + <string/> |
92 | + </property> |
93 | + <property name="icon"> |
94 | + <iconset resource="images.qrc"> |
95 | + <normaloff>:/facebook.png</normaloff>:/facebook.png</iconset> |
96 | + </property> |
97 | + <property name="iconSize"> |
98 | + <size> |
99 | + <width>32</width> |
100 | + <height>32</height> |
101 | + </size> |
102 | + </property> |
103 | + <property name="flat"> |
104 | + <bool>true</bool> |
105 | </property> |
106 | </widget> |
107 | </item> |
108 | @@ -240,15 +242,22 @@ |
109 | <header>ubuntuone.controlpanel.gui.qt.profile</header> |
110 | <container>1</container> |
111 | </customwidget> |
112 | + <customwidget> |
113 | + <class>FileSyncStatus</class> |
114 | + <extends>QWidget</extends> |
115 | + <header>ubuntuone.controlpanel.gui.qt.filesyncstatus</header> |
116 | + <container>1</container> |
117 | + </customwidget> |
118 | </customwidgets> |
119 | <tabstops> |
120 | <tabstop>tab_widget</tabstop> |
121 | <tabstop>help_button</tabstop> |
122 | <tabstop>twitter_button</tabstop> |
123 | <tabstop>facebook_button</tabstop> |
124 | - <tabstop>change_sync_status_button</tabstop> |
125 | <tabstop>get_more_space_button</tabstop> |
126 | </tabstops> |
127 | - <resources/> |
128 | + <resources> |
129 | + <include location="images.qrc"/> |
130 | + </resources> |
131 | <connections/> |
132 | </ui> |
133 | |
134 | === added file 'data/qt/filesyncstatus.ui' |
135 | --- data/qt/filesyncstatus.ui 1970-01-01 00:00:00 +0000 |
136 | +++ data/qt/filesyncstatus.ui 2011-05-31 18:28:26 +0000 |
137 | @@ -0,0 +1,45 @@ |
138 | +<?xml version="1.0" encoding="UTF-8"?> |
139 | +<ui version="4.0"> |
140 | + <class>Form</class> |
141 | + <widget class="QWidget" name="Form"> |
142 | + <property name="geometry"> |
143 | + <rect> |
144 | + <x>0</x> |
145 | + <y>0</y> |
146 | + <width>241</width> |
147 | + <height>47</height> |
148 | + </rect> |
149 | + </property> |
150 | + <property name="windowTitle"> |
151 | + <string>Form</string> |
152 | + </property> |
153 | + <layout class="QHBoxLayout" name="horizontalLayout_2"> |
154 | + <item> |
155 | + <layout class="QHBoxLayout" name="horizontalLayout"> |
156 | + <item> |
157 | + <widget class="QLabel" name="sync_status_label"> |
158 | + <property name="text"> |
159 | + <string>Status unknown</string> |
160 | + </property> |
161 | + <property name="buddy"> |
162 | + <cstring>sync_status_button</cstring> |
163 | + </property> |
164 | + </widget> |
165 | + </item> |
166 | + <item> |
167 | + <widget class="QPushButton" name="sync_status_button"> |
168 | + <property name="toolTip"> |
169 | + <string>test</string> |
170 | + </property> |
171 | + <property name="text"> |
172 | + <string>Action unknown</string> |
173 | + </property> |
174 | + </widget> |
175 | + </item> |
176 | + </layout> |
177 | + </item> |
178 | + </layout> |
179 | + </widget> |
180 | + <resources/> |
181 | + <connections/> |
182 | +</ui> |
183 | |
184 | === added file 'data/qt/images.qrc' |
185 | --- data/qt/images.qrc 1970-01-01 00:00:00 +0000 |
186 | +++ data/qt/images.qrc 2011-05-31 18:28:26 +0000 |
187 | @@ -0,0 +1,6 @@ |
188 | +<RCC> |
189 | + <qresource prefix="/"> |
190 | + <file>../twitter.png</file> |
191 | + <file>../facebook.png</file> |
192 | + </qresource> |
193 | +</RCC> |
194 | |
195 | === modified file 'data/qt/mainwindow.ui' |
196 | --- data/qt/mainwindow.ui 2011-05-24 14:20:18 +0000 |
197 | +++ data/qt/mainwindow.ui 2011-05-31 18:28:26 +0000 |
198 | @@ -34,7 +34,7 @@ |
199 | </property> |
200 | <layout class="QVBoxLayout" name="verticalLayout"> |
201 | <item> |
202 | - <widget class="ControlPanel" name="widget" native="true"/> |
203 | + <widget class="ControlPanel" name="control_panel" native="true"/> |
204 | </item> |
205 | </layout> |
206 | </widget> |
207 | |
208 | === modified file 'run-tests' |
209 | --- run-tests 2011-05-26 19:56:29 +0000 |
210 | +++ run-tests 2011-05-31 18:28:26 +0000 |
211 | @@ -39,7 +39,7 @@ |
212 | style_check() { |
213 | pylint --ignore ui ubuntuone/ |
214 | if [ -x `which pep8` ]; then |
215 | - pep8 --exclude '.svn,CVS,.bzr,.hg,.git,*_ui.py' --repeat bin/ $MODULE |
216 | + pep8 --exclude '.svn,CVS,.bzr,.hg,.git,*_ui.py,*_rc.py' --repeat bin/ $MODULE |
217 | else |
218 | echo "Please install the 'pep8' package." |
219 | fi |
220 | @@ -54,3 +54,4 @@ |
221 | fi |
222 | style_check |
223 | rm -rf _trial_temp |
224 | +rm -rf build |
225 | |
226 | === modified file 'ubuntuone/controlpanel/backend.py' |
227 | --- ubuntuone/controlpanel/backend.py 2011-05-24 18:56:16 +0000 |
228 | +++ ubuntuone/controlpanel/backend.py 2011-05-31 18:28:26 +0000 |
229 | @@ -531,6 +531,8 @@ |
230 | else: |
231 | yield self.unsubscribe_volume(volume_id) |
232 | |
233 | + returnValue(volume_id) |
234 | + |
235 | @inlineCallbacks |
236 | def subscribe_volume(self, volume_id): |
237 | """Subscribe to 'volume_id'.""" |
238 | |
239 | === modified file 'ubuntuone/controlpanel/gui/__init__.py' |
240 | --- ubuntuone/controlpanel/gui/__init__.py 2011-05-25 13:46:14 +0000 |
241 | +++ ubuntuone/controlpanel/gui/__init__.py 2011-05-31 18:28:26 +0000 |
242 | @@ -30,6 +30,11 @@ |
243 | ORANGE = '#DD4814' |
244 | QUOTA_THRESHOLD = 0.95 |
245 | SHARES_MIN_SIZE_FULL = 1048576 |
246 | +SUCCESS_COLOR = 'green' |
247 | + |
248 | +ERROR_ICON = u'✘' |
249 | +SYNCING_ICON = u'⇅' |
250 | +IDLE_ICON = u'✔' |
251 | |
252 | CONTACTS_ICON = 'contacts.png' |
253 | FACEBOOK_LOGO = 'facebook.png' |
254 | |
255 | === modified file 'ubuntuone/controlpanel/gui/gtk/gui.py' |
256 | --- ubuntuone/controlpanel/gui/gtk/gui.py 2011-05-25 14:34:17 +0000 |
257 | +++ ubuntuone/controlpanel/gui/gtk/gui.py 2011-05-31 18:28:26 +0000 |
258 | @@ -1339,42 +1339,44 @@ |
259 | """Backend notifies of file sync status being disabled.""" |
260 | self._update_status(FILE_SYNC_DISABLED, |
261 | FILE_SYNC_ENABLE, self.on_enable_clicked, |
262 | - '✘', 'red', FILE_SYNC_ENABLE_TOOLTIP) |
263 | + ERROR_ICON, ERROR_COLOR, FILE_SYNC_ENABLE_TOOLTIP) |
264 | |
265 | @log_call(logger.info) |
266 | def on_file_sync_status_starting(self, msg=None): |
267 | """Backend notifies of file sync status being starting.""" |
268 | self._update_status(FILE_SYNC_STARTING, |
269 | FILE_SYNC_STOP, self.on_stop_clicked, |
270 | - '⇅', ORANGE, FILE_SYNC_STOP_TOOLTIP) |
271 | + SYNCING_ICON, ORANGE, FILE_SYNC_STOP_TOOLTIP) |
272 | |
273 | @log_call(logger.info) |
274 | def on_file_sync_status_stopped(self, msg=None): |
275 | """Backend notifies of file sync being stopped.""" |
276 | self._update_status(FILE_SYNC_STOPPED, |
277 | FILE_SYNC_START, self.on_start_clicked, |
278 | - '✘', 'red', FILE_SYNC_START_TOOLTIP) |
279 | + ERROR_ICON, ERROR_COLOR, FILE_SYNC_START_TOOLTIP) |
280 | |
281 | @log_call(logger.info) |
282 | def on_file_sync_status_disconnected(self, msg=None): |
283 | """Backend notifies of file sync status being ready.""" |
284 | self._update_status(FILE_SYNC_DISCONNECTED, |
285 | FILE_SYNC_CONNECT, self.on_connect_clicked, |
286 | - '✘', 'red', FILE_SYNC_CONNECT_TOOLTIP,) |
287 | + ERROR_ICON, ERROR_COLOR, |
288 | + FILE_SYNC_CONNECT_TOOLTIP,) |
289 | |
290 | @log_call(logger.info) |
291 | def on_file_sync_status_syncing(self, msg=None): |
292 | """Backend notifies of file sync status being syncing.""" |
293 | self._update_status(FILE_SYNC_SYNCING, |
294 | FILE_SYNC_DISCONNECT, self.on_disconnect_clicked, |
295 | - '⇅', ORANGE, FILE_SYNC_DISCONNECT_TOOLTIP) |
296 | + SYNCING_ICON, ORANGE, FILE_SYNC_DISCONNECT_TOOLTIP) |
297 | |
298 | @log_call(logger.info) |
299 | def on_file_sync_status_idle(self, msg=None): |
300 | """Backend notifies of file sync status being idle.""" |
301 | self._update_status(FILE_SYNC_IDLE, |
302 | FILE_SYNC_DISCONNECT, self.on_disconnect_clicked, |
303 | - '✔', 'green', FILE_SYNC_DISCONNECT_TOOLTIP) |
304 | + IDLE_ICON, SUCCESS_COLOR, |
305 | + FILE_SYNC_DISCONNECT_TOOLTIP) |
306 | |
307 | @log_call(logger.error) |
308 | def on_file_sync_status_error(self, error_dict=None): |
309 | |
310 | === modified file 'ubuntuone/controlpanel/gui/gtk/tests/__init__.py' |
311 | --- ubuntuone/controlpanel/gui/gtk/tests/__init__.py 2011-05-24 16:05:30 +0000 |
312 | +++ ubuntuone/controlpanel/gui/gtk/tests/__init__.py 2011-05-31 18:28:26 +0000 |
313 | @@ -24,10 +24,24 @@ |
314 | |
315 | from ubuntuone.devtools.handlers import MementoHandler |
316 | |
317 | -from ubuntuone.controlpanel.backend import ControlBackend |
318 | from ubuntuone.controlpanel.gui.gtk import gui |
319 | from ubuntuone.controlpanel.gui.gtk.tests.test_package_manager import ( |
320 | FakedTransaction) |
321 | +# Unused imports, they are here to maintain old module API |
322 | +# pylint: disable=W0611 |
323 | +from ubuntuone.controlpanel.gui.tests import (FakedObject, |
324 | + FAKE_ACCOUNT_INFO, |
325 | + FAKE_DEVICE_INFO, |
326 | + FAKE_DEVICES_INFO, |
327 | + FAKE_FOLDERS_INFO, |
328 | + FAKE_SHARES_INFO, |
329 | + FAKE_VOLUMES_INFO, |
330 | + FAKE_VOLUMES_NO_FREE_SPACE_INFO, |
331 | + MUSIC_FOLDER, |
332 | + ROOT, |
333 | + USER_HOME, |
334 | +) |
335 | +# pylint: enable=W0611 |
336 | from ubuntuone.controlpanel.tests import TestCase |
337 | |
338 | |
339 | @@ -35,91 +49,6 @@ |
340 | # pylint: disable=W0201, W0212 |
341 | |
342 | |
343 | -FAKE_ACCOUNT_INFO = {'type': 'Payed', 'name': 'Test me', |
344 | - 'email': 'test.com', 'quota_total': '12345', 'quota_used': '9999'} |
345 | - |
346 | -USER_HOME = '/home/tester' |
347 | - |
348 | -ROOT = { |
349 | - u'volume_id': '', u'path': '/home/tester/My Ubuntu', |
350 | - u'subscribed': 'True', u'type': ControlBackend.ROOT_TYPE, |
351 | - u'display_name': u'My Ubuntu', |
352 | -} |
353 | - |
354 | -MUSIC_FOLDER = { |
355 | - u'volume_id': u'58236', u'subscribed': u'True', |
356 | - u'type': ControlBackend.FOLDER_TYPE, |
357 | - u'path': u'/home/tester/.ubuntuone/Purchased from Ubuntu One', |
358 | - u'suggested_path': u'~/.ubuntuone/Purchased from Ubuntu One', |
359 | - u'display_name': u'.ubuntuone/Purchased from Ubuntu One', |
360 | -} |
361 | - |
362 | -FAKE_FOLDERS_INFO = [ |
363 | - # backend send this ordered by path |
364 | - {u'volume_id': u'1', u'path': u'/home/tester/bar', |
365 | - u'suggested_path': u'~/bar', u'subscribed': u'True', |
366 | - u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'bar'}, |
367 | - {u'volume_id': u'2', u'path': u'/home/tester/baz', |
368 | - u'suggested_path': u'~/baz', u'subscribed': u'True', |
369 | - u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'baz'}, |
370 | - {u'volume_id': u'0', u'path': u'/home/tester/foo', |
371 | - u'suggested_path': u'~/foo', u'subscribed': u'', |
372 | - u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'foo'}, |
373 | -] |
374 | - |
375 | -FAKE_SHARES_INFO = [ |
376 | - # backend send this ordered by path |
377 | - {u'volume_id': u'1234', u'name': u'do', |
378 | - u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', |
379 | - u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
380 | - u'display_name': u'do'}, |
381 | - {u'volume_id': u'5678', u'name': u're', |
382 | - u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', |
383 | - u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE, |
384 | - u'display_name': u're'}, |
385 | -] |
386 | - |
387 | -FAKE_VOLUMES_INFO = [ |
388 | - (u'', u'147852369', [ROOT] + FAKE_FOLDERS_INFO), |
389 | - (u'Other User', gui.SHARES_MIN_SIZE_FULL, FAKE_SHARES_INFO), |
390 | -] |
391 | - |
392 | -FAKE_VOLUMES_NO_FREE_SPACE_INFO = [ |
393 | - (u'', u'500', [ROOT]), |
394 | - (u'No free space', u'0', |
395 | - [{u'volume_id': u'0', u'name': u'full', u'path': u'full-share', |
396 | - u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
397 | - u'display_name': u'something', |
398 | - }]), |
399 | - (u'Almost no free space', gui.SHARES_MIN_SIZE_FULL - 1, |
400 | - [{u'volume_id': u'1', u'name': u'almostfull', u'path': u'almost-full', |
401 | - u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
402 | - u'display_name': u'yadda', |
403 | - }]), |
404 | -] |
405 | - |
406 | -FAKE_DEVICE_INFO = { |
407 | - 'device_id': '1258-6854', 'device_name': 'Baz', 'device_type': 'Computer', |
408 | - 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
409 | - 'max_upload_speed': '1000', 'max_download_speed': '72548', |
410 | - 'show_all_notifications': 'True', |
411 | -} |
412 | - |
413 | -FAKE_DEVICES_INFO = [ |
414 | - {'device_id': '0', 'name': 'Ubuntu One @ Foo', 'type': 'Computer', |
415 | - 'is_local': '', 'configurable': ''}, |
416 | - {'device_id': '1', 'name': 'Ubuntu One @ Bar', 'type': 'Phone', |
417 | - 'is_local': '', 'configurable': ''}, |
418 | - {'device_id': '2', 'name': 'Ubuntu One @ Z', 'type': 'Computer', |
419 | - 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '', |
420 | - 'max_upload_speed': '0', 'max_download_speed': '0', |
421 | - 'show_all_notifications': ''}, |
422 | - {'device_id': '1258-6854', 'name': 'Ubuntu One @ Baz', 'type': 'Computer', |
423 | - 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
424 | - 'max_upload_speed': '1000', 'max_download_speed': '72548', |
425 | - 'show_all_notifications': 'True'}, # local |
426 | -] |
427 | - |
428 | FAKE_REPLICATIONS_INFO = [ |
429 | {'replication_id': 'foo', 'name': 'Bar', |
430 | 'enabled': 'True', 'dependency': ''}, |
431 | @@ -130,28 +59,6 @@ |
432 | ] |
433 | |
434 | |
435 | -class FakedObject(object): |
436 | - """Fake an object, record every call.""" |
437 | - |
438 | - exposed_methods = [] |
439 | - |
440 | - def __init__(self, *args, **kwargs): |
441 | - self._args = args |
442 | - self._kwargs = kwargs |
443 | - self._called = {} |
444 | - for i in self.exposed_methods: |
445 | - setattr(self, i, self._record_call(i)) |
446 | - |
447 | - def _record_call(self, func_name): |
448 | - """Store values when calling 'func_name'.""" |
449 | - |
450 | - def inner(*args, **kwargs): |
451 | - """Fake 'func_name'.""" |
452 | - self._called[func_name] = (args, kwargs) |
453 | - |
454 | - return inner |
455 | - |
456 | - |
457 | class FakedNMState(FakedObject): |
458 | """Fake a NetworkManagerState.""" |
459 | |
460 | |
461 | === modified file 'ubuntuone/controlpanel/gui/qt/controlpanel.py' |
462 | --- ubuntuone/controlpanel/gui/qt/controlpanel.py 2011-05-24 18:56:16 +0000 |
463 | +++ ubuntuone/controlpanel/gui/qt/controlpanel.py 2011-05-31 18:28:26 +0000 |
464 | @@ -1,6 +1,7 @@ |
465 | # -*- coding: utf-8 -*- |
466 | |
467 | # Authors: Alejandro J. Cura <alecu@canonical.com> |
468 | +# Authors: Natalia B Bidart <natalia.bidart@canonical.com> |
469 | # |
470 | # Copyright 2011 Canonical Ltd. |
471 | # |
472 | @@ -18,33 +19,16 @@ |
473 | |
474 | """The user interface for the control panel for Ubuntu One.""" |
475 | |
476 | -from PyQt4 import QtGui, QtCore |
477 | +from PyQt4 import QtGui |
478 | |
479 | from ubuntuone.controlpanel import backend |
480 | -from ubuntuone.controlpanel.logger import setup_logging, log_call |
481 | -# Wildcard import ubuntuone.controlpanel.gui |
482 | -# pylint: disable=W0401, W0614 |
483 | -from ubuntuone.controlpanel.gui import * |
484 | -# pylint: enable=W0401, W0614 |
485 | +from ubuntuone.controlpanel.logger import setup_logging |
486 | from ubuntuone.controlpanel.gui.qt.ui import controlpanel_ui |
487 | |
488 | |
489 | logger = setup_logging('qt.controlpanel') |
490 | |
491 | |
492 | -FILE_SYNC_STATUS = { |
493 | - backend.FILE_SYNC_DISCONNECTED: FILE_SYNC_DISCONNECTED, |
494 | - backend.FILE_SYNC_DISABLED: FILE_SYNC_DISABLED, |
495 | - backend.FILE_SYNC_ERROR: FILE_SYNC_ERROR, |
496 | - backend.FILE_SYNC_IDLE: FILE_SYNC_IDLE, |
497 | - backend.FILE_SYNC_STARTING: FILE_SYNC_STARTING, |
498 | - backend.FILE_SYNC_STOPPED: FILE_SYNC_STOPPED, |
499 | - backend.FILE_SYNC_SYNCING: FILE_SYNC_SYNCING, |
500 | -} |
501 | - |
502 | -STATUS_MARKUP = u'<b>⭐</b> %s' |
503 | - |
504 | - |
505 | class ControlPanel(QtGui.QWidget): |
506 | """The Control Panel widget""" |
507 | |
508 | @@ -55,28 +39,9 @@ |
509 | self.ui.setupUi(self) |
510 | |
511 | self.backend = backend.ControlBackend() |
512 | - self.backend.status_changed_handler = self.process_status |
513 | - |
514 | - # this call is crashing with MemoryError as per |
515 | - # http://pastebin.ubuntu.com/612270/ |
516 | - #self.backend.file_sync_status() |
517 | |
518 | logger.debug('%s: started.', self.__class__.__name__) |
519 | |
520 | - @log_call(logger.debug) |
521 | - def process_status(self, status): |
522 | - """Match status with signals.""" |
523 | - logger.debug('process_status: new status received %r', status) |
524 | - |
525 | - try: |
526 | - status = FILE_SYNC_STATUS[status[backend.STATUS_KEY]] |
527 | - except KeyError: |
528 | - logger.exception('process_status: received unknown status dict %r', |
529 | - status) |
530 | - else: |
531 | - msg = STATUS_MARKUP % (status,) |
532 | - self.ui.sync_status_label.setText(msg) |
533 | - |
534 | - @QtCore.pyqtSlot() |
535 | - def on_change_sync_status_button_clicked(self, *a, **kw): |
536 | - """The change sync status button was clicked.""" |
537 | + def load(self): |
538 | + """Load info.""" |
539 | + self.ui.file_sync_status.load() |
540 | |
541 | === added file 'ubuntuone/controlpanel/gui/qt/filesyncstatus.py' |
542 | --- ubuntuone/controlpanel/gui/qt/filesyncstatus.py 1970-01-01 00:00:00 +0000 |
543 | +++ ubuntuone/controlpanel/gui/qt/filesyncstatus.py 2011-05-31 18:28:26 +0000 |
544 | @@ -0,0 +1,151 @@ |
545 | +# -*- coding: utf-8 -*- |
546 | + |
547 | +# Authors: Natalia B Bidart <natalia.bidart@canonical.com> |
548 | +# |
549 | +# Copyright 2011 Canonical Ltd. |
550 | +# |
551 | +# This program is free software: you can redistribute it and/or modify it |
552 | +# under the terms of the GNU General Public License version 3, as published |
553 | +# by the Free Software Foundation. |
554 | +# |
555 | +# This program is distributed in the hope that it will be useful, but |
556 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
557 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
558 | +# PURPOSE. See the GNU General Public License for more details. |
559 | +# |
560 | +# You should have received a copy of the GNU General Public License along |
561 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
562 | + |
563 | +"""The file sync status widget.""" |
564 | + |
565 | +from PyQt4 import QtGui, QtCore |
566 | +from twisted.internet import defer |
567 | + |
568 | +from ubuntuone.controlpanel import backend |
569 | +from ubuntuone.controlpanel.logger import setup_logging, log_call |
570 | +# Wildcard import ubuntuone.controlpanel.gui |
571 | +# pylint: disable=W0401, W0614 |
572 | +from ubuntuone.controlpanel.gui import * |
573 | +# pylint: enable=W0401, W0614 |
574 | +from ubuntuone.controlpanel.gui.qt.ui import filesyncstatus_ui |
575 | + |
576 | + |
577 | +logger = setup_logging('qt.filesyncstatus') |
578 | + |
579 | + |
580 | +WARNING_MARKUP = '<font color="%s"><b>%%s</b></font>' % ERROR_COLOR |
581 | + |
582 | +FILE_SYNC_STATUS = { |
583 | + backend.FILE_SYNC_DISABLED: |
584 | + {'msg': FILE_SYNC_DISABLED, 'action': FILE_SYNC_ENABLE, |
585 | + 'backend_method': 'enable_files', |
586 | + 'icon': ERROR_ICON, 'color': ERROR_COLOR, |
587 | + 'tooltip': FILE_SYNC_ENABLE_TOOLTIP}, |
588 | + backend.FILE_SYNC_DISCONNECTED: |
589 | + {'msg': FILE_SYNC_DISCONNECTED, 'action': FILE_SYNC_CONNECT, |
590 | + 'backend_method': 'connect_files', |
591 | + 'icon': ERROR_ICON, 'color': ERROR_COLOR, |
592 | + 'tooltip': FILE_SYNC_CONNECT_TOOLTIP}, |
593 | + backend.FILE_SYNC_ERROR: |
594 | + {'msg': WARNING_MARKUP % FILE_SYNC_ERROR, 'action': FILE_SYNC_RESTART, |
595 | + 'backend_method': 'restart_files', |
596 | + 'tooltip': FILE_SYNC_RESTART_TOOLTIP}, |
597 | + backend.FILE_SYNC_IDLE: |
598 | + {'msg': FILE_SYNC_IDLE, 'action': FILE_SYNC_DISCONNECT, |
599 | + 'backend_method': 'disconnect_files', |
600 | + 'icon': IDLE_ICON, 'color': SUCCESS_COLOR, |
601 | + 'tooltip': FILE_SYNC_DISCONNECT_TOOLTIP}, |
602 | + backend.FILE_SYNC_STARTING: |
603 | + {'msg': FILE_SYNC_STARTING, 'action': FILE_SYNC_STOP, |
604 | + 'backend_method': 'stop_files', |
605 | + 'icon': SYNCING_ICON, 'color': ORANGE, |
606 | + 'tooltip': FILE_SYNC_STOP_TOOLTIP}, |
607 | + backend.FILE_SYNC_STOPPED: |
608 | + {'msg': FILE_SYNC_STOPPED, 'action': FILE_SYNC_START, |
609 | + 'backend_method': 'start_files', |
610 | + 'icon': ERROR_ICON, 'color': ERROR_COLOR, |
611 | + 'tooltip': FILE_SYNC_START_TOOLTIP}, |
612 | + backend.FILE_SYNC_SYNCING: |
613 | + {'msg': FILE_SYNC_SYNCING, 'action': FILE_SYNC_DISCONNECT, |
614 | + 'backend_method': 'disconnect_files', |
615 | + 'icon': SYNCING_ICON, 'color': ORANGE, |
616 | + 'tooltip': FILE_SYNC_DISCONNECT_TOOLTIP}, |
617 | + backend.FILE_SYNC_UNKNOWN: |
618 | + {'msg': WARNING_MARKUP % FILE_SYNC_ERROR, 'action': FILE_SYNC_RESTART, |
619 | + 'backend_method': 'restart_files', |
620 | + 'tooltip': FILE_SYNC_RESTART_TOOLTIP}, |
621 | +} |
622 | + |
623 | + |
624 | +class FileSyncStatus(QtGui.QWidget): |
625 | + """The FileSyncStatus widget""" |
626 | + |
627 | + def __init__(self, parent=None): |
628 | + """Initialize the UI of the widget.""" |
629 | + QtGui.QWidget.__init__(self, parent) |
630 | + self.ui = filesyncstatus_ui.Ui_Form() |
631 | + self.ui.setupUi(self) |
632 | + self.show() |
633 | + |
634 | + self._backend_method = None |
635 | + |
636 | + self.backend = backend.ControlBackend() |
637 | + self.backend.status_changed_handler = self.process_status |
638 | + |
639 | + logger.debug('%s: started.', self.__class__.__name__) |
640 | + |
641 | + def load(self): |
642 | + """Load info.""" |
643 | + d = defer.maybeDeferred(self.backend.file_sync_status) |
644 | + d.addCallback(self.process_status) |
645 | + |
646 | + @log_call(logger.debug) |
647 | + def process_status(self, status): |
648 | + """Match status with signals.""" |
649 | + logger.debug('process_status: new status received %r', status) |
650 | + |
651 | + try: |
652 | + status_key = status[backend.STATUS_KEY] |
653 | + data = FILE_SYNC_STATUS[status_key] |
654 | + except (KeyError, TypeError): |
655 | + logger.exception('process_status: received unknown status dict %r', |
656 | + status) |
657 | + return |
658 | + |
659 | + msg = data['msg'] |
660 | + if status_key in (backend.FILE_SYNC_ERROR, backend.FILE_SYNC_UNKNOWN): |
661 | + reason = status[backend.MSG_KEY] |
662 | + if reason: |
663 | + msg += ' (' + reason + ')' |
664 | + |
665 | + icon = data.get('icon') |
666 | + color = data.get('color') |
667 | + if icon is not None: |
668 | + foreground = '' if color is None else 'color="%s"' % color |
669 | + msg = '<font %s>%s</font> %s' % (foreground, icon, msg) |
670 | + |
671 | + self.ui.sync_status_label.setText(msg) |
672 | + |
673 | + action = data.get('action') |
674 | + if action is not None: |
675 | + self.ui.sync_status_button.setText(action) |
676 | + self.ui.sync_status_button.setEnabled(True) |
677 | + self.ui.sync_status_button.show() |
678 | + else: |
679 | + self.ui.sync_status_button.hide() |
680 | + |
681 | + tooltip = data.get('tooltip') |
682 | + if tooltip is not None: |
683 | + self.ui.sync_status_button.setToolTip(tooltip) |
684 | + |
685 | + self._backend_method = getattr(self.backend, data['backend_method']) |
686 | + |
687 | + @QtCore.pyqtSlot() |
688 | + def on_sync_status_button_clicked(self, *a, **kw): |
689 | + """Button was clicked, act accordingly to the label.""" |
690 | + self.ui.sync_status_button.setEnabled(False) |
691 | + if self._backend_method is not None: |
692 | + self._backend_method() |
693 | + else: |
694 | + logger.error('on_sync_status_button_clicked: backend method is ' |
695 | + 'None!') |
696 | |
697 | === modified file 'ubuntuone/controlpanel/gui/qt/gui.py' |
698 | --- ubuntuone/controlpanel/gui/qt/gui.py 2011-05-24 14:20:18 +0000 |
699 | +++ ubuntuone/controlpanel/gui/qt/gui.py 2011-05-31 18:28:26 +0000 |
700 | @@ -50,6 +50,10 @@ |
701 | self.close_callback() |
702 | event.accept() |
703 | |
704 | + def load(self): |
705 | + """Load info.""" |
706 | + self.ui.control_panel.load() |
707 | + |
708 | |
709 | def main(switch_to='', alert=False): |
710 | """Start the Qt reactor and open the main window.""" |
711 | @@ -68,6 +72,36 @@ |
712 | qt4reactor.install() |
713 | from twisted.internet import reactor |
714 | |
715 | + # Due to the crash with MemoryError as per |
716 | + # http://pastebin.ubuntu.com/612270/ |
717 | + # we need patch SyncDaemonTool so there is no Dbus interaction |
718 | + from ubuntuone.controlpanel.integrationtests.test_sd_client.test_linux \ |
719 | + import FakedSyncDaemonTool |
720 | + |
721 | + import subprocess |
722 | + |
723 | + class SDTool(FakedSyncDaemonTool): |
724 | + """A custom SDTool.""" |
725 | + |
726 | + def quit(self): |
727 | + """Quit the syncdaemon.""" |
728 | + subprocess.Popen(('u1sdtool', '-q')) |
729 | + |
730 | + def connect(self): |
731 | + """Connect syncdaemon.""" |
732 | + subprocess.Popen(('u1sdtool', '-c')) |
733 | + |
734 | + def disconnect(self): |
735 | + """Disconnect syncdaemon.""" |
736 | + subprocess.Popen(('u1sdtool', '-d')) |
737 | + |
738 | + def start(self): |
739 | + """Start syncdaemon if it's not running.""" |
740 | + subprocess.Popen(('u1sdtool', '-s')) |
741 | + |
742 | + from ubuntuone.platform.linux import tools |
743 | + tools.SyncDaemonTool = SDTool |
744 | + |
745 | window = MainWindow(close_callback=reactor.stop) |
746 | window.show() |
747 | |
748 | |
749 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/__init__.py' |
750 | --- ubuntuone/controlpanel/gui/qt/tests/__init__.py 2011-05-24 18:56:16 +0000 |
751 | +++ ubuntuone/controlpanel/gui/qt/tests/__init__.py 2011-05-31 18:28:26 +0000 |
752 | @@ -18,7 +18,12 @@ |
753 | |
754 | """The test suite for the Qt UI for the control panel for Ubuntu One.""" |
755 | |
756 | +from ubuntuone.controlpanel import backend |
757 | from ubuntuone.controlpanel.tests import TestCase |
758 | +from ubuntuone.controlpanel.gui.tests import FakedObject |
759 | + |
760 | +# Attribute 'yyy' defined outside __init__, access to a protected member |
761 | +# pylint: disable=W0201, W0212 |
762 | |
763 | |
764 | def skip_if_abstract_class(test): |
765 | @@ -38,6 +43,26 @@ |
766 | return inner |
767 | |
768 | |
769 | +class FakeUi(FakedObject): |
770 | + """A fake Ui object.""" |
771 | + |
772 | + exposed_methods = ['setupUi'] |
773 | + |
774 | + |
775 | +class FakedControlPanelBackend(FakedObject): |
776 | + """Fake a Control Panel Backend.""" |
777 | + |
778 | + exposed_methods = [ |
779 | + 'account_info', # account |
780 | + 'devices_info', 'change_device_settings', 'remove_device', # devices |
781 | + 'volumes_info', 'change_volume_settings', # volumes |
782 | + 'replications_info', 'change_replication_settings', # replications |
783 | + 'file_sync_status', 'enable_files', 'disable_files', # files |
784 | + 'connect_files', 'disconnect_files', |
785 | + 'restart_files', 'start_files', 'stop_files', 'shutdown', |
786 | + ] |
787 | + |
788 | + |
789 | class BaseTestCase(TestCase): |
790 | """Base Test Case.""" |
791 | |
792 | @@ -49,10 +74,21 @@ |
793 | @skip_if_abstract_class |
794 | def setUp(self): |
795 | super(BaseTestCase, self).setUp() |
796 | + self.patch(backend, 'ControlBackend', FakedControlPanelBackend) |
797 | # self.class_ui is not callable |
798 | # pylint: disable=E1102 |
799 | self.ui = self.class_ui(**self.kwargs) |
800 | |
801 | + def assert_backend_called(self, method_name, args=None, kwargs=None): |
802 | + """Check that the control panel backend 'method_name' was called.""" |
803 | + if args is None: |
804 | + args = () |
805 | + if kwargs is None: |
806 | + kwargs = {} |
807 | + |
808 | + self.assertIn(method_name, self.ui.backend._called) |
809 | + self.assertEqual(self.ui.backend._called[method_name], (args, kwargs)) |
810 | + |
811 | @skip_if_abstract_class |
812 | def test_init_loads_ui(self): |
813 | """The __init__ method loads the ui.""" |
814 | @@ -60,18 +96,5 @@ |
815 | # pylint: disable=E1102 |
816 | self.ui = self.class_ui(**self.kwargs) |
817 | # pylint: disable=E1101 |
818 | - self.assertEqual(self.ui.ui.called, |
819 | - ((self.ui,), {}), 'setupUi called.') |
820 | - |
821 | - |
822 | -class FakeUi(object): |
823 | - """A fake Ui object.""" |
824 | - |
825 | - def __init__(self): |
826 | - """Initialize this fake instance.""" |
827 | - self.called = None |
828 | - |
829 | - # pylint: disable=C0103 |
830 | - def setupUi(self, *args, **kwargs): |
831 | - """Fake setupUi.""" |
832 | - self.called = (args, kwargs) |
833 | + self.assertEqual(self.ui.ui._called, |
834 | + {'setupUi': ((self.ui,), {})}) |
835 | |
836 | === modified file 'ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py' |
837 | --- ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2011-05-24 20:00:59 +0000 |
838 | +++ ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2011-05-31 18:28:26 +0000 |
839 | @@ -33,45 +33,3 @@ |
840 | """Backend is created.""" |
841 | self.assertIsInstance(self.ui.backend, |
842 | gui.backend.ControlBackend) |
843 | - |
844 | - def test_process_status_changed(self): |
845 | - """Backend's file sync status changed callback is connected.""" |
846 | - self.assertEqual(self.ui.backend.status_changed_handler, |
847 | - self.ui.process_status) |
848 | - |
849 | - def _test_process_status(self, status_key): |
850 | - """File sync status changes update the label.""" |
851 | - status = {gui.backend.STATUS_KEY: status_key, |
852 | - gui.backend.MSG_KEY: 'something not important'} |
853 | - self.ui.process_status(status) |
854 | - |
855 | - self.assertEqual(self.ui.ui.sync_status_label.text(), |
856 | - gui.STATUS_MARKUP % gui.FILE_SYNC_STATUS[status_key]) |
857 | - |
858 | - def test_process_status_disconnected(self): |
859 | - """File sync status disconnected update the label.""" |
860 | - self._test_process_status(gui.backend.FILE_SYNC_DISCONNECTED) |
861 | - |
862 | - def test_process_status_disabled(self): |
863 | - """File sync status disabled update the label.""" |
864 | - self._test_process_status(gui.backend.FILE_SYNC_DISABLED) |
865 | - |
866 | - def test_process_status_error(self): |
867 | - """File sync status error update the label.""" |
868 | - self._test_process_status(gui.backend.FILE_SYNC_ERROR) |
869 | - |
870 | - def test_process_status_idle(self): |
871 | - """File sync status idle update the label.""" |
872 | - self._test_process_status(gui.backend.FILE_SYNC_IDLE) |
873 | - |
874 | - def test_process_status_starting(self): |
875 | - """File sync status starting update the label.""" |
876 | - self._test_process_status(gui.backend.FILE_SYNC_STARTING) |
877 | - |
878 | - def test_process_status_stopped(self): |
879 | - """File sync status stopped update the label.""" |
880 | - self._test_process_status(gui.backend.FILE_SYNC_STOPPED) |
881 | - |
882 | - def test_process_status_syncing(self): |
883 | - """File sync status syncing update the label.""" |
884 | - self._test_process_status(gui.backend.FILE_SYNC_SYNCING) |
885 | |
886 | === added file 'ubuntuone/controlpanel/gui/qt/tests/test_filesyncstatus.py' |
887 | --- ubuntuone/controlpanel/gui/qt/tests/test_filesyncstatus.py 1970-01-01 00:00:00 +0000 |
888 | +++ ubuntuone/controlpanel/gui/qt/tests/test_filesyncstatus.py 2011-05-31 18:28:26 +0000 |
889 | @@ -0,0 +1,159 @@ |
890 | +# -*- coding: utf-8 -*- |
891 | + |
892 | +# Authors: Natalia B Bidart <natalia.bidart@canonical.com> |
893 | +# |
894 | +# Copyright 2011 Canonical Ltd. |
895 | +# |
896 | +# This program is free software: you can redistribute it and/or modify it |
897 | +# under the terms of the GNU General Public License version 3, as published |
898 | +# by the Free Software Foundation. |
899 | +# |
900 | +# This program is distributed in the hope that it will be useful, but |
901 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
902 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
903 | +# PURPOSE. See the GNU General Public License for more details. |
904 | +# |
905 | +# You should have received a copy of the GNU General Public License along |
906 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
907 | + |
908 | +"""Tests for the Control Panel.""" |
909 | + |
910 | +from ubuntuone.controlpanel.gui.qt import filesyncstatus as gui |
911 | +from ubuntuone.controlpanel.gui.qt.tests import BaseTestCase |
912 | + |
913 | +backend = gui.backend # pylint: disable=C0103 |
914 | + |
915 | + |
916 | +class FileSyncStatusTestCase(BaseTestCase): |
917 | + """Test the qt control panel.""" |
918 | + |
919 | + innerclass_ui = gui.filesyncstatus_ui |
920 | + innerclass_name = "Ui_Form" |
921 | + class_ui = gui.FileSyncStatus |
922 | + |
923 | + def assert_status_correct(self, status_bd, status_ui, msg_bd=None, |
924 | + action=None, callback=None, tooltip=None): |
925 | + """The shown status is correct. |
926 | + |
927 | + * The ui's label shows 'status_ui'. |
928 | + * If action is not None, the ui's button shows that 'action' as label |
929 | + and when clicking it, 'callback' gets executed. |
930 | + * If action is None, the ui's button should be hidden. |
931 | + * If a tooltip is given, then it exists with correct text. |
932 | + |
933 | + """ |
934 | + if msg_bd is None: |
935 | + msg_bd = None |
936 | + expected_text = status_ui |
937 | + else: |
938 | + expected_text = status_ui + ' (' + msg_bd + ')' |
939 | + |
940 | + status = {backend.STATUS_KEY: status_bd, backend.MSG_KEY: msg_bd} |
941 | + self.ui.process_status(status) |
942 | + |
943 | + self.assertTrue(self.ui.ui.sync_status_label.isVisible()) |
944 | + |
945 | + actual_text = self.ui.ui.sync_status_label.text() |
946 | + msg = '%r does not end with %r' % (actual_text, expected_text) |
947 | + self.assertTrue(actual_text.endsWith(expected_text), msg) |
948 | + |
949 | + self.assertTrue(self.ui.ui.sync_status_button.isEnabled()) |
950 | + |
951 | + if action is not None: |
952 | + self.assertTrue(self.ui.ui.sync_status_button.isVisible()) |
953 | + self.assertTrue(self.ui.ui.sync_status_button.isEnabled()) |
954 | + self.assertEqual(self.ui.ui.sync_status_button.text(), action) |
955 | + |
956 | + self.ui.ui.sync_status_button.click() |
957 | + self.assertFalse(self.ui.ui.sync_status_button.isEnabled()) |
958 | + self.assert_backend_called(callback) |
959 | + else: |
960 | + self.assertFalse(self.ui.ui.sync_status_button.isVisible()) |
961 | + |
962 | + if tooltip is not None: |
963 | + self.assertEqual(self.ui.ui.sync_status_button.toolTip(), tooltip) |
964 | + else: |
965 | + self.assertEqual(self.ui.ui.sync_status_button.toolTip(), '') |
966 | + |
967 | + def test_backend(self): |
968 | + """Backend is created.""" |
969 | + self.assertIsInstance(self.ui.backend, |
970 | + backend.ControlBackend) |
971 | + |
972 | + def test_process_status_changed(self): |
973 | + """Backend's file sync status changed callback is connected.""" |
974 | + self.assertEqual(self.ui.backend.status_changed_handler, |
975 | + self.ui.process_status) |
976 | + |
977 | + def test_file_sync_status_is_requested_on_load(self): |
978 | + """The file sync status is requested to the backend.""" |
979 | + self.ui.load() |
980 | + self.assert_backend_called('file_sync_status', ()) |
981 | + |
982 | + def test_process_status_disabled(self): |
983 | + """File sync status disabled update the label.""" |
984 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_DISABLED, |
985 | + status_ui=gui.FILE_SYNC_DISABLED, |
986 | + action=gui.FILE_SYNC_ENABLE, |
987 | + callback='enable_files', |
988 | + tooltip=gui.FILE_SYNC_ENABLE_TOOLTIP) |
989 | + |
990 | + def test_process_status_disconnected(self): |
991 | + """File sync status disconnected update the label.""" |
992 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_DISCONNECTED, |
993 | + status_ui=gui.FILE_SYNC_DISCONNECTED, |
994 | + action=gui.FILE_SYNC_CONNECT, |
995 | + callback='connect_files', |
996 | + tooltip=gui.FILE_SYNC_CONNECT_TOOLTIP) |
997 | + |
998 | + def test_process_status_error(self): |
999 | + """File sync status error update the label.""" |
1000 | + msg = gui.WARNING_MARKUP % gui.FILE_SYNC_ERROR |
1001 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_ERROR, |
1002 | + status_ui=msg, |
1003 | + msg_bd='what an error!', |
1004 | + action=gui.FILE_SYNC_RESTART, |
1005 | + callback='restart_files', |
1006 | + tooltip=gui.FILE_SYNC_RESTART_TOOLTIP) |
1007 | + |
1008 | + def test_process_status_idle(self): |
1009 | + """File sync status idle update the label.""" |
1010 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_IDLE, |
1011 | + status_ui=gui.FILE_SYNC_IDLE, |
1012 | + action=gui.FILE_SYNC_DISCONNECT, |
1013 | + callback='disconnect_files', |
1014 | + tooltip=gui.FILE_SYNC_DISCONNECT_TOOLTIP) |
1015 | + |
1016 | + def test_process_status_starting(self): |
1017 | + """File sync status starting update the label.""" |
1018 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_STARTING, |
1019 | + status_ui=gui.FILE_SYNC_STARTING, |
1020 | + action=gui.FILE_SYNC_STOP, |
1021 | + callback='stop_files', |
1022 | + tooltip=gui.FILE_SYNC_STOP_TOOLTIP) |
1023 | + |
1024 | + def test_process_status_stopped(self): |
1025 | + """File sync status stopped update the label.""" |
1026 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_STOPPED, |
1027 | + status_ui=gui.FILE_SYNC_STOPPED, |
1028 | + action=gui.FILE_SYNC_START, |
1029 | + callback='start_files', |
1030 | + tooltip=gui.FILE_SYNC_START_TOOLTIP) |
1031 | + |
1032 | + def test_process_status_syncing(self): |
1033 | + """File sync status syncing update the label.""" |
1034 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_SYNCING, |
1035 | + status_ui=gui.FILE_SYNC_SYNCING, |
1036 | + action=gui.FILE_SYNC_DISCONNECT, |
1037 | + callback='disconnect_files', |
1038 | + tooltip=gui.FILE_SYNC_DISCONNECT_TOOLTIP) |
1039 | + |
1040 | + def test_process_status_unknown(self): |
1041 | + """File sync status unknown update the label.""" |
1042 | + msg = gui.WARNING_MARKUP % gui.FILE_SYNC_ERROR |
1043 | + self.assert_status_correct(status_bd=backend.FILE_SYNC_UNKNOWN, |
1044 | + status_ui=msg, |
1045 | + msg_bd='yadda oops', |
1046 | + action=gui.FILE_SYNC_RESTART, |
1047 | + callback='restart_files', |
1048 | + tooltip=gui.FILE_SYNC_RESTART_TOOLTIP) |
1049 | |
1050 | === added directory 'ubuntuone/controlpanel/gui/tests' |
1051 | === added file 'ubuntuone/controlpanel/gui/tests/__init__.py' |
1052 | --- ubuntuone/controlpanel/gui/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1053 | +++ ubuntuone/controlpanel/gui/tests/__init__.py 2011-05-31 18:28:26 +0000 |
1054 | @@ -0,0 +1,133 @@ |
1055 | +# -*- coding: utf-8 -*- |
1056 | + |
1057 | +# Authors: Natalia B Bidart <natalia.bidart@canonical.com> |
1058 | +# |
1059 | +# Copyright 2011 Canonical Ltd. |
1060 | +# |
1061 | +# This program is free software: you can redistribute it and/or modify it |
1062 | +# under the terms of the GNU General Public License version 3, as published |
1063 | +# by the Free Software Foundation. |
1064 | +# |
1065 | +# This program is distributed in the hope that it will be useful, but |
1066 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1067 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1068 | +# PURPOSE. See the GNU General Public License for more details. |
1069 | +# |
1070 | +# You should have received a copy of the GNU General Public License along |
1071 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1072 | + |
1073 | +"""The test suite for the GTK UI for the control panel for Ubuntu One.""" |
1074 | + |
1075 | +from ubuntuone.controlpanel import gui |
1076 | +from ubuntuone.controlpanel.backend import ControlBackend |
1077 | + |
1078 | +# Attribute 'yyy' defined outside __init__, access to a protected member |
1079 | +# pylint: disable=W0201, W0212 |
1080 | + |
1081 | + |
1082 | +FAKE_ACCOUNT_INFO = {'type': 'Payed', 'name': 'Test me', |
1083 | + 'email': 'test.com', 'quota_total': '12345', 'quota_used': '9999'} |
1084 | + |
1085 | +USER_HOME = '/home/tester' |
1086 | + |
1087 | +ROOT = { |
1088 | + u'volume_id': '', u'path': '/home/tester/My Ubuntu', |
1089 | + u'subscribed': 'True', u'type': ControlBackend.ROOT_TYPE, |
1090 | + u'display_name': u'My Ubuntu', |
1091 | +} |
1092 | + |
1093 | +MUSIC_FOLDER = { |
1094 | + u'volume_id': u'58236', u'subscribed': u'True', |
1095 | + u'type': ControlBackend.FOLDER_TYPE, |
1096 | + u'path': u'/home/tester/.ubuntuone/Purchased from Ubuntu One', |
1097 | + u'suggested_path': u'~/.ubuntuone/Purchased from Ubuntu One', |
1098 | + u'display_name': u'.ubuntuone/Purchased from Ubuntu One', |
1099 | +} |
1100 | + |
1101 | +FAKE_FOLDERS_INFO = [ |
1102 | + # backend send this ordered by path |
1103 | + {u'volume_id': u'1', u'path': u'/home/tester/bar', |
1104 | + u'suggested_path': u'~/bar', u'subscribed': u'True', |
1105 | + u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'bar'}, |
1106 | + {u'volume_id': u'2', u'path': u'/home/tester/baz', |
1107 | + u'suggested_path': u'~/baz', u'subscribed': u'True', |
1108 | + u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'baz'}, |
1109 | + {u'volume_id': u'0', u'path': u'/home/tester/foo', |
1110 | + u'suggested_path': u'~/foo', u'subscribed': u'', |
1111 | + u'type': ControlBackend.FOLDER_TYPE, u'display_name': u'foo'}, |
1112 | +] |
1113 | + |
1114 | +FAKE_SHARES_INFO = [ |
1115 | + # backend send this ordered by path |
1116 | + {u'volume_id': u'1234', u'name': u'do', |
1117 | + u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', |
1118 | + u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
1119 | + u'display_name': u'do'}, |
1120 | + {u'volume_id': u'5678', u'name': u're', |
1121 | + u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', |
1122 | + u'subscribed': u'True', u'type': ControlBackend.SHARE_TYPE, |
1123 | + u'display_name': u're'}, |
1124 | +] |
1125 | + |
1126 | +FAKE_VOLUMES_INFO = [ |
1127 | + (u'', u'147852369', [ROOT] + FAKE_FOLDERS_INFO), |
1128 | + (u'Other User', gui.SHARES_MIN_SIZE_FULL, FAKE_SHARES_INFO), |
1129 | +] |
1130 | + |
1131 | +FAKE_VOLUMES_NO_FREE_SPACE_INFO = [ |
1132 | + (u'', u'500', [ROOT]), |
1133 | + (u'No free space', u'0', |
1134 | + [{u'volume_id': u'0', u'name': u'full', u'path': u'full-share', |
1135 | + u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
1136 | + u'display_name': u'something', |
1137 | + }]), |
1138 | + (u'Almost no free space', gui.SHARES_MIN_SIZE_FULL - 1, |
1139 | + [{u'volume_id': u'1', u'name': u'almostfull', u'path': u'almost-full', |
1140 | + u'subscribed': u'', u'type': ControlBackend.SHARE_TYPE, |
1141 | + u'display_name': u'yadda', |
1142 | + }]), |
1143 | +] |
1144 | + |
1145 | +FAKE_DEVICE_INFO = { |
1146 | + 'device_id': '1258-6854', 'device_name': 'Baz', 'device_type': 'Computer', |
1147 | + 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
1148 | + 'max_upload_speed': '1000', 'max_download_speed': '72548', |
1149 | + 'show_all_notifications': 'True', |
1150 | +} |
1151 | + |
1152 | +FAKE_DEVICES_INFO = [ |
1153 | + {'device_id': '0', 'name': 'Ubuntu One @ Foo', 'type': 'Computer', |
1154 | + 'is_local': '', 'configurable': ''}, |
1155 | + {'device_id': '1', 'name': 'Ubuntu One @ Bar', 'type': 'Phone', |
1156 | + 'is_local': '', 'configurable': ''}, |
1157 | + {'device_id': '2', 'name': 'Ubuntu One @ Z', 'type': 'Computer', |
1158 | + 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '', |
1159 | + 'max_upload_speed': '0', 'max_download_speed': '0', |
1160 | + 'show_all_notifications': ''}, |
1161 | + {'device_id': '1258-6854', 'name': 'Ubuntu One @ Baz', 'type': 'Computer', |
1162 | + 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
1163 | + 'max_upload_speed': '1000', 'max_download_speed': '72548', |
1164 | + 'show_all_notifications': 'True'}, # local |
1165 | +] |
1166 | + |
1167 | + |
1168 | +class FakedObject(object): |
1169 | + """Fake an object, record every call.""" |
1170 | + |
1171 | + exposed_methods = [] |
1172 | + |
1173 | + def __init__(self, *args, **kwargs): |
1174 | + self._args = args |
1175 | + self._kwargs = kwargs |
1176 | + self._called = {} |
1177 | + for i in self.exposed_methods: |
1178 | + setattr(self, i, self._record_call(i)) |
1179 | + |
1180 | + def _record_call(self, func_name): |
1181 | + """Store values when calling 'func_name'.""" |
1182 | + |
1183 | + def inner(*args, **kwargs): |
1184 | + """Fake 'func_name'.""" |
1185 | + self._called[func_name] = (args, kwargs) |
1186 | + |
1187 | + return inner |
As with the other branch I get the following when running the tests:
E1101: 82:show_ all_notificatio ns_enabled: Instance of 'SyncDaemonTool' has no 'is_show_ all_notificatio ns_enabled' member show_all_ notifications: Instance of 'SyncDaemonTool' has no 'enable_ show_all_ notifications' member show_all_ notifications: Instance of 'SyncDaemonTool' has no 'enable_ show_all_ notifications' member get_shares_ dir: Instance of 'SyncDaemonTool' has no 'get_shares_dir' member get_shares_ dir_link: Instance of 'SyncDaemonTool' has no 'get_shares_ dir_link' member
E1101: 87:enable_
E1101: 92:disable_
E1101: 97:get_root_dir: Instance of 'SyncDaemonTool' has no 'get_root_dir' member
E1101:102:
E1101:107:
when not running the ui tests. With the ui tests I get the following:
Must run 2nd check in another process. ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == controlpanel. gui.qt. tests.test_ gui.MainWindowT estCase. test_close_ callback_ can_be_ none
=======
[ERROR]: ubuntuone.
Traceback (most recent call last): mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ tests/_ _init__ .py", line 39, in inner mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ tests/_ _init__ .py", line 80, in setUp ui(**self. kwargs) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ gui.py" , line 41, in __init__ ui.setupUi( self) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ ui/mainwindow_ ui.py", line 32, in setupUi control_ panel = ControlPanel( self.centralwid get) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ controlpanel. py", line 39, in __init__ ui.setupUi( self) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ ui/controlpanel _ui.py" , line 68, in setupUi profile_ tab = ProfilePanel() mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ profile. py", line 33, in __init__ ui.setupUi( self) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ ui/profile_ ui.py", line 77, in setupUi retranslateUi( Form) mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ ui/profile_ ui.py", line 91, in retranslateUi email_lineedit. setPlaceholderT ext(_(' <email address hidden>')) AttributeError: 'QLineEdit' object has no attribute 'setPlaceholder Text' ======= ======= ======= ======= ======= ======= ======= ======= ======= ======= == controlpanel. gui.qt. tests.test_ gui.MainWindowT estCase. test_close_ event_calls_ custom_ close_callback
File "/home/
result = test(instance)
File "/home/
self.ui = self.class_
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
self.
File "/home/
self.
exceptions.
=======
[ERROR]: ubuntuone.
Traceback (most recent call last): mandel/ Projects/ ubuntuone- control- panel/update- file-sync- status/ ubuntuone/ controlpanel/ gui/qt/ tests/_ _init__ .py", line 39, in inner
File "/home/
result = test(instance)
File "/home/mandel/P...