Merge lp:~nataliabidart/ubuntuone-control-panel/remove-devices into lp:ubuntuone-control-panel
- remove-devices
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | dobey | ||||
Approved revision: | 44 | ||||
Merged at revision: | 38 | ||||
Proposed branch: | lp:~nataliabidart/ubuntuone-control-panel/remove-devices | ||||
Merge into: | lp:ubuntuone-control-panel | ||||
Prerequisite: | lp:~nataliabidart/ubuntuone-control-panel/new-sso-iface | ||||
Diff against target: |
857 lines (+301/-79) 7 files modified
data/device.ui (+13/-11) ubuntuone/controlpanel/__init__.py (+1/-1) ubuntuone/controlpanel/backend.py (+37/-12) ubuntuone/controlpanel/gtk/gui.py (+75/-18) ubuntuone/controlpanel/gtk/tests/test_gui.py (+142/-31) ubuntuone/controlpanel/tests/test_backend.py (+26/-1) ubuntuone/controlpanel/webclient.py (+7/-5) |
||||
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-control-panel/remove-devices | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Manuel de la Peña (community) | Approve | ||
Roberto Alsina (community) | fieldtest | Approve | |
Review via email: mp+44139@code.launchpad.net |
Commit message
* Devices can now be removed (LP: #691295).
Description of the change
To run the tests, do:
./run-tests
To test IRL, open 2 terminals pointing to this branch, and run:
terminal 1: DEBUG=True PYTHONPATH=. ./bin/ubuntuone
terminal 2: DEBUG=True PYTHONPATH=. ./bin/ubuntuone
and play with the 3rd tab. The 'Remove' button is fully functional so be careful.
Among the suggested tests if removing the local device (ie the computer you're testing on). You should be taken to the overview panel after that to re-add your account.
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
The attempt to merge lp:~nataliabidart/ubuntuone-control-panel/remove-devices into lp:ubuntuone-control-panel failed. Below is the output from the failed tests.
Running test suite for ubuntuone/
ubuntuone.
BackendAccoun
test_
test_
test_
test_
test_get_token ... [OK]
BackendBasicT
test_
test_
test_get_token ... [OK]
BackendDevice
test_
test_
test_
test_
test_
test_
test_
test_
test_get_token ... [OK]
test_
test_
test_
BackendSyncSt
test_
test_
test_disabled ... [OK]
test_
test_error ... [OK]
test_get_token ... [OK]
test_idle ... [OK]
test_
test_
test_
test_
test_
test_
test_
test_
test_unknown ... ...
Preview Diff
1 | === modified file 'data/device.ui' | |||
2 | --- data/device.ui 2010-12-16 20:56:57 +0000 | |||
3 | +++ data/device.ui 2010-12-18 17:42:12 +0000 | |||
4 | @@ -2,6 +2,14 @@ | |||
5 | 2 | <interface> | 2 | <interface> |
6 | 3 | <requires lib="gtk+" version="2.16"/> | 3 | <requires lib="gtk+" version="2.16"/> |
7 | 4 | <!-- interface-naming-policy project-wide --> | 4 | <!-- interface-naming-policy project-wide --> |
8 | 5 | <object class="GtkAdjustment" id="adjustment2"> | ||
9 | 6 | <property name="upper">10000</property> | ||
10 | 7 | <property name="step_increment">1</property> | ||
11 | 8 | </object> | ||
12 | 9 | <object class="GtkAdjustment" id="adjustment1"> | ||
13 | 10 | <property name="upper">10000</property> | ||
14 | 11 | <property name="step_increment">1</property> | ||
15 | 12 | </object> | ||
16 | 5 | <object class="GtkVBox" id="itself"> | 13 | <object class="GtkVBox" id="itself"> |
17 | 6 | <property name="visible">True</property> | 14 | <property name="visible">True</property> |
18 | 7 | <property name="spacing">5</property> | 15 | <property name="spacing">5</property> |
19 | @@ -74,7 +82,7 @@ | |||
20 | 74 | <property name="can_focus">True</property> | 82 | <property name="can_focus">True</property> |
21 | 75 | <property name="receives_default">False</property> | 83 | <property name="receives_default">False</property> |
22 | 76 | <property name="draw_indicator">True</property> | 84 | <property name="draw_indicator">True</property> |
24 | 77 | <signal name="toggled" handler="on_limit_bandwidth_toggled"/> | 85 | <signal name="toggled" handler="on_limit_bandwidth_toggled" swapped="no"/> |
25 | 78 | </object> | 86 | </object> |
26 | 79 | </child> | 87 | </child> |
27 | 80 | <child> | 88 | <child> |
28 | @@ -108,7 +116,7 @@ | |||
29 | 108 | <property name="invisible_char">•</property> | 116 | <property name="invisible_char">•</property> |
30 | 109 | <property name="activates_default">True</property> | 117 | <property name="activates_default">True</property> |
31 | 110 | <property name="adjustment">adjustment1</property> | 118 | <property name="adjustment">adjustment1</property> |
33 | 111 | <signal name="value_changed" handler="on_max_upload_speed_value_changed"/> | 119 | <signal name="value-changed" handler="on_max_upload_speed_value_changed" swapped="no"/> |
34 | 112 | </object> | 120 | </object> |
35 | 113 | <packing> | 121 | <packing> |
36 | 114 | <property name="left_attach">1</property> | 122 | <property name="left_attach">1</property> |
37 | @@ -126,7 +134,7 @@ | |||
38 | 126 | <property name="invisible_char">•</property> | 134 | <property name="invisible_char">•</property> |
39 | 127 | <property name="activates_default">True</property> | 135 | <property name="activates_default">True</property> |
40 | 128 | <property name="adjustment">adjustment2</property> | 136 | <property name="adjustment">adjustment2</property> |
42 | 129 | <signal name="value_changed" handler="on_max_download_speed_value_changed"/> | 137 | <signal name="value-changed" handler="on_max_download_speed_value_changed" swapped="no"/> |
43 | 130 | </object> | 138 | </object> |
44 | 131 | <packing> | 139 | <packing> |
45 | 132 | <property name="left_attach">1</property> | 140 | <property name="left_attach">1</property> |
46 | @@ -161,6 +169,8 @@ | |||
47 | 161 | <property name="can_focus">True</property> | 169 | <property name="can_focus">True</property> |
48 | 162 | <property name="receives_default">True</property> | 170 | <property name="receives_default">True</property> |
49 | 163 | <property name="use_stock">True</property> | 171 | <property name="use_stock">True</property> |
50 | 172 | <signal name="activate" handler="on_remove_clicked" swapped="no"/> | ||
51 | 173 | <signal name="clicked" handler="on_remove_clicked" swapped="no"/> | ||
52 | 164 | </object> | 174 | </object> |
53 | 165 | <packing> | 175 | <packing> |
54 | 166 | <property name="expand">False</property> | 176 | <property name="expand">False</property> |
55 | @@ -190,12 +200,4 @@ | |||
56 | 190 | </packing> | 200 | </packing> |
57 | 191 | </child> | 201 | </child> |
58 | 192 | </object> | 202 | </object> |
59 | 193 | <object class="GtkAdjustment" id="adjustment1"> | ||
60 | 194 | <property name="upper">10000</property> | ||
61 | 195 | <property name="step_increment">1</property> | ||
62 | 196 | </object> | ||
63 | 197 | <object class="GtkAdjustment" id="adjustment2"> | ||
64 | 198 | <property name="upper">10000</property> | ||
65 | 199 | <property name="step_increment">1</property> | ||
66 | 200 | </object> | ||
67 | 201 | </interface> | 203 | </interface> |
68 | 202 | 204 | ||
69 | === modified file 'ubuntuone/controlpanel/__init__.py' | |||
70 | --- ubuntuone/controlpanel/__init__.py 2010-10-08 01:31:34 +0000 | |||
71 | +++ ubuntuone/controlpanel/__init__.py 2010-12-18 17:42:12 +0000 | |||
72 | @@ -29,4 +29,4 @@ | |||
73 | 29 | DBUS_PREFERENCES_PATH = "/preferences" | 29 | DBUS_PREFERENCES_PATH = "/preferences" |
74 | 30 | DBUS_PREFERENCES_IFACE = "com.ubuntuone.controlpanel.Preferences" | 30 | DBUS_PREFERENCES_IFACE = "com.ubuntuone.controlpanel.Preferences" |
75 | 31 | 31 | ||
77 | 32 | WEBSERVICE_BASE_URL = "https://one.ubuntu.com/api/" | 32 | WEBSERVICE_BASE_URL = u"https://one.ubuntu.com/api/" |
78 | 33 | 33 | ||
79 | === modified file 'ubuntuone/controlpanel/backend.py' | |||
80 | --- ubuntuone/controlpanel/backend.py 2010-12-18 17:42:11 +0000 | |||
81 | +++ ubuntuone/controlpanel/backend.py 2010-12-18 17:42:12 +0000 | |||
82 | @@ -49,6 +49,11 @@ | |||
83 | 49 | STATUS_KEY = 'status' | 49 | STATUS_KEY = 'status' |
84 | 50 | 50 | ||
85 | 51 | 51 | ||
86 | 52 | def bool_str(value): | ||
87 | 53 | """Return the string representation of a bool (dbus-compatible).""" | ||
88 | 54 | return 'True' if value else '' | ||
89 | 55 | |||
90 | 56 | |||
91 | 52 | class ControlBackend(object): | 57 | class ControlBackend(object): |
92 | 53 | """The control panel backend.""" | 58 | """The control panel backend.""" |
93 | 54 | 59 | ||
94 | @@ -124,6 +129,15 @@ | |||
95 | 124 | credentials = yield dbus_client.get_credentials() | 129 | credentials = yield dbus_client.get_credentials() |
96 | 125 | returnValue(credentials["token"]) | 130 | returnValue(credentials["token"]) |
97 | 126 | 131 | ||
98 | 132 | @inlineCallbacks | ||
99 | 133 | def device_is_local(self, device_id): | ||
100 | 134 | """Return whether 'device_id' is the local devicew or not.""" | ||
101 | 135 | dtype, did = self.type_n_id(device_id) | ||
102 | 136 | local_token = yield self.get_token() | ||
103 | 137 | is_local = (dtype == DEVICE_TYPE_COMPUTER and did == local_token) | ||
104 | 138 | logger.info('device_is_local: result %r, ', is_local) | ||
105 | 139 | returnValue(is_local) | ||
106 | 140 | |||
107 | 127 | @log_call(logger.debug) | 141 | @log_call(logger.debug) |
108 | 128 | @inlineCallbacks | 142 | @inlineCallbacks |
109 | 129 | def account_info(self): | 143 | def account_info(self): |
110 | @@ -146,7 +160,6 @@ | |||
111 | 146 | def devices_info(self): | 160 | def devices_info(self): |
112 | 147 | """Get the user devices info.""" | 161 | """Get the user devices info.""" |
113 | 148 | result = [] | 162 | result = [] |
114 | 149 | this_token = yield self.get_token() | ||
115 | 150 | limit_bw = yield dbus_client.bandwidth_throttling_enabled() | 163 | limit_bw = yield dbus_client.bandwidth_throttling_enabled() |
116 | 151 | limits = yield dbus_client.get_throttling_limits() | 164 | limits = yield dbus_client.get_throttling_limits() |
117 | 152 | 165 | ||
118 | @@ -159,16 +172,22 @@ | |||
119 | 159 | di["configurable"] = '' | 172 | di["configurable"] = '' |
120 | 160 | if di["type"] == DEVICE_TYPE_COMPUTER: | 173 | if di["type"] == DEVICE_TYPE_COMPUTER: |
121 | 161 | di["device_id"] = di["type"] + d["token"] | 174 | di["device_id"] = di["type"] + d["token"] |
122 | 162 | if d["token"] == this_token: | ||
123 | 163 | di["configurable"] = 'True' | ||
124 | 164 | di["limit_bandwidth"] = 'True' if limit_bw else '' | ||
125 | 165 | upload = limits["upload"] | ||
126 | 166 | download = limits["download"] | ||
127 | 167 | di[UPLOAD_KEY] = str(upload) | ||
128 | 168 | di[DOWNLOAD_KEY] = str(download) | ||
129 | 169 | if di["type"] == DEVICE_TYPE_PHONE: | 175 | if di["type"] == DEVICE_TYPE_PHONE: |
130 | 170 | di["device_id"] = di["type"] + str(d["id"]) | 176 | di["device_id"] = di["type"] + str(d["id"]) |
131 | 171 | 177 | ||
132 | 178 | is_local = yield self.device_is_local(di["device_id"]) | ||
133 | 179 | di["is_local"] = bool_str(is_local) | ||
134 | 180 | # currently, only local devices are configurable. | ||
135 | 181 | # eventually, more the devices will be configurable. | ||
136 | 182 | di["configurable"] = bool_str(is_local) | ||
137 | 183 | |||
138 | 184 | if bool(di["configurable"]): | ||
139 | 185 | di["limit_bandwidth"] = bool_str(limit_bw) | ||
140 | 186 | upload = limits["upload"] | ||
141 | 187 | download = limits["download"] | ||
142 | 188 | di[UPLOAD_KEY] = str(upload) | ||
143 | 189 | di[DOWNLOAD_KEY] = str(download) | ||
144 | 190 | |||
145 | 172 | # date_added is not in the webservice yet (LP: #673668) | 191 | # date_added is not in the webservice yet (LP: #673668) |
146 | 173 | # di["date_added"] = "" | 192 | # di["date_added"] = "" |
147 | 174 | 193 | ||
148 | @@ -190,9 +209,7 @@ | |||
149 | 190 | @inlineCallbacks | 209 | @inlineCallbacks |
150 | 191 | def change_device_settings(self, device_id, settings): | 210 | def change_device_settings(self, device_id, settings): |
151 | 192 | """Change the settings for the given device.""" | 211 | """Change the settings for the given device.""" |
155 | 193 | dtype, did = self.type_n_id(device_id) | 212 | is_local = yield self.device_is_local(device_id) |
153 | 194 | local_token = yield self.get_token() | ||
154 | 195 | is_local = (dtype == DEVICE_TYPE_COMPUTER and did == local_token) | ||
156 | 196 | 213 | ||
157 | 197 | if is_local and "limit_bandwidth" in settings: | 214 | if is_local and "limit_bandwidth" in settings: |
158 | 198 | limit_bw = bool(settings["limit_bandwidth"]) | 215 | limit_bw = bool(settings["limit_bandwidth"]) |
159 | @@ -222,8 +239,16 @@ | |||
160 | 222 | def remove_device(self, device_id): | 239 | def remove_device(self, device_id): |
161 | 223 | """Remove a device's tokens from the sso server.""" | 240 | """Remove a device's tokens from the sso server.""" |
162 | 224 | dtype, did = self.type_n_id(device_id) | 241 | dtype, did = self.type_n_id(device_id) |
164 | 225 | api = DEVICE_REMOVE_API % (dtype, did) | 242 | is_local = yield self.device_is_local(device_id) |
165 | 243 | |||
166 | 244 | api = DEVICE_REMOVE_API % (dtype.lower(), did) | ||
167 | 226 | yield self.wc.call_api(api) | 245 | yield self.wc.call_api(api) |
168 | 246 | |||
169 | 247 | if is_local: | ||
170 | 248 | logger.warning('remove_device: device is local, id %r, ' | ||
171 | 249 | 'clearing credentials.', device_id) | ||
172 | 250 | yield dbus_client.clear_credentials() | ||
173 | 251 | |||
174 | 227 | returnValue(device_id) | 252 | returnValue(device_id) |
175 | 228 | 253 | ||
176 | 229 | @log_call(logger.debug) | 254 | @log_call(logger.debug) |
177 | 230 | 255 | ||
178 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' | |||
179 | --- ubuntuone/controlpanel/gtk/gui.py 2010-12-17 17:25:10 +0000 | |||
180 | +++ ubuntuone/controlpanel/gtk/gui.py 2010-12-18 17:42:12 +0000 | |||
181 | @@ -48,7 +48,7 @@ | |||
182 | 48 | from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH, | 48 | from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH, |
183 | 49 | DBUS_PREFERENCES_IFACE) | 49 | DBUS_PREFERENCES_IFACE) |
184 | 50 | from ubuntuone.controlpanel.backend import (DEVICE_TYPE_PHONE, | 50 | from ubuntuone.controlpanel.backend import (DEVICE_TYPE_PHONE, |
186 | 51 | DEVICE_TYPE_COMPUTER) | 51 | DEVICE_TYPE_COMPUTER, bool_str) |
187 | 52 | from ubuntuone.controlpanel.logger import setup_logging, log_call | 52 | from ubuntuone.controlpanel.logger import setup_logging, log_call |
188 | 53 | from ubuntuone.controlpanel.utils import get_data_file | 53 | from ubuntuone.controlpanel.utils import get_data_file |
189 | 54 | 54 | ||
190 | @@ -74,11 +74,6 @@ | |||
191 | 74 | KILOBYTES = 1024 | 74 | KILOBYTES = 1024 |
192 | 75 | 75 | ||
193 | 76 | 76 | ||
194 | 77 | def bool_str(value): | ||
195 | 78 | """Return the string representation of a bool (dbus-compatible).""" | ||
196 | 79 | return 'True' if value else '' | ||
197 | 80 | |||
198 | 81 | |||
199 | 82 | def filter_by_app_name(f): | 77 | def filter_by_app_name(f): |
200 | 83 | """Excecute 'f' filtering by app_name.""" | 78 | """Excecute 'f' filtering by app_name.""" |
201 | 84 | 79 | ||
202 | @@ -187,15 +182,23 @@ | |||
203 | 187 | self._window_id = window_id | 182 | self._window_id = window_id |
204 | 188 | 183 | ||
205 | 189 | self.management = None | 184 | self.management = None |
207 | 190 | self.overview = OverviewPanel(window_id=window_id) | 185 | self.overview = None |
208 | 186 | self.on_show_overview_panel() | ||
209 | 187 | self.show() | ||
210 | 188 | |||
211 | 189 | def on_show_overview_panel(self, widget=None): | ||
212 | 190 | """Show the overview panel.""" | ||
213 | 191 | for child in self.get_children(): | ||
214 | 192 | self.remove(child) | ||
215 | 193 | |||
216 | 194 | self.overview = OverviewPanel(window_id=self._window_id) | ||
217 | 191 | self.overview.connect('credentials-found', | 195 | self.overview.connect('credentials-found', |
218 | 192 | self.on_show_management_panel) | 196 | self.on_show_management_panel) |
219 | 193 | self.add(self.overview) | 197 | self.add(self.overview) |
220 | 194 | self.show() | ||
221 | 195 | 198 | ||
222 | 196 | def on_show_management_panel(self, widget=None, | 199 | def on_show_management_panel(self, widget=None, |
223 | 197 | credentials_are_new=False, token=None): | 200 | credentials_are_new=False, token=None): |
225 | 198 | """Show the netbook (main panel).""" | 201 | """Show the notebook (main panel).""" |
226 | 199 | if self.overview in self.get_children(): | 202 | if self.overview in self.get_children(): |
227 | 200 | self.remove(self.overview) | 203 | self.remove(self.overview) |
228 | 201 | 204 | ||
229 | @@ -206,6 +209,9 @@ | |||
230 | 206 | 209 | ||
231 | 207 | self.add(self.management) | 210 | self.add(self.management) |
232 | 208 | 211 | ||
233 | 212 | self.management.connect('local-device-removed', | ||
234 | 213 | self.on_show_overview_panel) | ||
235 | 214 | |||
236 | 209 | 215 | ||
237 | 210 | class UbuntuOneBin(gtk.VBox): | 216 | class UbuntuOneBin(gtk.VBox): |
238 | 211 | """A Ubuntu One bin.""" | 217 | """A Ubuntu One bin.""" |
239 | @@ -505,10 +511,11 @@ | |||
240 | 505 | 511 | ||
241 | 506 | 512 | ||
242 | 507 | class Device(gtk.VBox, ControlPanelMixin): | 513 | class Device(gtk.VBox, ControlPanelMixin): |
244 | 508 | """The devices panel.""" | 514 | """The device widget.""" |
245 | 509 | 515 | ||
246 | 510 | DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n' | 516 | DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n' |
247 | 511 | 'previous values were restored.') | 517 | 'previous values were restored.') |
248 | 518 | DEVICE_REMOVAL_ERROR = _('The device could not be removed.') | ||
249 | 512 | 519 | ||
250 | 513 | def __init__(self): | 520 | def __init__(self): |
251 | 514 | gtk.VBox.__init__(self) | 521 | gtk.VBox.__init__(self) |
252 | @@ -516,19 +523,25 @@ | |||
253 | 516 | 523 | ||
254 | 517 | self._updating = False | 524 | self._updating = False |
255 | 518 | self._last_settings = {} | 525 | self._last_settings = {} |
256 | 526 | self.id = None | ||
257 | 527 | self.is_local = False | ||
258 | 519 | self.configurable = False | 528 | self.configurable = False |
259 | 520 | 529 | ||
261 | 521 | self.update(device_id='', device_name='', limit_bandwidth=False, | 530 | self.update(device_id=None, device_name='', |
262 | 531 | is_local=False, configurable=False, limit_bandwidth=False, | ||
263 | 522 | max_upload_speed=0, max_download_speed=0) | 532 | max_upload_speed=0, max_download_speed=0) |
264 | 523 | 533 | ||
265 | 524 | self.add(self.itself) | 534 | self.add(self.itself) |
266 | 525 | self.device_id.hide() | ||
267 | 526 | self.show() | 535 | self.show() |
268 | 527 | 536 | ||
269 | 528 | self.backend.connect_to_signal('DeviceSettingsChanged', | 537 | self.backend.connect_to_signal('DeviceSettingsChanged', |
270 | 529 | self.on_device_settings_changed) | 538 | self.on_device_settings_changed) |
271 | 530 | self.backend.connect_to_signal('DeviceSettingsChangeError', | 539 | self.backend.connect_to_signal('DeviceSettingsChangeError', |
272 | 531 | self.on_device_settings_change_error) | 540 | self.on_device_settings_change_error) |
273 | 541 | self.backend.connect_to_signal('DeviceRemoved', | ||
274 | 542 | self.on_device_removed) | ||
275 | 543 | self.backend.connect_to_signal('DeviceRemovalError', | ||
276 | 544 | self.on_device_removal_error) | ||
277 | 532 | 545 | ||
278 | 533 | def _change_device_settings(self, *args): | 546 | def _change_device_settings(self, *args): |
279 | 534 | """Update backend settings for this device.""" | 547 | """Update backend settings for this device.""" |
280 | @@ -538,8 +551,7 @@ | |||
281 | 538 | # Not disabling the GUI to avoid annyong twitchings | 551 | # Not disabling the GUI to avoid annyong twitchings |
282 | 539 | #self.set_sensitive(False) | 552 | #self.set_sensitive(False) |
283 | 540 | self.warning_label.set_text('') | 553 | self.warning_label.set_text('') |
286 | 541 | self.backend.change_device_settings(self.device_id.get_text(), | 554 | self.backend.change_device_settings(self.id, self.__dict__) |
285 | 542 | self.__dict__) | ||
287 | 543 | 555 | ||
288 | 544 | def _block_signals(f): | 556 | def _block_signals(f): |
289 | 545 | """Execute 'f' while having the _updating flag set.""" | 557 | """Execute 'f' while having the _updating flag set.""" |
290 | @@ -563,6 +575,11 @@ | |||
291 | 563 | on_max_upload_speed_value_changed = _change_device_settings | 575 | on_max_upload_speed_value_changed = _change_device_settings |
292 | 564 | on_max_download_speed_value_changed = _change_device_settings | 576 | on_max_download_speed_value_changed = _change_device_settings |
293 | 565 | 577 | ||
294 | 578 | def on_remove_clicked(self, widget): | ||
295 | 579 | """Remove button was clicked or activated.""" | ||
296 | 580 | self.backend.remove_device(self.id) | ||
297 | 581 | self.set_sensitive(False) | ||
298 | 582 | |||
299 | 566 | @_block_signals | 583 | @_block_signals |
300 | 567 | def update(self, **kwargs): | 584 | def update(self, **kwargs): |
301 | 568 | """Update according to named parameters. | 585 | """Update according to named parameters. |
302 | @@ -571,6 +588,7 @@ | |||
303 | 571 | * device_id (string, not shown to the user) | 588 | * device_id (string, not shown to the user) |
304 | 572 | * device_name (string) | 589 | * device_name (string) |
305 | 573 | * type (either DEVICE_TYPE_PHONE or DEVICE_TYPE_COMPUTER) | 590 | * type (either DEVICE_TYPE_PHONE or DEVICE_TYPE_COMPUTER) |
306 | 591 | * is_local (True/False) | ||
307 | 574 | * configurable (True/False) | 592 | * configurable (True/False) |
308 | 575 | * if configurable, the following can be set: | 593 | * if configurable, the following can be set: |
309 | 576 | * limit_bandwidth (True/False) | 594 | * limit_bandwidth (True/False) |
310 | @@ -579,7 +597,7 @@ | |||
311 | 579 | 597 | ||
312 | 580 | """ | 598 | """ |
313 | 581 | if 'device_id' in kwargs: | 599 | if 'device_id' in kwargs: |
315 | 582 | self.device_id.set_text(kwargs['device_id']) | 600 | self.id = kwargs['device_id'] |
316 | 583 | 601 | ||
317 | 584 | if 'device_name' in kwargs: | 602 | if 'device_name' in kwargs: |
318 | 585 | self.device_name.set_markup('<b>%s</b>' % kwargs['device_name']) | 603 | self.device_name.set_markup('<b>%s</b>' % kwargs['device_name']) |
319 | @@ -590,6 +608,9 @@ | |||
320 | 590 | self.device_type.set_from_icon_name(dtype.lower(), | 608 | self.device_type.set_from_icon_name(dtype.lower(), |
321 | 591 | gtk.ICON_SIZE_BUTTON) | 609 | gtk.ICON_SIZE_BUTTON) |
322 | 592 | 610 | ||
323 | 611 | if 'is_local' in kwargs: | ||
324 | 612 | self.is_local = bool(kwargs['is_local']) | ||
325 | 613 | |||
326 | 593 | if 'configurable' in kwargs: | 614 | if 'configurable' in kwargs: |
327 | 594 | self.configurable = bool(kwargs['configurable']) | 615 | self.configurable = bool(kwargs['configurable']) |
328 | 595 | self.throttling.set_visible(self.configurable) | 616 | self.throttling.set_visible(self.configurable) |
329 | @@ -607,9 +628,10 @@ | |||
330 | 607 | @property | 628 | @property |
331 | 608 | def __dict__(self): | 629 | def __dict__(self): |
332 | 609 | result = { | 630 | result = { |
334 | 610 | 'device_id': self.device_id.get_text(), | 631 | 'device_id': self.id, |
335 | 611 | 'device_name': self.device_name.get_text(), | 632 | 'device_name': self.device_name.get_text(), |
336 | 612 | 'device_type': self.device_type.get_icon_name()[0].capitalize(), | 633 | 'device_type': self.device_type.get_icon_name()[0].capitalize(), |
337 | 634 | 'is_local': bool_str(self.is_local), | ||
338 | 613 | 'configurable': bool_str(self.configurable), | 635 | 'configurable': bool_str(self.configurable), |
339 | 614 | 'limit_bandwidth': bool_str(self.limit_bandwidth.get_active()), | 636 | 'limit_bandwidth': bool_str(self.limit_bandwidth.get_active()), |
340 | 615 | 'max_upload_speed': \ | 637 | 'max_upload_speed': \ |
341 | @@ -622,7 +644,7 @@ | |||
342 | 622 | @log_call(logger.info) | 644 | @log_call(logger.info) |
343 | 623 | def on_device_settings_changed(self, device_id): | 645 | def on_device_settings_changed(self, device_id): |
344 | 624 | """The change of this device settings succeded.""" | 646 | """The change of this device settings succeded.""" |
346 | 625 | if device_id != self.device_id.get_text(): | 647 | if device_id != self.id: |
347 | 626 | return | 648 | return |
348 | 627 | self.set_sensitive(True) | 649 | self.set_sensitive(True) |
349 | 628 | self.warning_label.set_text('') | 650 | self.warning_label.set_text('') |
350 | @@ -631,12 +653,27 @@ | |||
351 | 631 | @log_call(logger.error) | 653 | @log_call(logger.error) |
352 | 632 | def on_device_settings_change_error(self, device_id, error_dict=None): | 654 | def on_device_settings_change_error(self, device_id, error_dict=None): |
353 | 633 | """The change of this device settings failed.""" | 655 | """The change of this device settings failed.""" |
355 | 634 | if device_id != self.device_id.get_text(): | 656 | if device_id != self.id: |
356 | 635 | return | 657 | return |
357 | 636 | self.update(**self._last_settings) | 658 | self.update(**self._last_settings) |
358 | 637 | self._set_warning(self.DEVICE_CHANGE_ERROR, self.warning_label) | 659 | self._set_warning(self.DEVICE_CHANGE_ERROR, self.warning_label) |
359 | 638 | self.set_sensitive(True) | 660 | self.set_sensitive(True) |
360 | 639 | 661 | ||
361 | 662 | @log_call(logger.warning) | ||
362 | 663 | def on_device_removed(self, device_id): | ||
363 | 664 | """The removal of this device succeded.""" | ||
364 | 665 | if device_id != self.id: | ||
365 | 666 | return | ||
366 | 667 | self.hide() | ||
367 | 668 | |||
368 | 669 | @log_call(logger.error) | ||
369 | 670 | def on_device_removal_error(self, device_id, error_dict=None): | ||
370 | 671 | """The removal of this device failed.""" | ||
371 | 672 | if device_id != self.id: | ||
372 | 673 | return | ||
373 | 674 | self._set_warning(self.DEVICE_REMOVAL_ERROR, self.warning_label) | ||
374 | 675 | self.set_sensitive(True) | ||
375 | 676 | |||
376 | 640 | 677 | ||
377 | 641 | class DevicesPanel(UbuntuOneBin, ControlPanelMixin): | 678 | class DevicesPanel(UbuntuOneBin, ControlPanelMixin): |
378 | 642 | """The devices panel.""" | 679 | """The devices panel.""" |
379 | @@ -650,10 +687,14 @@ | |||
380 | 650 | self.add(self.itself) | 687 | self.add(self.itself) |
381 | 651 | self.show() | 688 | self.show() |
382 | 652 | 689 | ||
383 | 690 | self._devices = {} | ||
384 | 691 | |||
385 | 653 | self.backend.connect_to_signal('DevicesInfoReady', | 692 | self.backend.connect_to_signal('DevicesInfoReady', |
386 | 654 | self.on_devices_info_ready) | 693 | self.on_devices_info_ready) |
387 | 655 | self.backend.connect_to_signal('DevicesInfoError', | 694 | self.backend.connect_to_signal('DevicesInfoError', |
388 | 656 | self.on_devices_info_error) | 695 | self.on_devices_info_error) |
389 | 696 | self.backend.connect_to_signal('DeviceRemoved', | ||
390 | 697 | self.on_device_removed) | ||
391 | 657 | self.backend.devices_info() | 698 | self.backend.devices_info() |
392 | 658 | 699 | ||
393 | 659 | def on_devices_info_ready(self, info): | 700 | def on_devices_info_ready(self, info): |
394 | @@ -665,11 +706,22 @@ | |||
395 | 665 | DEVICE_TYPE_COMPUTER) | 706 | DEVICE_TYPE_COMPUTER) |
396 | 666 | device.update(**device_info) | 707 | device.update(**device_info) |
397 | 667 | self.devices.pack_start(device) | 708 | self.devices.pack_start(device) |
398 | 709 | self._devices[device.id] = device | ||
399 | 668 | 710 | ||
400 | 669 | @log_call(logger.error) | 711 | @log_call(logger.error) |
401 | 670 | def on_devices_info_error(self, error_dict=None): | 712 | def on_devices_info_error(self, error_dict=None): |
402 | 671 | """Backend notifies of an error when fetching volumes info.""" | 713 | """Backend notifies of an error when fetching volumes info.""" |
403 | 672 | 714 | ||
404 | 715 | @log_call(logger.warning) | ||
405 | 716 | def on_device_removed(self, device_id): | ||
406 | 717 | """The removal of a device succeded.""" | ||
407 | 718 | if device_id in self._devices: | ||
408 | 719 | child = self._devices.pop(device_id) | ||
409 | 720 | self.devices.remove(child) | ||
410 | 721 | |||
411 | 722 | if child.is_local: | ||
412 | 723 | self.emit('local-device-removed') | ||
413 | 724 | |||
414 | 673 | 725 | ||
415 | 674 | class ApplicationsPanel(UbuntuOneBin, ControlPanelMixin): | 726 | class ApplicationsPanel(UbuntuOneBin, ControlPanelMixin): |
416 | 675 | """The applications panel.""" | 727 | """The applications panel.""" |
417 | @@ -750,6 +802,8 @@ | |||
418 | 750 | self.notebook.insert_page(getattr(self, tab), position=page_num) | 802 | self.notebook.insert_page(getattr(self, tab), position=page_num) |
419 | 751 | 803 | ||
420 | 752 | self.folders_button.connect('clicked', lambda b: self.folders.load()) | 804 | self.folders_button.connect('clicked', lambda b: self.folders.load()) |
421 | 805 | sig = 'local-device-removed' | ||
422 | 806 | self.devices.connect(sig, lambda widget: self.emit(sig)) | ||
423 | 753 | 807 | ||
424 | 754 | self.backend.account_info() | 808 | self.backend.account_info() |
425 | 755 | self.backend.file_sync_status() | 809 | self.backend.file_sync_status() |
426 | @@ -818,3 +872,6 @@ | |||
427 | 818 | gobject.signal_new('credentials-found', OverviewPanel, | 872 | gobject.signal_new('credentials-found', OverviewPanel, |
428 | 819 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, | 873 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, |
429 | 820 | (gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT)) | 874 | (gobject.TYPE_BOOLEAN, gobject.TYPE_PYOBJECT)) |
430 | 875 | |||
431 | 876 | gobject.signal_new('local-device-removed', DevicesPanel, | ||
432 | 877 | gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()) | ||
433 | 821 | 878 | ||
434 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' | |||
435 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2010-12-17 17:25:10 +0000 | |||
436 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2010-12-18 17:42:12 +0000 | |||
437 | @@ -47,19 +47,21 @@ | |||
438 | 47 | 47 | ||
439 | 48 | FAKE_DEVICE_INFO = { | 48 | FAKE_DEVICE_INFO = { |
440 | 49 | 'device_id': '1258-6854', 'device_name': 'Baz', 'device_type': 'Computer', | 49 | 'device_id': '1258-6854', 'device_name': 'Baz', 'device_type': 'Computer', |
442 | 50 | 'configurable': 'True', 'limit_bandwidth': 'True', | 50 | 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
443 | 51 | 'max_upload_speed': '1000', 'max_download_speed': '72548', | 51 | 'max_upload_speed': '1000', 'max_download_speed': '72548', |
444 | 52 | } | 52 | } |
445 | 53 | 53 | ||
446 | 54 | FAKE_DEVICES_INFO = [ | 54 | FAKE_DEVICES_INFO = [ |
449 | 55 | {'device_id': '0', 'name': 'Foo', 'type': 'Computer', 'configurable': ''}, | 55 | {'device_id': '0', 'name': 'Foo', 'type': 'Computer', |
450 | 56 | {'device_id': '1', 'name': 'Bar', 'type': 'Phone', 'configurable': ''}, | 56 | 'is_local': '', 'configurable': ''}, |
451 | 57 | {'device_id': '1', 'name': 'Bar', 'type': 'Phone', | ||
452 | 58 | 'is_local': '', 'configurable': ''}, | ||
453 | 57 | {'device_id': '2', 'name': 'Z', 'type': 'Computer', | 59 | {'device_id': '2', 'name': 'Z', 'type': 'Computer', |
455 | 58 | 'configurable': 'True', 'limit_bandwidth': '', | 60 | 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '', |
456 | 59 | 'max_upload_speed': '0', 'max_download_speed': '0'}, | 61 | 'max_upload_speed': '0', 'max_download_speed': '0'}, |
457 | 60 | {'device_id': '1258-6854', 'name': 'Baz', 'type': 'Computer', | 62 | {'device_id': '1258-6854', 'name': 'Baz', 'type': 'Computer', |
460 | 61 | 'configurable': 'True', 'limit_bandwidth': 'True', | 63 | 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True', |
461 | 62 | 'max_upload_speed': '1000', 'max_download_speed': '72548'}, | 64 | 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local |
462 | 63 | ] | 65 | ] |
463 | 64 | 66 | ||
464 | 65 | 67 | ||
465 | @@ -128,6 +130,7 @@ | |||
466 | 128 | exposed_methods = [ | 130 | exposed_methods = [ |
467 | 129 | 'account_info', 'devices_info', 'change_device_settings', | 131 | 'account_info', 'devices_info', 'change_device_settings', |
468 | 130 | 'volumes_info', 'change_volume_settings', 'file_sync_status', | 132 | 'volumes_info', 'change_volume_settings', 'file_sync_status', |
469 | 133 | 'remove_device', | ||
470 | 131 | ] | 134 | ] |
471 | 132 | 135 | ||
472 | 133 | 136 | ||
473 | @@ -356,6 +359,15 @@ | |||
474 | 356 | self.assertEqual(self.ui.management.notebook.get_current_page(), | 359 | self.assertEqual(self.ui.management.notebook.get_current_page(), |
475 | 357 | self.ui.management.FOLDERS_PAGE) | 360 | self.ui.management.FOLDERS_PAGE) |
476 | 358 | 361 | ||
477 | 362 | def test_local_device_removed_shows_overview_panel(self): | ||
478 | 363 | """On 'local-device-removed' signal, the overview panel is shown.""" | ||
479 | 364 | self.ui.overview.emit('credentials-found', True, object()) | ||
480 | 365 | self.ui.management.emit('local-device-removed') | ||
481 | 366 | |||
482 | 367 | children = self.ui.get_children() | ||
483 | 368 | self.assertEqual(1, len(children)) | ||
484 | 369 | self.assertTrue(children[0] is self.ui.overview) | ||
485 | 370 | |||
486 | 359 | 371 | ||
487 | 360 | class UbuntuOneBinTestCase(BaseTestCase): | 372 | class UbuntuOneBinTestCase(BaseTestCase): |
488 | 361 | """The test suite for a Ubuntu One panel.""" | 373 | """The test suite for a Ubuntu One panel.""" |
489 | @@ -907,12 +919,14 @@ | |||
490 | 907 | 919 | ||
491 | 908 | def assert_device_equal(self, device, expected): | 920 | def assert_device_equal(self, device, expected): |
492 | 909 | """Assert that the device has the values from expected.""" | 921 | """Assert that the device has the values from expected.""" |
494 | 910 | self.assertEqual(device.device_id.get_text(), | 922 | self.assertEqual(device.id, |
495 | 911 | expected['device_id']) | 923 | expected['device_id']) |
496 | 912 | self.assertEqual(device.device_name.get_text(), | 924 | self.assertEqual(device.device_name.get_text(), |
497 | 913 | expected['device_name']) | 925 | expected['device_name']) |
498 | 914 | self.assertEqual(device.device_type.get_icon_name()[0], | 926 | self.assertEqual(device.device_type.get_icon_name()[0], |
499 | 915 | expected['device_type'].lower()) | 927 | expected['device_type'].lower()) |
500 | 928 | self.assertEqual(device.is_local, | ||
501 | 929 | bool(expected['is_local'])) | ||
502 | 916 | self.assertEqual(device.configurable, | 930 | self.assertEqual(device.configurable, |
503 | 917 | bool(expected['configurable'])) | 931 | bool(expected['configurable'])) |
504 | 918 | self.assertEqual(device.limit_bandwidth.get_active(), | 932 | self.assertEqual(device.limit_bandwidth.get_active(), |
505 | @@ -927,7 +941,7 @@ | |||
506 | 927 | """Changing throttling settings updates the backend properly.""" | 941 | """Changing throttling settings updates the backend properly.""" |
507 | 928 | expected = self.ui.__dict__ | 942 | expected = self.ui.__dict__ |
508 | 929 | self.assert_backend_called('change_device_settings', | 943 | self.assert_backend_called('change_device_settings', |
510 | 930 | (self.ui.device_id.get_text(), expected)) | 944 | (self.ui.id, expected)) |
511 | 931 | self.assertEqual(self.ui.warning_label.get_text(), '') | 945 | self.assertEqual(self.ui.warning_label.get_text(), '') |
512 | 932 | 946 | ||
513 | 933 | def modify_settings(self): | 947 | def modify_settings(self): |
514 | @@ -961,16 +975,13 @@ | |||
515 | 961 | """The warning label is cleared.""" | 975 | """The warning label is cleared.""" |
516 | 962 | self.assertEqual(self.ui.warning_label.get_text(), '') | 976 | self.assertEqual(self.ui.warning_label.get_text(), '') |
517 | 963 | 977 | ||
518 | 964 | def test_device_id_is_hidden(self): | ||
519 | 965 | """The device id label is hidden.""" | ||
520 | 966 | self.assertFalse(self.ui.device_id.get_visible()) | ||
521 | 967 | |||
522 | 968 | def test_default_values(self): | 978 | def test_default_values(self): |
523 | 969 | """Default values are correct.""" | 979 | """Default values are correct.""" |
525 | 970 | self.assertEqual(self.ui.device_id.get_text(), '') | 980 | self.assertEqual(self.ui.id, None) |
526 | 971 | self.assertEqual(self.ui.device_name.get_text(), '') | 981 | self.assertEqual(self.ui.device_name.get_text(), '') |
527 | 972 | self.assertEqual(self.ui.device_type.get_icon_name()[0], | 982 | self.assertEqual(self.ui.device_type.get_icon_name()[0], |
528 | 973 | gui.DEVICE_TYPE_COMPUTER.lower()) | 983 | gui.DEVICE_TYPE_COMPUTER.lower()) |
529 | 984 | self.assertEqual(self.ui.is_local, False) | ||
530 | 974 | self.assertEqual(self.ui.configurable, False) | 985 | self.assertEqual(self.ui.configurable, False) |
531 | 975 | self.assertEqual(self.ui.limit_bandwidth.get_active(), False) | 986 | self.assertEqual(self.ui.limit_bandwidth.get_active(), False) |
532 | 976 | self.assertEqual(self.ui.max_upload_speed.get_value_as_int(), 0) | 987 | self.assertEqual(self.ui.max_upload_speed.get_value_as_int(), 0) |
533 | @@ -980,12 +991,6 @@ | |||
534 | 980 | """When updating, the backend is not called.""" | 991 | """When updating, the backend is not called.""" |
535 | 981 | self.assertEqual(self.ui.backend._called, {}) | 992 | self.assertEqual(self.ui.backend._called, {}) |
536 | 982 | 993 | ||
537 | 983 | def test_update_device_id(self): | ||
538 | 984 | """A device can be updated from a dict.""" | ||
539 | 985 | value = '741-822-963' | ||
540 | 986 | self.ui.update(device_id=value) | ||
541 | 987 | self.assertEqual(value, self.ui.device_id.get_text()) | ||
542 | 988 | |||
543 | 989 | def test_update_device_name(self): | 994 | def test_update_device_name(self): |
544 | 990 | """A device can be updated from a dict.""" | 995 | """A device can be updated from a dict.""" |
545 | 991 | value = 'The death star' | 996 | value = 'The death star' |
546 | @@ -1012,13 +1017,23 @@ | |||
547 | 1012 | self.assertEqual((dtype.lower(), gui.gtk.ICON_SIZE_BUTTON), | 1017 | self.assertEqual((dtype.lower(), gui.gtk.ICON_SIZE_BUTTON), |
548 | 1013 | self.ui.device_type.get_icon_name()) | 1018 | self.ui.device_type.get_icon_name()) |
549 | 1014 | 1019 | ||
551 | 1015 | def test_update_configurable(self): | 1020 | def test_update_is_not_local(self): |
552 | 1021 | """A device can be updated from a dict.""" | ||
553 | 1022 | self.ui.update(is_local='') | ||
554 | 1023 | self.assertFalse(self.ui.is_local) | ||
555 | 1024 | |||
556 | 1025 | def test_update_is_local(self): | ||
557 | 1026 | """A device can be updated from a dict.""" | ||
558 | 1027 | self.ui.update(is_local='True') | ||
559 | 1028 | self.assertTrue(self.ui.is_local) | ||
560 | 1029 | |||
561 | 1030 | def test_update_non_configurable(self): | ||
562 | 1016 | """A device can be updated from a dict.""" | 1031 | """A device can be updated from a dict.""" |
563 | 1017 | self.ui.update(configurable='') | 1032 | self.ui.update(configurable='') |
564 | 1018 | self.assertFalse(self.ui.configurable) | 1033 | self.assertFalse(self.ui.configurable) |
565 | 1019 | self.assertFalse(self.ui.throttling.get_visible()) | 1034 | self.assertFalse(self.ui.throttling.get_visible()) |
566 | 1020 | 1035 | ||
568 | 1021 | def test_update_non_configurable(self): | 1036 | def test_update_configurable(self): |
569 | 1022 | """A device can be updated from a dict.""" | 1037 | """A device can be updated from a dict.""" |
570 | 1023 | self.ui.update(configurable='True') | 1038 | self.ui.update(configurable='True') |
571 | 1024 | self.assertTrue(self.ui.configurable) | 1039 | self.assertTrue(self.ui.configurable) |
572 | @@ -1073,12 +1088,15 @@ | |||
573 | 1073 | [self.ui.on_device_settings_changed]) | 1088 | [self.ui.on_device_settings_changed]) |
574 | 1074 | self.assertEqual(self.ui.backend._signals['DeviceSettingsChangeError'], | 1089 | self.assertEqual(self.ui.backend._signals['DeviceSettingsChangeError'], |
575 | 1075 | [self.ui.on_device_settings_change_error]) | 1090 | [self.ui.on_device_settings_change_error]) |
576 | 1091 | self.assertEqual(self.ui.backend._signals['DeviceRemoved'], | ||
577 | 1092 | [self.ui.on_device_removed]) | ||
578 | 1093 | self.assertEqual(self.ui.backend._signals['DeviceRemovalError'], | ||
579 | 1094 | [self.ui.on_device_removal_error]) | ||
580 | 1076 | 1095 | ||
581 | 1077 | def test_on_device_settings_changed(self): | 1096 | def test_on_device_settings_changed(self): |
582 | 1078 | """When settings were changed for this device, enable it.""" | 1097 | """When settings were changed for this device, enable it.""" |
583 | 1079 | self.modify_settings() | 1098 | self.modify_settings() |
586 | 1080 | did = self.ui.device_id.get_text() | 1099 | self.ui.on_device_settings_changed(device_id=self.ui.id) |
585 | 1081 | self.ui.on_device_settings_changed(device_id=did) | ||
587 | 1082 | 1100 | ||
588 | 1083 | self.assertTrue(self.ui.get_sensitive()) | 1101 | self.assertTrue(self.ui.get_sensitive()) |
589 | 1084 | self.assertEqual(self.ui.warning_label.get_text(), '') | 1102 | self.assertEqual(self.ui.warning_label.get_text(), '') |
590 | @@ -1087,8 +1105,7 @@ | |||
591 | 1087 | def test_on_device_settings_change_after_error(self): | 1105 | def test_on_device_settings_change_after_error(self): |
592 | 1088 | """Change success after error.""" | 1106 | """Change success after error.""" |
593 | 1089 | self.modify_settings() | 1107 | self.modify_settings() |
596 | 1090 | did = self.ui.device_id.get_text() | 1108 | self.ui.on_device_settings_change_error(device_id=self.ui.id) # error |
595 | 1091 | self.ui.on_device_settings_change_error(device_id=did) # change failed | ||
597 | 1092 | 1109 | ||
598 | 1093 | self.test_on_device_settings_changed() | 1110 | self.test_on_device_settings_changed() |
599 | 1094 | 1111 | ||
600 | @@ -1109,8 +1126,7 @@ | |||
601 | 1109 | 1126 | ||
602 | 1110 | self.modify_settings() | 1127 | self.modify_settings() |
603 | 1111 | 1128 | ||
606 | 1112 | did = self.ui.device_id.get_text() | 1129 | self.ui.on_device_settings_change_error(device_id=self.ui.id) # error |
605 | 1113 | self.ui.on_device_settings_change_error(device_id=did) # change failed | ||
607 | 1114 | 1130 | ||
608 | 1115 | self.assertTrue(self.ui.get_sensitive()) | 1131 | self.assertTrue(self.ui.get_sensitive()) |
609 | 1116 | self.assert_warning_correct(self.ui.warning_label, | 1132 | self.assert_warning_correct(self.ui.warning_label, |
610 | @@ -1120,8 +1136,7 @@ | |||
611 | 1120 | def test_on_device_settings_change_error_after_success(self): | 1136 | def test_on_device_settings_change_error_after_success(self): |
612 | 1121 | """Change error after success.""" | 1137 | """Change error after success.""" |
613 | 1122 | self.modify_settings() | 1138 | self.modify_settings() |
616 | 1123 | did = self.ui.device_id.get_text() | 1139 | self.ui.on_device_settings_changed(device_id=self.ui.id) |
615 | 1124 | self.ui.on_device_settings_changed(device_id=did) | ||
617 | 1125 | 1140 | ||
618 | 1126 | self.test_on_device_settings_change_error() | 1141 | self.test_on_device_settings_change_error() |
619 | 1127 | 1142 | ||
620 | @@ -1131,6 +1146,49 @@ | |||
621 | 1131 | self.ui.on_device_settings_change_error(device_id='yudo') | 1146 | self.ui.on_device_settings_change_error(device_id='yudo') |
622 | 1132 | self.assertEqual(self.ui.warning_label.get_text(), '') | 1147 | self.assertEqual(self.ui.warning_label.get_text(), '') |
623 | 1133 | 1148 | ||
624 | 1149 | def test_remove(self): | ||
625 | 1150 | """Clicking on remove calls the backend properly.""" | ||
626 | 1151 | self.ui.is_local = False | ||
627 | 1152 | self.ui.remove.clicked() | ||
628 | 1153 | |||
629 | 1154 | self.assert_backend_called('remove_device', (self.ui.id,)) | ||
630 | 1155 | self.assertFalse(self.ui.get_sensitive(), | ||
631 | 1156 | 'Must be disabled while removing.') | ||
632 | 1157 | |||
633 | 1158 | def test_on_device_removed(self): | ||
634 | 1159 | """On this device removed, hide and destroy.""" | ||
635 | 1160 | self.ui.remove.clicked() | ||
636 | 1161 | self.ui.on_device_removed(device_id=self.ui.id) | ||
637 | 1162 | |||
638 | 1163 | self.assertFalse(self.ui.get_visible(), | ||
639 | 1164 | 'Must not be visible after removed.') | ||
640 | 1165 | |||
641 | 1166 | def test_on_device_removed_other_id(self): | ||
642 | 1167 | """On other device removed, do nothing.""" | ||
643 | 1168 | self.ui.remove.clicked() | ||
644 | 1169 | self.ui.on_device_removed(device_id='foo') | ||
645 | 1170 | |||
646 | 1171 | self.assertTrue(self.ui.get_visible(), | ||
647 | 1172 | 'Must be visible after other device was removed.') | ||
648 | 1173 | |||
649 | 1174 | def test_on_device_removal_error(self): | ||
650 | 1175 | """On this device removal error, re-enable and show error.""" | ||
651 | 1176 | self.ui.remove.clicked() | ||
652 | 1177 | self.ui.on_device_removal_error(device_id=self.ui.id) | ||
653 | 1178 | |||
654 | 1179 | self.assertTrue(self.ui.get_sensitive(), | ||
655 | 1180 | 'Must be enabled after removal error.') | ||
656 | 1181 | self.assert_warning_correct(self.ui.warning_label, | ||
657 | 1182 | self.ui.DEVICE_REMOVAL_ERROR) | ||
658 | 1183 | |||
659 | 1184 | def test_on_device_removal_error_other_id(self): | ||
660 | 1185 | """On other device removal error, do nothing.""" | ||
661 | 1186 | self.ui.remove.clicked() | ||
662 | 1187 | self.ui.on_device_removal_error(device_id='foo') | ||
663 | 1188 | |||
664 | 1189 | self.assertFalse(self.ui.get_sensitive(), | ||
665 | 1190 | 'Must be disabled after other device removal error.') | ||
666 | 1191 | |||
667 | 1134 | 1192 | ||
668 | 1135 | class DevicesTestCase(ControlPanelMixinTestCase): | 1193 | class DevicesTestCase(ControlPanelMixinTestCase): |
669 | 1136 | """The test suite for the devices panel.""" | 1194 | """The test suite for the devices panel.""" |
670 | @@ -1156,6 +1214,8 @@ | |||
671 | 1156 | [self.ui.on_devices_info_ready]) | 1214 | [self.ui.on_devices_info_ready]) |
672 | 1157 | self.assertEqual(self.ui.backend._signals['DevicesInfoError'], | 1215 | self.assertEqual(self.ui.backend._signals['DevicesInfoError'], |
673 | 1158 | [self.ui.on_devices_info_error]) | 1216 | [self.ui.on_devices_info_error]) |
674 | 1217 | self.assertEqual(self.ui.backend._signals['DeviceRemoved'], | ||
675 | 1218 | [self.ui.on_device_removed]) | ||
676 | 1159 | 1219 | ||
677 | 1160 | def test_devices_info_is_requested(self): | 1220 | def test_devices_info_is_requested(self): |
678 | 1161 | """The devices info is requested to the backend.""" | 1221 | """The devices info is requested to the backend.""" |
679 | @@ -1171,12 +1231,13 @@ | |||
680 | 1171 | for child, device in zip(children, FAKE_DEVICES_INFO): | 1231 | for child, device in zip(children, FAKE_DEVICES_INFO): |
681 | 1172 | self.assertIsInstance(child, gui.Device) | 1232 | self.assertIsInstance(child, gui.Device) |
682 | 1173 | 1233 | ||
685 | 1174 | self.assertEqual(device['device_id'], | 1234 | self.assertEqual(device['device_id'], child.id) |
684 | 1175 | child.device_id.get_text()) | ||
686 | 1176 | self.assertEqual(device['device_name'], | 1235 | self.assertEqual(device['device_name'], |
687 | 1177 | child.device_name.get_text()) | 1236 | child.device_name.get_text()) |
688 | 1178 | self.assertEqual(device['device_type'].lower(), | 1237 | self.assertEqual(device['device_type'].lower(), |
689 | 1179 | child.device_type.get_icon_name()[0]) | 1238 | child.device_type.get_icon_name()[0]) |
690 | 1239 | self.assertEqual(bool(device['is_local']), | ||
691 | 1240 | child.is_local) | ||
692 | 1180 | self.assertEqual(bool(device['configurable']), | 1241 | self.assertEqual(bool(device['configurable']), |
693 | 1181 | child.configurable) | 1242 | child.configurable) |
694 | 1182 | 1243 | ||
695 | @@ -1190,9 +1251,51 @@ | |||
696 | 1190 | self.assertEqual(value, | 1251 | self.assertEqual(value, |
697 | 1191 | child.max_download_speed.get_value_as_int()) | 1252 | child.max_download_speed.get_value_as_int()) |
698 | 1192 | 1253 | ||
699 | 1254 | def test_on_devices_info_ready_have_devices_cached(self): | ||
700 | 1255 | """The devices are cached for further removal.""" | ||
701 | 1256 | self.ui.on_devices_info_ready(FAKE_DEVICES_INFO) | ||
702 | 1257 | |||
703 | 1258 | for child in self.ui.devices.get_children(): | ||
704 | 1259 | self.assertTrue(self.ui._devices[child.id] is child) | ||
705 | 1260 | |||
706 | 1193 | def test_on_devices_info_error(self): | 1261 | def test_on_devices_info_error(self): |
707 | 1194 | """The devices info couldn't be retrieved.""" | 1262 | """The devices info couldn't be retrieved.""" |
708 | 1195 | self.ui.on_devices_info_error() | 1263 | self.ui.on_devices_info_error() |
709 | 1264 | # add test! | ||
710 | 1265 | |||
711 | 1266 | def test_on_device_removed(self): | ||
712 | 1267 | """When a child device was removed, remove and destroy.""" | ||
713 | 1268 | self.ui.on_devices_info_ready(FAKE_DEVICES_INFO) | ||
714 | 1269 | did = FAKE_DEVICES_INFO[0]['device_id'] | ||
715 | 1270 | device = self.ui._devices[did] | ||
716 | 1271 | self.ui.on_device_removed(device_id=did) | ||
717 | 1272 | |||
718 | 1273 | self.assertTrue(device not in self.ui.devices.get_children()) | ||
719 | 1274 | self.assertTrue(did not in self.ui._devices) | ||
720 | 1275 | |||
721 | 1276 | def test_on_local_device_removed(self): | ||
722 | 1277 | """Removing the local device emits local-device-removed.""" | ||
723 | 1278 | self.ui.connect('local-device-removed', self._set_called) | ||
724 | 1279 | |||
725 | 1280 | self.ui.on_devices_info_ready(FAKE_DEVICES_INFO) | ||
726 | 1281 | local_device = FAKE_DEVICES_INFO[-1] | ||
727 | 1282 | assert bool(local_device['is_local']) | ||
728 | 1283 | local_device_id = local_device['device_id'] | ||
729 | 1284 | assert self.ui._devices[local_device_id].is_local | ||
730 | 1285 | |||
731 | 1286 | self.ui.on_device_removed(device_id=local_device_id) | ||
732 | 1287 | |||
733 | 1288 | self.assertEqual(self._called, ((self.ui,), {})) | ||
734 | 1289 | |||
735 | 1290 | def test_on_device_removed_for_no_child_device(self): | ||
736 | 1291 | """On other device removed, do nothing.""" | ||
737 | 1292 | self.ui.on_devices_info_ready(FAKE_DEVICES_INFO) | ||
738 | 1293 | old_devices = self.ui.devices.get_children() | ||
739 | 1294 | |||
740 | 1295 | self.ui.on_device_removed(device_id='foo') | ||
741 | 1296 | |||
742 | 1297 | new_devices = self.ui.devices.get_children() | ||
743 | 1298 | self.assertEqual(new_devices, old_devices) | ||
744 | 1196 | 1299 | ||
745 | 1197 | 1300 | ||
746 | 1198 | class ApplicationsTestCase(ControlPanelMixinTestCase): | 1301 | class ApplicationsTestCase(ControlPanelMixinTestCase): |
747 | @@ -1413,3 +1516,11 @@ | |||
748 | 1413 | self.assert_warning_correct(self.ui.status_label, | 1516 | self.assert_warning_correct(self.ui.status_label, |
749 | 1414 | self.ui.FILE_SYNC_ERROR) | 1517 | self.ui.FILE_SYNC_ERROR) |
750 | 1415 | self.assertFalse(self.ui.status_label.active) | 1518 | self.assertFalse(self.ui.status_label.active) |
751 | 1519 | |||
752 | 1520 | def test_local_device_removed_is_emitted(self): | ||
753 | 1521 | """Signal local-device-removed is sent when DevicesPanel emits it.""" | ||
754 | 1522 | self.ui.connect('local-device-removed', self._set_called) | ||
755 | 1523 | |||
756 | 1524 | self.ui.devices.emit('local-device-removed') | ||
757 | 1525 | |||
758 | 1526 | self.assertEqual(self._called, ((self.ui,), {})) | ||
759 | 1416 | 1527 | ||
760 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' | |||
761 | --- ubuntuone/controlpanel/tests/test_backend.py 2010-12-18 17:42:11 +0000 | |||
762 | +++ ubuntuone/controlpanel/tests/test_backend.py 2010-12-18 17:42:12 +0000 | |||
763 | @@ -114,9 +114,11 @@ | |||
764 | 114 | "device_id": "ComputerABCDEF01234token", | 114 | "device_id": "ComputerABCDEF01234token", |
765 | 115 | "name": "Ubuntu One @ darkstar", | 115 | "name": "Ubuntu One @ darkstar", |
766 | 116 | "type": "Computer", | 116 | "type": "Computer", |
767 | 117 | "is_local": '', | ||
768 | 117 | "configurable": '', | 118 | "configurable": '', |
769 | 118 | }, | 119 | }, |
770 | 119 | { | 120 | { |
771 | 121 | 'is_local': 'True', | ||
772 | 120 | 'configurable': 'True', | 122 | 'configurable': 'True', |
773 | 121 | 'device_id': 'ComputerABC1234DEF', | 123 | 'device_id': 'ComputerABC1234DEF', |
774 | 122 | 'limit_bandwidth': '', | 124 | 'limit_bandwidth': '', |
775 | @@ -130,6 +132,7 @@ | |||
776 | 130 | "name": "Nokia E65", | 132 | "name": "Nokia E65", |
777 | 131 | "type": "Phone", | 133 | "type": "Phone", |
778 | 132 | "configurable": '', | 134 | "configurable": '', |
779 | 135 | "is_local": '', | ||
780 | 133 | }, | 136 | }, |
781 | 134 | ] | 137 | ] |
782 | 135 | 138 | ||
783 | @@ -301,6 +304,16 @@ | |||
784 | 301 | token = yield self.be.get_token() | 304 | token = yield self.be.get_token() |
785 | 302 | self.assertEqual(token, SAMPLE_CREDENTIALS["token"]) | 305 | self.assertEqual(token, SAMPLE_CREDENTIALS["token"]) |
786 | 303 | 306 | ||
787 | 307 | @inlineCallbacks | ||
788 | 308 | def test_device_is_local(self): | ||
789 | 309 | """The device_is_local returns the right result.""" | ||
790 | 310 | result = yield self.be.device_is_local(self.local_token) | ||
791 | 311 | self.assertTrue(result) | ||
792 | 312 | |||
793 | 313 | did = EXPECTED_DEVICES_INFO[0]['device_id'] | ||
794 | 314 | result = yield self.be.device_is_local(did) | ||
795 | 315 | self.assertFalse(result) | ||
796 | 316 | |||
797 | 304 | 317 | ||
798 | 305 | class BackendAccountTestCase(BackendBasicTestCase): | 318 | class BackendAccountTestCase(BackendBasicTestCase): |
799 | 306 | """Account tests for the backend.""" | 319 | """Account tests for the backend.""" |
800 | @@ -345,11 +358,23 @@ | |||
801 | 345 | """The remove_device method calls the right api.""" | 358 | """The remove_device method calls the right api.""" |
802 | 346 | dtype, did = "Computer", "SAMPLE-TOKEN" | 359 | dtype, did = "Computer", "SAMPLE-TOKEN" |
803 | 347 | device_id = dtype + did | 360 | device_id = dtype + did |
805 | 348 | apiurl = DEVICE_REMOVE_API % (dtype, did) | 361 | apiurl = DEVICE_REMOVE_API % (dtype.lower(), did) |
806 | 349 | # pylint: disable=E1101 | 362 | # pylint: disable=E1101 |
807 | 350 | self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON | 363 | self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON |
808 | 351 | result = yield self.be.remove_device(device_id) | 364 | result = yield self.be.remove_device(device_id) |
809 | 352 | self.assertEqual(result, device_id) | 365 | self.assertEqual(result, device_id) |
810 | 366 | # credentials were not cleared | ||
811 | 367 | self.assertEqual(MockDBusClient.creds, SAMPLE_CREDENTIALS) | ||
812 | 368 | |||
813 | 369 | @inlineCallbacks | ||
814 | 370 | def test_remove_device_clear_credentials_if_local_device(self): | ||
815 | 371 | """The remove_device method clears the credentials if is local.""" | ||
816 | 372 | apiurl = DEVICE_REMOVE_API % ('computer', SAMPLE_CREDENTIALS['token']) | ||
817 | 373 | # pylint: disable=E1101 | ||
818 | 374 | self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON | ||
819 | 375 | yield self.be.remove_device(self.local_token) | ||
820 | 376 | # credentials were cleared | ||
821 | 377 | self.assertEqual(MockDBusClient.creds, None) | ||
822 | 353 | 378 | ||
823 | 354 | @inlineCallbacks | 379 | @inlineCallbacks |
824 | 355 | def test_remove_device_fails(self): | 380 | def test_remove_device_fails(self): |
825 | 356 | 381 | ||
826 | === modified file 'ubuntuone/controlpanel/webclient.py' | |||
827 | --- ubuntuone/controlpanel/webclient.py 2010-12-02 16:23:03 +0000 | |||
828 | +++ ubuntuone/controlpanel/webclient.py 2010-12-18 17:42:12 +0000 | |||
829 | @@ -48,22 +48,24 @@ | |||
830 | 48 | 48 | ||
831 | 49 | def _handler(self, session, msg, d): | 49 | def _handler(self, session, msg, d): |
832 | 50 | """Handle the result of an http message.""" | 50 | """Handle the result of an http message.""" |
834 | 51 | logger.debug("WebClient: got http response: %d", msg.status_code) | 51 | logger.debug("WebClient: got http response %d for uri %r", |
835 | 52 | msg.status_code, msg.get_uri().to_string(False)) | ||
836 | 53 | data = msg.response_body.data | ||
837 | 52 | if msg.status_code == 200: | 54 | if msg.status_code == 200: |
839 | 53 | result = simplejson.loads(msg.response_body.data) | 55 | result = simplejson.loads(data) |
840 | 54 | d.callback(result) | 56 | d.callback(result) |
841 | 55 | else: | 57 | else: |
843 | 56 | e = WebClientError(msg.status_code, msg) | 58 | e = WebClientError(msg.status_code, data) |
844 | 57 | d.errback(e) | 59 | d.errback(e) |
845 | 58 | 60 | ||
846 | 59 | def _call_api_with_creds(self, credentials, api_name): | 61 | def _call_api_with_creds(self, credentials, api_name): |
847 | 60 | """Get a given url from the webservice with credentials.""" | 62 | """Get a given url from the webservice with credentials.""" |
849 | 61 | url = self.base_url + api_name | 63 | url = (self.base_url + api_name).encode('utf-8') |
850 | 62 | method = "GET" | 64 | method = "GET" |
851 | 65 | logger.debug("WebClient: getting url: %s, %s", method, url) | ||
852 | 63 | msg = Soup.Message.new(method, url) | 66 | msg = Soup.Message.new(method, url) |
853 | 64 | add_oauth_headers(msg.request_headers.append, method, url, credentials) | 67 | add_oauth_headers(msg.request_headers.append, method, url, credentials) |
854 | 65 | d = defer.Deferred() | 68 | d = defer.Deferred() |
855 | 66 | logger.debug("WebClient: getting url: %s", url) | ||
856 | 67 | self.session.queue_message(msg, self._handler, d) | 69 | self.session.queue_message(msg, self._handler, d) |
857 | 68 | return d | 70 | return d |
858 | 69 | 71 |
It works.