Merge lp:~nataliabidart/ubuntuone-control-panel/start-dc-on-backend into lp:ubuntuone-control-panel
- start-dc-on-backend
- Merge into trunk
Proposed by
Natalia Bidart
Status: | Superseded |
---|---|
Proposed branch: | lp:~nataliabidart/ubuntuone-control-panel/start-dc-on-backend |
Merge into: | lp:ubuntuone-control-panel |
Diff against target: |
1989 lines (+1003/-414) 14 files modified
data/install.ui (+7/-2) po/POTFILES.in (+2/-1) pylintrc (+1/-1) ubuntuone/controlpanel/backend.py (+41/-1) ubuntuone/controlpanel/dbus_service.py (+41/-0) ubuntuone/controlpanel/gtk/gui.py (+114/-81) ubuntuone/controlpanel/gtk/tests/__init__.py (+14/-13) ubuntuone/controlpanel/gtk/tests/test_gui.py (+187/-140) ubuntuone/controlpanel/integrationtests/test_dbus_service.py (+55/-7) ubuntuone/controlpanel/logger.py (+1/-4) ubuntuone/controlpanel/replication_client.py (+115/-0) ubuntuone/controlpanel/tests/__init__.py (+149/-1) ubuntuone/controlpanel/tests/test_backend.py (+116/-163) ubuntuone/controlpanel/tests/test_replication_client.py (+160/-0) |
To merge this branch: | bzr merge lp:~nataliabidart/ubuntuone-control-panel/start-dc-on-backend |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu One hackers | Pending | ||
Review via email: mp+45440@code.launchpad.net |
Commit message
Desktopcouch replication service is accessed through the backend using its DBus service (LP: #696782).
Description of the change
To post a comment you must log in.
- 55. By Natalia Bidart
-
Avoiding conflicts.
- 56. By Natalia Bidart
-
Merged dependency branch in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/install.ui' | |||
2 | --- data/install.ui 2010-12-24 14:53:03 +0000 | |||
3 | +++ data/install.ui 2011-01-06 20:36:09 +0000 | |||
4 | @@ -23,11 +23,12 @@ | |||
5 | 23 | <property name="visible">True</property> | 23 | <property name="visible">True</property> |
6 | 24 | <child> | 24 | <child> |
7 | 25 | <object class="GtkButton" id="install_button"> | 25 | <object class="GtkButton" id="install_button"> |
9 | 26 | <property name="label">gtk-ok</property> | 26 | <property name="label" translatable="yes">_Install now</property> |
10 | 27 | <property name="visible">True</property> | 27 | <property name="visible">True</property> |
11 | 28 | <property name="can_focus">True</property> | 28 | <property name="can_focus">True</property> |
12 | 29 | <property name="receives_default">True</property> | 29 | <property name="receives_default">True</property> |
14 | 30 | <property name="use_stock">True</property> | 30 | <property name="image">image1</property> |
15 | 31 | <property name="use_underline">True</property> | ||
16 | 31 | <signal name="clicked" handler="on_install_button_clicked"/> | 32 | <signal name="clicked" handler="on_install_button_clicked"/> |
17 | 32 | </object> | 33 | </object> |
18 | 33 | <packing> | 34 | <packing> |
19 | @@ -43,4 +44,8 @@ | |||
20 | 43 | </packing> | 44 | </packing> |
21 | 44 | </child> | 45 | </child> |
22 | 45 | </object> | 46 | </object> |
23 | 47 | <object class="GtkImage" id="image1"> | ||
24 | 48 | <property name="visible">True</property> | ||
25 | 49 | <property name="stock">gtk-ok</property> | ||
26 | 50 | </object> | ||
27 | 46 | </interface> | 51 | </interface> |
28 | 47 | 52 | ||
29 | === modified file 'po/POTFILES.in' | |||
30 | --- po/POTFILES.in 2011-01-04 16:12:56 +0000 | |||
31 | +++ po/POTFILES.in 2011-01-06 20:36:09 +0000 | |||
32 | @@ -1,8 +1,9 @@ | |||
33 | 1 | ubuntuone-control-panel-gtk.desktop.in | 1 | ubuntuone-control-panel-gtk.desktop.in |
34 | 2 | ubuntuone/controlpanel/gtk/gui.py | 2 | ubuntuone/controlpanel/gtk/gui.py |
35 | 3 | [type: gettext/glade] data/dashboard.ui | 3 | [type: gettext/glade] data/dashboard.ui |
36 | 4 | [type: gettext/glade] data/services.ui | ||
37 | 5 | [type: gettext/glade] data/device.ui | 4 | [type: gettext/glade] data/device.ui |
38 | 6 | [type: gettext/glade] data/devices.ui | 5 | [type: gettext/glade] data/devices.ui |
39 | 6 | [type: gettext/glade] data/install.ui | ||
40 | 7 | [type: gettext/glade] data/management.ui | 7 | [type: gettext/glade] data/management.ui |
41 | 8 | [type: gettext/glade] data/overview.ui | 8 | [type: gettext/glade] data/overview.ui |
42 | 9 | [type: gettext/glade] data/services.ui | ||
43 | 9 | 10 | ||
44 | === modified file 'pylintrc' | |||
45 | --- pylintrc 2010-10-13 18:55:23 +0000 | |||
46 | +++ pylintrc 2011-01-06 20:36:09 +0000 | |||
47 | @@ -272,7 +272,7 @@ | |||
48 | 272 | max-line-length=79 | 272 | max-line-length=79 |
49 | 273 | 273 | ||
50 | 274 | # Maximum number of lines in a module | 274 | # Maximum number of lines in a module |
52 | 275 | max-module-lines=2000 | 275 | max-module-lines=2500 |
53 | 276 | 276 | ||
54 | 277 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 | 277 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 |
55 | 278 | # tab). | 278 | # tab). |
56 | 279 | 279 | ||
57 | === modified file 'ubuntuone/controlpanel/backend.py' | |||
58 | --- ubuntuone/controlpanel/backend.py 2010-12-23 18:20:56 +0000 | |||
59 | +++ ubuntuone/controlpanel/backend.py 2011-01-06 20:36:09 +0000 | |||
60 | @@ -22,6 +22,7 @@ | |||
61 | 22 | from twisted.internet.defer import inlineCallbacks, returnValue | 22 | from twisted.internet.defer import inlineCallbacks, returnValue |
62 | 23 | 23 | ||
63 | 24 | from ubuntuone.controlpanel import dbus_client | 24 | from ubuntuone.controlpanel import dbus_client |
64 | 25 | from ubuntuone.controlpanel import replication_client | ||
65 | 25 | from ubuntuone.controlpanel.logger import setup_logging, log_call | 26 | from ubuntuone.controlpanel.logger import setup_logging, log_call |
66 | 26 | from ubuntuone.controlpanel.webclient import WebClient | 27 | from ubuntuone.controlpanel.webclient import WebClient |
67 | 27 | 28 | ||
68 | @@ -48,6 +49,9 @@ | |||
69 | 48 | MSG_KEY = 'message' | 49 | MSG_KEY = 'message' |
70 | 49 | STATUS_KEY = 'status' | 50 | STATUS_KEY = 'status' |
71 | 50 | 51 | ||
72 | 52 | BOOKMARKS_PKG = 'xul-ext-bindwood' | ||
73 | 53 | CONTACTS_PKG = 'evolution-couchdb' | ||
74 | 54 | |||
75 | 51 | 55 | ||
76 | 52 | def bool_str(value): | 56 | def bool_str(value): |
77 | 53 | """Return the string representation of a bool (dbus-compatible).""" | 57 | """Return the string representation of a bool (dbus-compatible).""" |
78 | @@ -300,7 +304,7 @@ | |||
79 | 300 | 304 | ||
80 | 301 | """ | 305 | """ |
81 | 302 | if 'subscribed' in settings: | 306 | if 'subscribed' in settings: |
83 | 303 | subscribed = settings['subscribed'] | 307 | subscribed = bool(settings['subscribed']) |
84 | 304 | if subscribed: | 308 | if subscribed: |
85 | 305 | yield self.subscribe_volume(volume_id) | 309 | yield self.subscribe_volume(volume_id) |
86 | 306 | else: | 310 | else: |
87 | @@ -321,6 +325,42 @@ | |||
88 | 321 | yield dbus_client.unsubscribe_folder(volume_id) | 325 | yield dbus_client.unsubscribe_folder(volume_id) |
89 | 322 | 326 | ||
90 | 323 | @log_call(logger.debug) | 327 | @log_call(logger.debug) |
91 | 328 | @inlineCallbacks | ||
92 | 329 | def replications_info(self): | ||
93 | 330 | """Get the user replications info.""" | ||
94 | 331 | replications = yield replication_client.get_replications() | ||
95 | 332 | exclusions = yield replication_client.get_exclusions() | ||
96 | 333 | |||
97 | 334 | result = [] | ||
98 | 335 | for rep in replications: | ||
99 | 336 | dependency = '' | ||
100 | 337 | if rep == replication_client.BOOKMARKS: | ||
101 | 338 | dependency = BOOKMARKS_PKG | ||
102 | 339 | elif rep == replication_client.CONTACTS: | ||
103 | 340 | dependency = CONTACTS_PKG | ||
104 | 341 | |||
105 | 342 | repd = { | ||
106 | 343 | "replication_id": rep, | ||
107 | 344 | "name": rep, # this may change to be more user friendly | ||
108 | 345 | "enabled": bool_str(rep not in exclusions), | ||
109 | 346 | "dependency": dependency, | ||
110 | 347 | } | ||
111 | 348 | result.append(repd) | ||
112 | 349 | |||
113 | 350 | returnValue(result) | ||
114 | 351 | |||
115 | 352 | @log_call(logger.info) | ||
116 | 353 | @inlineCallbacks | ||
117 | 354 | def change_replication_settings(self, replication_id, settings): | ||
118 | 355 | """Change the settings for the given replication.""" | ||
119 | 356 | if 'enabled' in settings: | ||
120 | 357 | if bool(settings['enabled']): | ||
121 | 358 | yield replication_client.replicate(replication_id) | ||
122 | 359 | else: | ||
123 | 360 | yield replication_client.exclude(replication_id) | ||
124 | 361 | returnValue(replication_id) | ||
125 | 362 | |||
126 | 363 | @log_call(logger.debug) | ||
127 | 324 | def query_bookmark_extension(self): | 364 | def query_bookmark_extension(self): |
128 | 325 | """True if the bookmark extension has been installed.""" | 365 | """True if the bookmark extension has been installed.""" |
129 | 326 | # still pending (LP: #673672) | 366 | # still pending (LP: #673672) |
130 | 327 | 367 | ||
131 | === modified file 'ubuntuone/controlpanel/dbus_service.py' | |||
132 | --- ubuntuone/controlpanel/dbus_service.py 2010-12-23 18:20:56 +0000 | |||
133 | +++ ubuntuone/controlpanel/dbus_service.py 2011-01-06 20:36:09 +0000 | |||
134 | @@ -339,6 +339,47 @@ | |||
135 | 339 | 339 | ||
136 | 340 | @log_call(logger.debug) | 340 | @log_call(logger.debug) |
137 | 341 | @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") | 341 | @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") |
138 | 342 | def replications_info(self): | ||
139 | 343 | """Return the replications info.""" | ||
140 | 344 | d = self.backend.replications_info() | ||
141 | 345 | d.addCallback(self.ReplicationsInfoReady) | ||
142 | 346 | d.addErrback(transform_failure(self.ReplicationsInfoError)) | ||
143 | 347 | |||
144 | 348 | @log_call(logger.debug) | ||
145 | 349 | @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="aa{ss}") | ||
146 | 350 | def ReplicationsInfoReady(self, info): | ||
147 | 351 | """The replications info is ready.""" | ||
148 | 352 | |||
149 | 353 | @log_call(logger.error) | ||
150 | 354 | @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}") | ||
151 | 355 | def ReplicationsInfoError(self, error): | ||
152 | 356 | """Problem getting the replications info.""" | ||
153 | 357 | |||
154 | 358 | #--- | ||
155 | 359 | |||
156 | 360 | @log_call(logger.info) | ||
157 | 361 | @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="sa{ss}") | ||
158 | 362 | def change_replication_settings(self, replication_id, settings): | ||
159 | 363 | """Configure a given replication.""" | ||
160 | 364 | d = self.backend.change_replication_settings(replication_id, settings) | ||
161 | 365 | d.addCallback(self.ReplicationSettingsChanged) | ||
162 | 366 | d.addErrback(transform_failure(self.ReplicationSettingsChangeError), | ||
163 | 367 | replication_id) | ||
164 | 368 | |||
165 | 369 | @log_call(logger.info) | ||
166 | 370 | @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="s") | ||
167 | 371 | def ReplicationSettingsChanged(self, replication_id): | ||
168 | 372 | """The settings for the replication were changed.""" | ||
169 | 373 | |||
170 | 374 | @log_call(logger.error) | ||
171 | 375 | @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="sa{ss}") | ||
172 | 376 | def ReplicationSettingsChangeError(self, replication_id, error): | ||
173 | 377 | """Problem changing settings for the replication.""" | ||
174 | 378 | |||
175 | 379 | #--- | ||
176 | 380 | |||
177 | 381 | @log_call(logger.debug) | ||
178 | 382 | @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="") | ||
179 | 342 | def query_bookmark_extension(self): | 383 | def query_bookmark_extension(self): |
180 | 343 | """Check if the extension to sync bookmarks is installed.""" | 384 | """Check if the extension to sync bookmarks is installed.""" |
181 | 344 | d = self.backend.query_bookmark_extension() | 385 | d = self.backend.query_bookmark_extension() |
182 | 345 | 386 | ||
183 | === modified file 'ubuntuone/controlpanel/gtk/gui.py' | |||
184 | --- ubuntuone/controlpanel/gtk/gui.py 2010-12-26 15:02:52 +0000 | |||
185 | +++ ubuntuone/controlpanel/gtk/gui.py 2011-01-06 20:36:09 +0000 | |||
186 | @@ -78,6 +78,12 @@ | |||
187 | 78 | VALUE_ERROR = _('Value could not be retrieved.') | 78 | VALUE_ERROR = _('Value could not be retrieved.') |
188 | 79 | WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ORANGE | 79 | WARNING_MARKUP = '<span foreground="%s"><b>%%s</b></span>' % ORANGE |
189 | 80 | KILOBYTES = 1024 | 80 | KILOBYTES = 1024 |
190 | 81 | NO_OP = lambda *a, **kw: None | ||
191 | 82 | |||
192 | 83 | |||
193 | 84 | def error_handler(*args, **kwargs): | ||
194 | 85 | """Log errors when calling D-Bus methods in a async way.""" | ||
195 | 86 | logger.error('Error handler received: %r, %r', args, kwargs) | ||
196 | 81 | 87 | ||
197 | 82 | 88 | ||
198 | 83 | def filter_by_app_name(f): | 89 | def filter_by_app_name(f): |
199 | @@ -352,7 +358,8 @@ | |||
200 | 352 | settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION, | 358 | settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION, |
201 | 353 | WINDOW_ID_KEY: str(self._window_id), | 359 | WINDOW_ID_KEY: str(self._window_id), |
202 | 354 | PING_URL_KEY: U1_PING_URL} | 360 | PING_URL_KEY: U1_PING_URL} |
204 | 355 | self.sso_backend.register(U1_APP_NAME, settings) | 361 | self.sso_backend.register(U1_APP_NAME, settings, |
205 | 362 | reply_handler=NO_OP, error_handler=error_handler) | ||
206 | 356 | self.set_property('greyed', True) | 363 | self.set_property('greyed', True) |
207 | 357 | self.warning_label.set_text('') | 364 | self.warning_label.set_text('') |
208 | 358 | 365 | ||
209 | @@ -361,7 +368,8 @@ | |||
210 | 361 | settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION, | 368 | settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION, |
211 | 362 | WINDOW_ID_KEY: str(self._window_id), | 369 | WINDOW_ID_KEY: str(self._window_id), |
212 | 363 | PING_URL_KEY: U1_PING_URL} | 370 | PING_URL_KEY: U1_PING_URL} |
214 | 364 | self.sso_backend.login(U1_APP_NAME, settings) | 371 | self.sso_backend.login(U1_APP_NAME, settings, |
215 | 372 | reply_handler=NO_OP, error_handler=error_handler) | ||
216 | 365 | self.set_property('greyed', True) | 373 | self.set_property('greyed', True) |
217 | 366 | self.warning_label.set_text('') | 374 | self.warning_label.set_text('') |
218 | 367 | 375 | ||
219 | @@ -408,7 +416,8 @@ | |||
220 | 408 | else: | 416 | else: |
221 | 409 | self.set_sensitive(True) | 417 | self.set_sensitive(True) |
222 | 410 | self.warning_label.set_text('') | 418 | self.warning_label.set_text('') |
224 | 411 | self.sso_backend.find_credentials(U1_APP_NAME, {}) | 419 | self.sso_backend.find_credentials(U1_APP_NAME, {}, |
225 | 420 | reply_handler=NO_OP, error_handler=error_handler) | ||
226 | 412 | 421 | ||
227 | 413 | 422 | ||
228 | 414 | class DashboardPanel(UbuntuOneBin, ControlPanelMixin): | 423 | class DashboardPanel(UbuntuOneBin, ControlPanelMixin): |
229 | @@ -516,11 +525,13 @@ | |||
230 | 516 | volume_id = checkbutton.get_label() | 525 | volume_id = checkbutton.get_label() |
231 | 517 | subscribed = bool_str(checkbutton.get_active()) | 526 | subscribed = bool_str(checkbutton.get_active()) |
232 | 518 | self.backend.change_volume_settings(volume_id, | 527 | self.backend.change_volume_settings(volume_id, |
234 | 519 | {'subscribed': subscribed}) | 528 | {'subscribed': subscribed}, |
235 | 529 | reply_handler=NO_OP, error_handler=error_handler) | ||
236 | 520 | 530 | ||
237 | 521 | def load(self): | 531 | def load(self): |
238 | 522 | """Load the volume list.""" | 532 | """Load the volume list.""" |
240 | 523 | self.backend.volumes_info() | 533 | self.backend.volumes_info(reply_handler=NO_OP, |
241 | 534 | error_handler=error_handler) | ||
242 | 524 | self.message.start() | 535 | self.message.start() |
243 | 525 | 536 | ||
244 | 526 | 537 | ||
245 | @@ -565,7 +576,8 @@ | |||
246 | 565 | # Not disabling the GUI to avoid annyong twitchings | 576 | # Not disabling the GUI to avoid annyong twitchings |
247 | 566 | #self.set_sensitive(False) | 577 | #self.set_sensitive(False) |
248 | 567 | self.warning_label.set_text('') | 578 | self.warning_label.set_text('') |
250 | 568 | self.backend.change_device_settings(self.id, self.__dict__) | 579 | self.backend.change_device_settings(self.id, self.__dict__, |
251 | 580 | reply_handler=NO_OP, error_handler=error_handler) | ||
252 | 569 | 581 | ||
253 | 570 | def _block_signals(f): | 582 | def _block_signals(f): |
254 | 571 | """Execute 'f' while having the _updating flag set.""" | 583 | """Execute 'f' while having the _updating flag set.""" |
255 | @@ -591,7 +603,8 @@ | |||
256 | 591 | 603 | ||
257 | 592 | def on_remove_clicked(self, widget): | 604 | def on_remove_clicked(self, widget): |
258 | 593 | """Remove button was clicked or activated.""" | 605 | """Remove button was clicked or activated.""" |
260 | 594 | self.backend.remove_device(self.id) | 606 | self.backend.remove_device(self.id, |
261 | 607 | reply_handler=NO_OP, error_handler=error_handler) | ||
262 | 595 | self.set_sensitive(False) | 608 | self.set_sensitive(False) |
263 | 596 | 609 | ||
264 | 597 | @_block_signals | 610 | @_block_signals |
265 | @@ -747,7 +760,8 @@ | |||
266 | 747 | 760 | ||
267 | 748 | def load(self): | 761 | def load(self): |
268 | 749 | """Load the device list.""" | 762 | """Load the device list.""" |
270 | 750 | self.backend.devices_info() | 763 | self.backend.devices_info(reply_handler=NO_OP, |
271 | 764 | error_handler=error_handler) | ||
272 | 751 | self.message.start() | 765 | self.message.start() |
273 | 752 | 766 | ||
274 | 753 | 767 | ||
275 | @@ -818,12 +832,18 @@ | |||
276 | 818 | class Service(gtk.VBox, ControlPanelMixin): | 832 | class Service(gtk.VBox, ControlPanelMixin): |
277 | 819 | """A service.""" | 833 | """A service.""" |
278 | 820 | 834 | ||
280 | 821 | def __init__(self, name, localized_name, *args, **kwargs): | 835 | CHANGE_ERROR = _('The settings could not be changed,\n' |
281 | 836 | 'previous values were restored.') | ||
282 | 837 | |||
283 | 838 | def __init__(self, service_id, name, *args, **kwargs): | ||
284 | 822 | gtk.VBox.__init__(self) | 839 | gtk.VBox.__init__(self) |
285 | 823 | ControlPanelMixin.__init__(self) | 840 | ControlPanelMixin.__init__(self) |
289 | 824 | self.service_name = name | 841 | self.id = service_id |
290 | 825 | 842 | ||
291 | 826 | self.button = gtk.CheckButton(label=localized_name) | 843 | self.warning_label = gtk.Label() |
292 | 844 | self.pack_start(self.warning_label, expand=False) | ||
293 | 845 | |||
294 | 846 | self.button = gtk.CheckButton(label=name) | ||
295 | 827 | self.pack_start(self.button, expand=False) | 847 | self.pack_start(self.button, expand=False) |
296 | 828 | 848 | ||
297 | 829 | self.show_all() | 849 | self.show_all() |
298 | @@ -835,15 +855,18 @@ | |||
299 | 835 | FILES_SERVICE_NAME = _('Files') | 855 | FILES_SERVICE_NAME = _('Files') |
300 | 836 | 856 | ||
301 | 837 | def __init__(self): | 857 | def __init__(self): |
304 | 838 | Service.__init__(self, name='files', | 858 | Service.__init__(self, service_id='files', |
305 | 839 | localized_name=self.FILES_SERVICE_NAME) | 859 | name=self.FILES_SERVICE_NAME) |
306 | 840 | 860 | ||
307 | 841 | self.set_sensitive(False) | 861 | self.set_sensitive(False) |
308 | 862 | |||
309 | 842 | self.backend.connect_to_signal('FileSyncStatusChanged', | 863 | self.backend.connect_to_signal('FileSyncStatusChanged', |
310 | 843 | self.on_file_sync_status_changed) | 864 | self.on_file_sync_status_changed) |
311 | 844 | self.backend.connect_to_signal('FilesEnabled', self.on_files_enabled) | 865 | self.backend.connect_to_signal('FilesEnabled', self.on_files_enabled) |
312 | 845 | self.backend.connect_to_signal('FilesDisabled', self.on_files_disabled) | 866 | self.backend.connect_to_signal('FilesDisabled', self.on_files_disabled) |
314 | 846 | self.backend.file_sync_status() | 867 | |
315 | 868 | self.backend.file_sync_status(reply_handler=NO_OP, | ||
316 | 869 | error_handler=error_handler) | ||
317 | 847 | 870 | ||
318 | 848 | @log_call(logger.debug) | 871 | @log_call(logger.debug) |
319 | 849 | def on_file_sync_status_changed(self, status): | 872 | def on_file_sync_status_changed(self, status): |
320 | @@ -869,19 +892,24 @@ | |||
321 | 869 | """Button was toggled, exclude/replicate the service properly.""" | 892 | """Button was toggled, exclude/replicate the service properly.""" |
322 | 870 | logger.info('File sync enabled? %r', self.button.get_active()) | 893 | logger.info('File sync enabled? %r', self.button.get_active()) |
323 | 871 | if self.button.get_active(): | 894 | if self.button.get_active(): |
325 | 872 | self.backend.enable_files() | 895 | self.backend.enable_files(reply_handler=NO_OP, |
326 | 896 | error_handler=error_handler) | ||
327 | 873 | else: | 897 | else: |
329 | 874 | self.backend.disable_files() | 898 | self.backend.disable_files(reply_handler=NO_OP, |
330 | 899 | error_handler=error_handler) | ||
331 | 875 | 900 | ||
332 | 876 | 901 | ||
333 | 877 | class DesktopcouchService(Service): | 902 | class DesktopcouchService(Service): |
334 | 878 | """A desktopcouch service.""" | 903 | """A desktopcouch service.""" |
335 | 879 | 904 | ||
341 | 880 | def __init__(self, name, localized_name, | 905 | def __init__(self, service_id, name, enabled, dependency=None): |
342 | 881 | replication_service, dependency=None): | 906 | Service.__init__(self, service_id, name) |
343 | 882 | Service.__init__(self, name, localized_name) | 907 | |
344 | 883 | self.replication_service = replication_service | 908 | self.backend.connect_to_signal('ReplicationSettingsChanged', |
345 | 884 | enabled = name not in self.replication_service.all_exclusions() | 909 | self.on_replication_settings_changed) |
346 | 910 | self.backend.connect_to_signal('ReplicationSettingsChangeError', | ||
347 | 911 | self.on_replication_settings_change_error) | ||
348 | 912 | |||
349 | 885 | self.button.set_active(enabled) | 913 | self.button.set_active(enabled) |
350 | 886 | 914 | ||
351 | 887 | self.dependency = None | 915 | self.dependency = None |
352 | @@ -903,11 +931,27 @@ | |||
353 | 903 | def on_button_toggled(self, button): | 931 | def on_button_toggled(self, button): |
354 | 904 | """Button was toggled, exclude/replicate the service properly.""" | 932 | """Button was toggled, exclude/replicate the service properly.""" |
355 | 905 | logger.info('Starting replication for %r? %r', | 933 | logger.info('Starting replication for %r? %r', |
361 | 906 | self.service_name, self.button.get_active()) | 934 | self.id, self.button.get_active()) |
362 | 907 | if self.button.get_active(): | 935 | |
363 | 908 | self.replication_service.replicate(self.service_name) | 936 | args = {'enabled': bool_str(self.button.get_active())} |
364 | 909 | else: | 937 | self.backend.change_replication_settings(self.id, args, |
365 | 910 | self.replication_service.exclude(self.service_name) | 938 | reply_handler=NO_OP, error_handler=error_handler) |
366 | 939 | |||
367 | 940 | @log_call(logger.info) | ||
368 | 941 | def on_replication_settings_changed(self, replication_id): | ||
369 | 942 | """The change of settings for this replication succeded.""" | ||
370 | 943 | if replication_id != self.id: | ||
371 | 944 | return | ||
372 | 945 | self.warning_label.set_text('') | ||
373 | 946 | |||
374 | 947 | @log_call(logger.error) | ||
375 | 948 | def on_replication_settings_change_error(self, replication_id, | ||
376 | 949 | error_dict=None): | ||
377 | 950 | """The change of settings for this replication failed.""" | ||
378 | 951 | if replication_id != self.id: | ||
379 | 952 | return | ||
380 | 953 | self.button.set_active(not self.button.get_active()) | ||
381 | 954 | self._set_warning(self.CHANGE_ERROR, self.warning_label) | ||
382 | 911 | 955 | ||
383 | 912 | 956 | ||
384 | 913 | class ServicesPanel(UbuntuOneBin, ControlPanelMixin): | 957 | class ServicesPanel(UbuntuOneBin, ControlPanelMixin): |
385 | @@ -916,32 +960,33 @@ | |||
386 | 916 | TITLE = _('Ubuntu One services including data sync are enabled for the ' | 960 | TITLE = _('Ubuntu One services including data sync are enabled for the ' |
387 | 917 | 'data types and services listed below.') | 961 | 'data types and services listed below.') |
388 | 918 | CHOOSE_SERVICES = _('Choose services to synchronize with this computer:') | 962 | CHOOSE_SERVICES = _('Choose services to synchronize with this computer:') |
392 | 919 | DESKTOPCOUCH_PKG = 'desktopcouch' | 963 | DESKTOPCOUCH_PKG = 'desktopcouch-ubuntuone' |
390 | 920 | BINDWOOD_PKG = 'xul-ext-bindwood' | ||
391 | 921 | EVOCOUCH_PKG = 'evolution-couchdb' | ||
393 | 922 | BOOKMARKS = _('Bookmarks (Firefox)') | 964 | BOOKMARKS = _('Bookmarks (Firefox)') |
394 | 923 | CONTACTS = _('Contacts (Evolution)') | 965 | CONTACTS = _('Contacts (Evolution)') |
395 | 924 | NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.') | 966 | NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.') |
396 | 925 | 967 | ||
398 | 926 | def __init__(self, replication_exclusion_class=None): | 968 | def __init__(self): |
399 | 927 | UbuntuOneBin.__init__(self) | 969 | UbuntuOneBin.__init__(self) |
400 | 928 | ControlPanelMixin.__init__(self, filename='services.ui') | 970 | ControlPanelMixin.__init__(self, filename='services.ui') |
401 | 929 | self.add(self.itself) | 971 | self.add(self.itself) |
402 | 930 | 972 | ||
403 | 931 | self.replication_exclusion_class = replication_exclusion_class | ||
404 | 932 | self.replication_service = None | ||
405 | 933 | self.has_desktopcouch = False | ||
406 | 934 | self.has_bindwood = False | ||
407 | 935 | self.has_evocouch = False | ||
408 | 936 | self.package_manager = package_manager.PackageManager() | 973 | self.package_manager = package_manager.PackageManager() |
409 | 937 | self.install_box = None | 974 | self.install_box = None |
412 | 938 | self.bookmarks = None | 975 | |
413 | 939 | self.contacts = None | 976 | self.backend.connect_to_signal('ReplicationsInfoReady', |
414 | 977 | self.on_replications_info_ready) | ||
415 | 978 | self.backend.connect_to_signal('ReplicationsInfoError', | ||
416 | 979 | self.on_replications_info_error) | ||
417 | 940 | 980 | ||
418 | 941 | self.files.pack_start(FilesService(), expand=False) | 981 | self.files.pack_start(FilesService(), expand=False) |
419 | 942 | 982 | ||
420 | 943 | self.show() | 983 | self.show() |
421 | 944 | 984 | ||
422 | 985 | @property | ||
423 | 986 | def has_desktopcouch(self): | ||
424 | 987 | """Is desktopcouch installed?""" | ||
425 | 988 | return self.package_manager.is_installed(self.DESKTOPCOUCH_PKG) | ||
426 | 989 | |||
427 | 945 | @log_call(logger.debug) | 990 | @log_call(logger.debug) |
428 | 946 | def load(self): | 991 | def load(self): |
429 | 947 | """Load info.""" | 992 | """Load info.""" |
430 | @@ -949,16 +994,7 @@ | |||
431 | 949 | self.itself.remove(self.install_box) | 994 | self.itself.remove(self.install_box) |
432 | 950 | self.install_box = None | 995 | self.install_box = None |
433 | 951 | 996 | ||
444 | 952 | self.has_desktopcouch = \ | 997 | logger.info('load: has_desktopcouch? %r', self.has_desktopcouch) |
435 | 953 | self.package_manager.is_installed(self.DESKTOPCOUCH_PKG) | ||
436 | 954 | self.has_bindwood = \ | ||
437 | 955 | self.package_manager.is_installed(self.BINDWOOD_PKG) | ||
438 | 956 | self.has_evocouch = \ | ||
439 | 957 | self.package_manager.is_installed(self.EVOCOUCH_PKG) | ||
440 | 958 | |||
441 | 959 | logger.info('load: has_desktopcouch? %r has_bindwood? %s ' | ||
442 | 960 | 'has_evocouch? %s', self.has_desktopcouch, | ||
443 | 961 | self.has_bindwood, self.has_evocouch) | ||
445 | 962 | if not self.has_desktopcouch: | 998 | if not self.has_desktopcouch: |
446 | 963 | self.message.set_text('') | 999 | self.message.set_text('') |
447 | 964 | self.replications.hide() | 1000 | self.replications.hide() |
448 | @@ -975,46 +1011,41 @@ | |||
449 | 975 | @log_call(logger.debug) | 1011 | @log_call(logger.debug) |
450 | 976 | def load_replications(self, *args): | 1012 | def load_replications(self, *args): |
451 | 977 | """Load replications info.""" | 1013 | """Load replications info.""" |
452 | 1014 | # ask replications to the backend | ||
453 | 1015 | self.message.start() | ||
454 | 1016 | self.backend.replications_info(reply_handler=NO_OP, | ||
455 | 1017 | error_handler=error_handler) | ||
456 | 1018 | |||
457 | 1019 | @log_call(logger.debug) | ||
458 | 1020 | def on_replications_info_ready(self, info): | ||
459 | 1021 | """The replication info is ready.""" | ||
460 | 1022 | self.on_success(self.CHOOSE_SERVICES) | ||
461 | 1023 | |||
462 | 978 | self.replications.show() | 1024 | self.replications.show() |
463 | 979 | 1025 | ||
464 | 980 | if self.install_box is not None: | 1026 | if self.install_box is not None: |
465 | 981 | self.itself.remove(self.install_box) | 1027 | self.itself.remove(self.install_box) |
466 | 982 | self.install_box = None | 1028 | self.install_box = None |
467 | 983 | 1029 | ||
468 | 984 | self.message.set_text(self.CHOOSE_SERVICES) | ||
469 | 985 | for child in self.replications.get_children(): | 1030 | for child in self.replications.get_children(): |
470 | 986 | self.replications.remove(child) | 1031 | self.replications.remove(child) |
471 | 987 | 1032 | ||
502 | 988 | # Unable to import 'desktopcouch.application.replication_services' | 1033 | for item in info: |
503 | 989 | # pylint: disable=F0401 | 1034 | pkg = item['dependency'] |
504 | 990 | if self.replication_exclusion_class is None: | 1035 | child = DesktopcouchService(service_id=item['replication_id'], |
505 | 991 | from desktopcouch.application.replication_services import \ | 1036 | name=item['name'], # self.BOOKMARKS, |
506 | 992 | ubuntuone as u1rep | 1037 | enabled=bool(item['enabled']), |
507 | 993 | self.replication_exclusion_class = u1rep.ReplicationExclusion | 1038 | dependency=pkg if pkg else None) |
508 | 994 | 1039 | self.replications.pack_start(child, expand=False) | |
509 | 995 | if self.replication_service is None: | 1040 | |
510 | 996 | try: | 1041 | @log_call(logger.error) |
511 | 997 | self.replication_service = self.replication_exclusion_class() | 1042 | def on_replications_info_error(self, error_dict=None): |
512 | 998 | except ValueError: | 1043 | """The replication info can not be retrieved.""" |
513 | 999 | logger.exception('Can not load replications:') | 1044 | if error_dict is not None and \ |
514 | 1000 | self._set_warning(self.NO_PAIRING_RECORD, self.message) | 1045 | error_dict.get('error_type', None) == 'NoPairingRecord': |
515 | 1001 | return | 1046 | self.on_error(self.NO_PAIRING_RECORD) |
516 | 1002 | 1047 | else: | |
517 | 1003 | pkg = None | 1048 | self.on_error() |
488 | 1004 | if not self.has_bindwood: | ||
489 | 1005 | pkg = self.BINDWOOD_PKG | ||
490 | 1006 | self.bookmarks = DesktopcouchService('bookmarks', self.BOOKMARKS, | ||
491 | 1007 | self.replication_service, | ||
492 | 1008 | dependency=pkg) | ||
493 | 1009 | self.replications.pack_start(self.bookmarks, expand=False) | ||
494 | 1010 | |||
495 | 1011 | pkg = None | ||
496 | 1012 | if not self.has_evocouch: | ||
497 | 1013 | pkg = self.EVOCOUCH_PKG | ||
498 | 1014 | self.contacts = DesktopcouchService('contacts', self.CONTACTS, | ||
499 | 1015 | self.replication_service, | ||
500 | 1016 | dependency=pkg) | ||
501 | 1017 | self.replications.pack_start(self.contacts, expand=False) | ||
518 | 1018 | 1049 | ||
519 | 1019 | 1050 | ||
520 | 1020 | class ManagementPanel(gtk.VBox, ControlPanelMixin): | 1051 | class ManagementPanel(gtk.VBox, ControlPanelMixin): |
521 | @@ -1107,8 +1138,10 @@ | |||
522 | 1107 | 1138 | ||
523 | 1108 | def load(self): | 1139 | def load(self): |
524 | 1109 | """Load the account info and file sync status list.""" | 1140 | """Load the account info and file sync status list.""" |
527 | 1110 | self.backend.account_info() | 1141 | self.backend.account_info(reply_handler=NO_OP, |
528 | 1111 | self.backend.file_sync_status() | 1142 | error_handler=error_handler) |
529 | 1143 | self.backend.file_sync_status(reply_handler=NO_OP, | ||
530 | 1144 | error_handler=error_handler) | ||
531 | 1112 | self.dashboard_button.clicked() | 1145 | self.dashboard_button.clicked() |
532 | 1113 | 1146 | ||
533 | 1114 | @log_call(logger.debug) | 1147 | @log_call(logger.debug) |
534 | 1115 | 1148 | ||
535 | === modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py' | |||
536 | --- ubuntuone/controlpanel/gtk/tests/__init__.py 2010-12-23 19:17:53 +0000 | |||
537 | +++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-06 20:36:09 +0000 | |||
538 | @@ -53,6 +53,15 @@ | |||
539 | 53 | 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local | 53 | 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local |
540 | 54 | ] | 54 | ] |
541 | 55 | 55 | ||
542 | 56 | FAKE_REPLICATIONS_INFO = [ | ||
543 | 57 | {'replication_id': 'foo', 'name': 'Bar', | ||
544 | 58 | 'enabled': 'True', 'dependency': ''}, | ||
545 | 59 | {'replication_id': 'yadda', 'name': 'Foo', | ||
546 | 60 | 'enabled': '', 'dependency': 'a very weird one'}, | ||
547 | 61 | {'replication_id': 'yoda', 'name': 'Figthers', | ||
548 | 62 | 'enabled': 'True', 'dependency': 'other dep'}, | ||
549 | 63 | ] | ||
550 | 64 | |||
551 | 56 | 65 | ||
552 | 57 | class FakedObject(object): | 66 | class FakedObject(object): |
553 | 58 | """Fake an object, record every call.""" | 67 | """Fake an object, record every call.""" |
554 | @@ -117,9 +126,11 @@ | |||
555 | 117 | object_path = gui.DBUS_PREFERENCES_PATH | 126 | object_path = gui.DBUS_PREFERENCES_PATH |
556 | 118 | iface = gui.DBUS_PREFERENCES_IFACE | 127 | iface = gui.DBUS_PREFERENCES_IFACE |
557 | 119 | exposed_methods = [ | 128 | exposed_methods = [ |
561 | 120 | 'account_info', 'devices_info', 'change_device_settings', | 129 | 'account_info', # account |
562 | 121 | 'volumes_info', 'change_volume_settings', 'file_sync_status', | 130 | 'devices_info', 'change_device_settings', 'remove_device', # devices |
563 | 122 | 'remove_device', 'enable_files', 'disable_files', | 131 | 'volumes_info', 'change_volume_settings', # volumes |
564 | 132 | 'replications_info', 'change_replication_settings', # replications | ||
565 | 133 | 'file_sync_status', 'enable_files', 'disable_files', # files | ||
566 | 123 | ] | 134 | ] |
567 | 124 | 135 | ||
568 | 125 | 136 | ||
569 | @@ -157,13 +168,3 @@ | |||
570 | 157 | yield | 168 | yield |
571 | 158 | self._installed[package_name] = True | 169 | self._installed[package_name] = True |
572 | 159 | gui.package_manager.return_value(FakedTransaction([package_name])) | 170 | gui.package_manager.return_value(FakedTransaction([package_name])) |
573 | 160 | |||
574 | 161 | |||
575 | 162 | class FakedReplication(object): | ||
576 | 163 | """Faked a DC replication exclusion.""" | ||
577 | 164 | |||
578 | 165 | def __init__(self): | ||
579 | 166 | self._exclusions = set() | ||
580 | 167 | self.all_exclusions = lambda: self._exclusions | ||
581 | 168 | self.replicate = self._exclusions.remove | ||
582 | 169 | self.exclude = self._exclusions.add | ||
583 | 170 | 171 | ||
584 | === modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py' | |||
585 | --- ubuntuone/controlpanel/gtk/tests/test_gui.py 2010-12-26 15:02:52 +0000 | |||
586 | +++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-06 20:36:09 +0000 | |||
587 | @@ -26,9 +26,10 @@ | |||
588 | 26 | 26 | ||
589 | 27 | from ubuntuone.controlpanel.gtk import gui | 27 | from ubuntuone.controlpanel.gtk import gui |
590 | 28 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, | 28 | from ubuntuone.controlpanel.gtk.tests import (FAKE_ACCOUNT_INFO, |
592 | 29 | FAKE_VOLUMES_INFO, FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, | 29 | FAKE_DEVICE_INFO, FAKE_DEVICES_INFO, |
593 | 30 | FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, | ||
594 | 30 | FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface, | 31 | FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface, |
596 | 31 | FakedPackageManager, FakedReplication, | 32 | FakedPackageManager, |
597 | 32 | ) | 33 | ) |
598 | 33 | from ubuntuone.controlpanel.tests import TOKEN, TestCase | 34 | from ubuntuone.controlpanel.tests import TOKEN, TestCase |
599 | 34 | from ubuntuone.controlpanel.gtk.tests.test_package_manager import ( | 35 | from ubuntuone.controlpanel.gtk.tests.test_package_manager import ( |
600 | @@ -37,6 +38,8 @@ | |||
601 | 37 | 38 | ||
602 | 38 | # Attribute 'yyy' defined outside __init__, access to a protected member | 39 | # Attribute 'yyy' defined outside __init__, access to a protected member |
603 | 39 | # pylint: disable=W0201, W0212 | 40 | # pylint: disable=W0201, W0212 |
604 | 41 | # Too many lines in module | ||
605 | 42 | # pylint: disable=C0302 | ||
606 | 40 | 43 | ||
607 | 41 | 44 | ||
608 | 42 | class BaseTestCase(TestCase): | 45 | class BaseTestCase(TestCase): |
609 | @@ -96,7 +99,9 @@ | |||
610 | 96 | if backend is None: | 99 | if backend is None: |
611 | 97 | backend = self.ui.backend | 100 | backend = self.ui.backend |
612 | 98 | self.assertIn(method_name, backend._called) | 101 | self.assertIn(method_name, backend._called) |
614 | 99 | self.assertEqual(backend._called[method_name], (args, {})) | 102 | kwargs = {'reply_handler': gui.NO_OP, |
615 | 103 | 'error_handler': gui.error_handler} | ||
616 | 104 | self.assertEqual(backend._called[method_name], (args, kwargs)) | ||
617 | 100 | 105 | ||
618 | 101 | def assert_warning_correct(self, warning, text): | 106 | def assert_warning_correct(self, warning, text): |
619 | 102 | """Check that 'warning' is visible, showing 'text'.""" | 107 | """Check that 'warning' is visible, showing 'text'.""" |
620 | @@ -1361,9 +1366,9 @@ | |||
621 | 1361 | """The test suite for a service.""" | 1366 | """The test suite for a service.""" |
622 | 1362 | 1367 | ||
623 | 1363 | klass = gui.Service | 1368 | klass = gui.Service |
627 | 1364 | name = 'dc_test' | 1369 | service_id = 'dc_test' |
628 | 1365 | localized_name = u'Qué lindo test!' | 1370 | name = u'Qué lindo test!' |
629 | 1366 | kwargs = {'name': 'dc_test', 'localized_name': u'Qué lindo test!'} | 1371 | kwargs = {'service_id': service_id, 'name': name} |
630 | 1367 | 1372 | ||
631 | 1368 | def test_is_an_box(self): | 1373 | def test_is_an_box(self): |
632 | 1369 | """Inherits from gtk.VBox.""" | 1374 | """Inherits from gtk.VBox.""" |
633 | @@ -1373,30 +1378,35 @@ | |||
634 | 1373 | """Is visible.""" | 1378 | """Is visible.""" |
635 | 1374 | self.assertTrue(self.ui.get_visible()) | 1379 | self.assertTrue(self.ui.get_visible()) |
636 | 1375 | 1380 | ||
637 | 1381 | def test_warning_label_is_cleared(self): | ||
638 | 1382 | """The warning label is cleared.""" | ||
639 | 1383 | self.assertEqual(self.ui.warning_label.get_text(), '') | ||
640 | 1384 | |||
641 | 1385 | def test_warning_label_packed(self): | ||
642 | 1386 | """The warning label is packed as child.""" | ||
643 | 1387 | self.assertIn(self.ui.warning_label, self.ui.get_children()) | ||
644 | 1388 | |||
645 | 1376 | def test_check_button_packed(self): | 1389 | def test_check_button_packed(self): |
647 | 1377 | """A check button is packed as only child.""" | 1390 | """A check button is packed as child.""" |
648 | 1378 | self.assertIn(self.ui.button, self.ui.get_children()) | 1391 | self.assertIn(self.ui.button, self.ui.get_children()) |
649 | 1379 | 1392 | ||
650 | 1380 | def test_label(self): | 1393 | def test_label(self): |
651 | 1381 | """The label is set.""" | 1394 | """The label is set.""" |
653 | 1382 | self.assertEqual(self.localized_name, self.ui.button.get_label()) | 1395 | self.assertEqual(self.name, self.ui.button.get_label()) |
654 | 1383 | 1396 | ||
658 | 1384 | def test_service_name(self): | 1397 | def test_service_id(self): |
659 | 1385 | """The service_name is set.""" | 1398 | """The service id is set.""" |
660 | 1386 | self.assertEqual(self.name, self.ui.service_name) | 1399 | self.assertEqual(self.service_id, self.ui.id) |
661 | 1387 | 1400 | ||
662 | 1388 | 1401 | ||
663 | 1389 | class FilesServiceTestCase(ServiceTestCase): | 1402 | class FilesServiceTestCase(ServiceTestCase): |
664 | 1390 | """The test suite for the file sync service.""" | 1403 | """The test suite for the file sync service.""" |
665 | 1391 | 1404 | ||
666 | 1392 | klass = gui.FilesService | 1405 | klass = gui.FilesService |
667 | 1406 | service_id = 'files' | ||
668 | 1407 | name = gui.FilesService.FILES_SERVICE_NAME | ||
669 | 1393 | kwargs = {} | 1408 | kwargs = {} |
670 | 1394 | 1409 | ||
671 | 1395 | def setUp(self): | ||
672 | 1396 | self.name = 'files' | ||
673 | 1397 | self.localized_name = gui.FilesService.FILES_SERVICE_NAME | ||
674 | 1398 | super(FilesServiceTestCase, self).setUp() | ||
675 | 1399 | |||
676 | 1400 | def test_backend_account_signals(self): | 1410 | def test_backend_account_signals(self): |
677 | 1401 | """The proper signals are connected to the backend.""" | 1411 | """The proper signals are connected to the backend.""" |
678 | 1402 | self.assertEqual(self.ui.backend._signals['FileSyncStatusChanged'], | 1412 | self.assertEqual(self.ui.backend._signals['FileSyncStatusChanged'], |
679 | @@ -1461,35 +1471,36 @@ | |||
680 | 1461 | """The test suite for a desktopcouch service.""" | 1471 | """The test suite for a desktopcouch service.""" |
681 | 1462 | 1472 | ||
682 | 1463 | klass = gui.DesktopcouchService | 1473 | klass = gui.DesktopcouchService |
683 | 1474 | enabled = True | ||
684 | 1464 | 1475 | ||
685 | 1465 | def setUp(self): | 1476 | def setUp(self): |
689 | 1466 | self.replication = FakedReplication() | 1477 | self.kwargs['enabled'] = self.enabled |
687 | 1467 | self.name = self.kwargs['name'] | ||
688 | 1468 | self.kwargs['replication_service'] = self.replication | ||
690 | 1469 | super(DesktopcouchServiceTestCase, self).setUp() | 1478 | super(DesktopcouchServiceTestCase, self).setUp() |
691 | 1470 | 1479 | ||
692 | 1480 | def modify_settings(self): | ||
693 | 1481 | """Modify settings so values actually change.""" | ||
694 | 1482 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
695 | 1483 | |||
696 | 1484 | def test_backend_account_signals(self): | ||
697 | 1485 | """The proper signals are connected to the backend.""" | ||
698 | 1486 | self.assertEqual( | ||
699 | 1487 | self.ui.backend._signals['ReplicationSettingsChanged'], | ||
700 | 1488 | [self.ui.on_replication_settings_changed]) | ||
701 | 1489 | self.assertEqual( | ||
702 | 1490 | self.ui.backend._signals['ReplicationSettingsChangeError'], | ||
703 | 1491 | [self.ui.on_replication_settings_change_error]) | ||
704 | 1492 | |||
705 | 1471 | def test_active(self): | 1493 | def test_active(self): |
714 | 1472 | """Is active since replication has an empty database.""" | 1494 | """Is active if enabled.""" |
715 | 1473 | self.assertTrue(self.ui.button.get_active()) | 1495 | self.assertEqual(self.enabled, self.ui.button.get_active()) |
708 | 1474 | |||
709 | 1475 | def test_not_active(self): | ||
710 | 1476 | """Is not active since 'name' is excluded on replication database.""" | ||
711 | 1477 | self.replication.exclude(self.name) | ||
712 | 1478 | self.ui = self.klass(**self.kwargs) | ||
713 | 1479 | self.assertFalse(self.ui.button.get_active()) | ||
716 | 1480 | 1496 | ||
717 | 1481 | def test_on_button_toggled(self): | 1497 | def test_on_button_toggled(self): |
718 | 1482 | """When toggling the button, the DC exclude list is updated.""" | 1498 | """When toggling the button, the DC exclude list is updated.""" |
719 | 1483 | assert self.ui.button.get_active() | ||
720 | 1484 | self.ui.button.set_active(not self.ui.button.get_active()) | 1499 | self.ui.button.set_active(not self.ui.button.get_active()) |
721 | 1485 | self.assertEqual(set([self.name]), self.replication.all_exclusions()) | ||
722 | 1486 | 1500 | ||
729 | 1487 | def test_on_button_toggled_twice(self): | 1501 | args = (self.service_id, |
730 | 1488 | """When toggling the button twice, the DC exclude list is updated.""" | 1502 | {'enabled': gui.bool_str(self.ui.button.get_active())}) |
731 | 1489 | assert self.ui.button.get_active() | 1503 | self.assert_backend_called('change_replication_settings', args) |
726 | 1490 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
727 | 1491 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
728 | 1492 | self.assertEqual(set(), self.replication.all_exclusions()) | ||
732 | 1493 | 1504 | ||
733 | 1494 | def test_dependency(self): | 1505 | def test_dependency(self): |
734 | 1495 | """The dependency box is None.""" | 1506 | """The dependency box is None.""" |
735 | @@ -1499,6 +1510,72 @@ | |||
736 | 1499 | """The check button is sensitive.""" | 1510 | """The check button is sensitive.""" |
737 | 1500 | self.assertTrue(self.ui.button.get_sensitive()) | 1511 | self.assertTrue(self.ui.button.get_sensitive()) |
738 | 1501 | 1512 | ||
739 | 1513 | def test_on_replication_settings_changed(self): | ||
740 | 1514 | """When settings were changed for this replication, enable it.""" | ||
741 | 1515 | new_val = not self.ui.button.get_active() | ||
742 | 1516 | self.ui.button.set_active(new_val) | ||
743 | 1517 | |||
744 | 1518 | self.ui.on_replication_settings_changed(replication_id=self.ui.id) | ||
745 | 1519 | |||
746 | 1520 | self.assertEqual(self.ui.warning_label.get_text(), '') | ||
747 | 1521 | self.assertEqual(new_val, self.ui.button.get_active()) | ||
748 | 1522 | |||
749 | 1523 | def test_on_replication_settings_changed_after_error(self): | ||
750 | 1524 | """Change success after error.""" | ||
751 | 1525 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
752 | 1526 | self.ui.on_replication_settings_change_error(replication_id=self.ui.id) | ||
753 | 1527 | |||
754 | 1528 | self.test_on_replication_settings_changed() | ||
755 | 1529 | |||
756 | 1530 | def test_on_replication_settings_changed_different_id(self): | ||
757 | 1531 | """When settings were changed for other rep, nothing changes.""" | ||
758 | 1532 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
759 | 1533 | self.ui.on_replication_settings_changed(replication_id='yadda') | ||
760 | 1534 | |||
761 | 1535 | self.assertEqual(self.ui.warning_label.get_text(), '') | ||
762 | 1536 | |||
763 | 1537 | def test_on_replication_settings_changed_different_id_after_error(self): | ||
764 | 1538 | """When settings were changed for other + error, nothing changes.""" | ||
765 | 1539 | self.ui.on_replication_settings_change_error(replication_id=self.ui.id) | ||
766 | 1540 | self.ui.on_replication_settings_changed(replication_id='yadda') | ||
767 | 1541 | |||
768 | 1542 | self.assert_warning_correct(self.ui.warning_label, | ||
769 | 1543 | self.ui.CHANGE_ERROR) | ||
770 | 1544 | |||
771 | 1545 | def test_on_replication_settings_change_error(self): | ||
772 | 1546 | """When settings were not changed, notify the user. | ||
773 | 1547 | |||
774 | 1548 | Also, confirm that old value was restored. | ||
775 | 1549 | |||
776 | 1550 | """ | ||
777 | 1551 | old_val = self.ui.button.get_active() | ||
778 | 1552 | self.ui.button.set_active(not old_val) | ||
779 | 1553 | self.ui.on_replication_settings_change_error(replication_id=self.ui.id) | ||
780 | 1554 | |||
781 | 1555 | self.assert_warning_correct(self.ui.warning_label, | ||
782 | 1556 | self.ui.CHANGE_ERROR) | ||
783 | 1557 | self.assertEqual(old_val, self.ui.button.get_active()) | ||
784 | 1558 | |||
785 | 1559 | def test_on_replication_settings_change_error_after_success(self): | ||
786 | 1560 | """Change error after success.""" | ||
787 | 1561 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
788 | 1562 | self.ui.on_replication_settings_changed(replication_id=self.ui.id) | ||
789 | 1563 | |||
790 | 1564 | self.test_on_replication_settings_change_error() | ||
791 | 1565 | |||
792 | 1566 | def test_on_replication_settings_change_error_different_id(self): | ||
793 | 1567 | """When settings were not changed for other replication, do nothing.""" | ||
794 | 1568 | self.ui.button.set_active(not self.ui.button.get_active()) | ||
795 | 1569 | self.ui.on_replication_settings_change_error(replication_id='yudo') | ||
796 | 1570 | |||
797 | 1571 | self.assertEqual(self.ui.warning_label.get_text(), '') | ||
798 | 1572 | |||
799 | 1573 | |||
800 | 1574 | class DesktopcouchServiceDisabledAtStartupTestCase(ServiceTestCase): | ||
801 | 1575 | """The test suite for a desktopcouch service when enabled=False.""" | ||
802 | 1576 | |||
803 | 1577 | enabled = False | ||
804 | 1578 | |||
805 | 1502 | 1579 | ||
806 | 1503 | class DesktopcouchServiceWithDependencyTestCase(DesktopcouchServiceTestCase): | 1580 | class DesktopcouchServiceWithDependencyTestCase(DesktopcouchServiceTestCase): |
807 | 1504 | """The test suite for a desktopcouch service when it needs a dependency.""" | 1581 | """The test suite for a desktopcouch service when it needs a dependency.""" |
808 | @@ -1532,7 +1609,8 @@ | |||
809 | 1532 | self.ui.dependency.emit('finished') | 1609 | self.ui.dependency.emit('finished') |
810 | 1533 | 1610 | ||
811 | 1534 | self.assertTrue(self.ui.dependency is None) | 1611 | self.assertTrue(self.ui.dependency is None) |
813 | 1535 | self.assertEqual(self.ui.get_children(), [self.ui.button]) | 1612 | self.assertEqual(sorted(self.ui.get_children()), |
814 | 1613 | sorted([self.ui.button, self.ui.warning_label])) | ||
815 | 1536 | 1614 | ||
816 | 1537 | 1615 | ||
817 | 1538 | class ServicesTestCase(ControlPanelMixinTestCase): | 1616 | class ServicesTestCase(ControlPanelMixinTestCase): |
818 | @@ -1562,6 +1640,13 @@ | |||
819 | 1562 | """The install box is None.""" | 1640 | """The install box is None.""" |
820 | 1563 | self.assertTrue(self.ui.install_box is None) | 1641 | self.assertTrue(self.ui.install_box is None) |
821 | 1564 | 1642 | ||
822 | 1643 | def test_backend_signals(self): | ||
823 | 1644 | """The proper signals are connected to the backend.""" | ||
824 | 1645 | self.assertEqual(self.ui.backend._signals['ReplicationsInfoReady'], | ||
825 | 1646 | [self.ui.on_replications_info_ready]) | ||
826 | 1647 | self.assertEqual(self.ui.backend._signals['ReplicationsInfoError'], | ||
827 | 1648 | [self.ui.on_replications_info_error]) | ||
828 | 1649 | |||
829 | 1565 | 1650 | ||
830 | 1566 | class ServicesFilesTestCase(ServicesTestCase): | 1651 | class ServicesFilesTestCase(ServicesTestCase): |
831 | 1567 | """The test suite for the services panel (files section).""" | 1652 | """The test suite for the services panel (files section).""" |
832 | @@ -1589,22 +1674,10 @@ | |||
833 | 1589 | self.assertFalse(self.ui.message.active) | 1674 | self.assertFalse(self.ui.message.active) |
834 | 1590 | self.assertEqual(self.ui.message.get_text(), '') | 1675 | self.assertEqual(self.ui.message.get_text(), '') |
835 | 1591 | 1676 | ||
836 | 1592 | def test_replication_service(self): | ||
837 | 1593 | """Has a replication service.""" | ||
838 | 1594 | self.assertEqual(self.ui.replication_service, None) | ||
839 | 1595 | |||
840 | 1596 | def test_has_desktopcouch(self): | 1677 | def test_has_desktopcouch(self): |
841 | 1597 | """Has desktopcouch installed?""" | 1678 | """Has desktopcouch installed?""" |
842 | 1598 | self.assertFalse(self.ui.has_desktopcouch) | 1679 | self.assertFalse(self.ui.has_desktopcouch) |
843 | 1599 | 1680 | ||
844 | 1600 | def test_has_bindwood(self): | ||
845 | 1601 | """Has bindwood installed?""" | ||
846 | 1602 | self.assertFalse(self.ui.has_bindwood) | ||
847 | 1603 | |||
848 | 1604 | def test_has_evocouch(self): | ||
849 | 1605 | """Has evocouch installed?""" | ||
850 | 1606 | self.assertFalse(self.ui.has_evocouch) | ||
851 | 1607 | |||
852 | 1608 | def test_install_box_is_hidden(self): | 1681 | def test_install_box_is_hidden(self): |
853 | 1609 | """The install box is not hidden.""" | 1682 | """The install box is not hidden.""" |
854 | 1610 | self.assertTrue(self.ui.install_box.get_visible()) | 1683 | self.assertTrue(self.ui.install_box.get_visible()) |
855 | @@ -1629,41 +1702,27 @@ | |||
856 | 1629 | 1702 | ||
857 | 1630 | self.assertEqual(self._called, ((self.ui.install_box,), {})) | 1703 | self.assertEqual(self._called, ((self.ui.install_box,), {})) |
858 | 1631 | 1704 | ||
859 | 1705 | def test_load_replications(self): | ||
860 | 1706 | """The load_replications starts the spinner and calls the backend.""" | ||
861 | 1707 | self.ui.load_replications() | ||
862 | 1708 | |||
863 | 1709 | self.assertTrue(self.ui.message.active) | ||
864 | 1710 | self.assert_backend_called('replications_info', ()) | ||
865 | 1711 | |||
866 | 1632 | 1712 | ||
867 | 1633 | class ServicesWithDesktopcouchTestCase(ServicesTestCase): | 1713 | class ServicesWithDesktopcouchTestCase(ServicesTestCase): |
868 | 1634 | """The test suite for the services panel.""" | 1714 | """The test suite for the services panel.""" |
869 | 1635 | 1715 | ||
870 | 1636 | kwargs = {'replication_exclusion_class': FakedReplication} | ||
871 | 1637 | |||
872 | 1638 | def setUp(self): | 1716 | def setUp(self): |
873 | 1639 | super(ServicesWithDesktopcouchTestCase, self).setUp() | 1717 | super(ServicesWithDesktopcouchTestCase, self).setUp() |
874 | 1640 | self.ui.package_manager._installed[self.ui.DESKTOPCOUCH_PKG] = True | 1718 | self.ui.package_manager._installed[self.ui.DESKTOPCOUCH_PKG] = True |
876 | 1641 | self.ui.load() | 1719 | self.ui.on_replications_info_ready(info=FAKE_REPLICATIONS_INFO) |
877 | 1642 | 1720 | ||
878 | 1643 | def test_message(self): | 1721 | def test_message(self): |
879 | 1644 | """Global load message is stopped and proper test is shown.""" | 1722 | """Global load message is stopped and proper test is shown.""" |
880 | 1645 | self.assertFalse(self.ui.message.active) | 1723 | self.assertFalse(self.ui.message.active) |
881 | 1646 | self.assertEqual(self.ui.message.get_text(), self.ui.CHOOSE_SERVICES) | 1724 | self.assertEqual(self.ui.message.get_text(), self.ui.CHOOSE_SERVICES) |
882 | 1647 | 1725 | ||
883 | 1648 | def test_replication_service(self): | ||
884 | 1649 | """Has a replication service.""" | ||
885 | 1650 | self.assertIsInstance(self.ui.replication_service, FakedReplication) | ||
886 | 1651 | |||
887 | 1652 | def test_no_pairing_record(self): | ||
888 | 1653 | """The pairing record is not in place.""" | ||
889 | 1654 | |||
890 | 1655 | def no_pairing_record(*a): | ||
891 | 1656 | """Fake a ReplicationExclusion with no pairing record.""" | ||
892 | 1657 | raise ValueError("No pairing record for ubuntuone.") | ||
893 | 1658 | |||
894 | 1659 | self.ui.replication_exclusion_class = no_pairing_record | ||
895 | 1660 | self.ui.replication_service = None | ||
896 | 1661 | self.ui.load() | ||
897 | 1662 | |||
898 | 1663 | self.assertEqual(self.ui.replications.get_children(), []) | ||
899 | 1664 | self.assertFalse(self.ui.message.active) | ||
900 | 1665 | self.assert_warning_correct(self.ui.message, self.ui.NO_PAIRING_RECORD) | ||
901 | 1666 | |||
902 | 1667 | def test_has_desktopcouch(self): | 1726 | def test_has_desktopcouch(self): |
903 | 1668 | """Has desktopcouch installed?""" | 1727 | """Has desktopcouch installed?""" |
904 | 1669 | self.assertTrue(self.ui.has_desktopcouch) | 1728 | self.assertTrue(self.ui.has_desktopcouch) |
905 | @@ -1673,79 +1732,67 @@ | |||
906 | 1673 | self.assertTrue(self.ui.replications.get_visible()) | 1732 | self.assertTrue(self.ui.replications.get_visible()) |
907 | 1674 | 1733 | ||
908 | 1675 | children = self.ui.replications.get_children() | 1734 | children = self.ui.replications.get_children() |
911 | 1676 | self.assertEqual(len(children), 2) | 1735 | self.assertEqual(len(children), len(FAKE_REPLICATIONS_INFO)) |
912 | 1677 | for child in children: | 1736 | for expected, child in zip(FAKE_REPLICATIONS_INFO, children): |
913 | 1678 | self.assertIsInstance(child, gui.DesktopcouchService) | 1737 | self.assertIsInstance(child, gui.DesktopcouchService) |
921 | 1679 | 1738 | self.assertEqual(expected['replication_id'], child.id) | |
922 | 1680 | self.assertTrue(self.ui.bookmarks is children[0]) | 1739 | self.assertEqual(expected['name'], child.button.get_label()) |
923 | 1681 | self.assertTrue(self.ui.contacts is children[1]) | 1740 | self.assertEqual(bool(expected['enabled']), |
924 | 1682 | 1741 | child.button.get_active()) | |
925 | 1683 | def test_replications_after_loading_twice(self): | 1742 | |
926 | 1684 | """Has proper child after loading twice.""" | 1743 | if expected['dependency']: |
927 | 1685 | self.ui.load() | 1744 | self.assertTrue(child.dependency is not None) |
928 | 1745 | self.assertEqual(expected['dependency'], | ||
929 | 1746 | child.dependency.package_name) | ||
930 | 1747 | else: | ||
931 | 1748 | self.assertTrue(child.dependency is None) | ||
932 | 1749 | |||
933 | 1750 | def test_replications_after_getting_info_twice(self): | ||
934 | 1751 | """Has proper child after getting backend info twice.""" | ||
935 | 1752 | self.ui.on_replications_info_ready(info=FAKE_REPLICATIONS_INFO) | ||
936 | 1686 | self.test_replications() | 1753 | self.test_replications() |
937 | 1687 | 1754 | ||
999 | 1688 | def test_bookmarks(self): | 1755 | |
1000 | 1689 | """The bookmarks is correct.""" | 1756 | class ServicesWithDesktopcouchErrorTestCase(ServicesTestCase): |
1001 | 1690 | self.assertEqual(self.ui.bookmarks.service_name, 'bookmarks') | 1757 | """The test suite for the services panel.""" |
1002 | 1691 | self.assertEqual(self.ui.bookmarks.button.get_label(), | 1758 | |
1003 | 1692 | self.ui.BOOKMARKS) | 1759 | def setUp(self): |
1004 | 1693 | self.assertTrue(self.ui.bookmarks.replication_service is | 1760 | super(ServicesWithDesktopcouchErrorTestCase, self).setUp() |
1005 | 1694 | self.ui.replication_service) | 1761 | self.ui.package_manager._installed[self.ui.DESKTOPCOUCH_PKG] = True |
1006 | 1695 | 1762 | ||
1007 | 1696 | def test_bookmarks_dependency(self): | 1763 | def test_no_pairing_record(self): |
1008 | 1697 | """The bookmarks dependency is correct.""" | 1764 | """The pairing record is not in place.""" |
1009 | 1698 | self.assertTrue(self.ui.bookmarks.dependency is not None) | 1765 | error_dict = {'error_type': 'NoPairingRecord'} |
1010 | 1699 | self.assertEqual(self.ui.bookmarks.dependency.package_name, | 1766 | self.ui.on_replications_info_error(error_dict) |
1011 | 1700 | self.ui.BINDWOOD_PKG) | 1767 | |
1012 | 1701 | 1768 | self.assertEqual(self.ui.replications.get_children(), []) | |
1013 | 1702 | def test_contacts(self): | 1769 | self.assertFalse(self.ui.message.active) |
1014 | 1703 | """The contacts is correct.""" | 1770 | self.assert_warning_correct(self.ui.message, self.ui.NO_PAIRING_RECORD) |
1015 | 1704 | self.assertEqual(self.ui.contacts.service_name, 'contacts') | 1771 | |
1016 | 1705 | self.assertEqual(self.ui.contacts.button.get_label(), | 1772 | def test_other_error(self): |
1017 | 1706 | self.ui.CONTACTS) | 1773 | """There was an error other than no pairing record.""" |
1018 | 1707 | self.assertTrue(self.ui.contacts.replication_service is | 1774 | error_dict = {'error_type': 'OtherError'} |
1019 | 1708 | self.ui.replication_service) | 1775 | self.ui.on_replications_info_error(error_dict) |
1020 | 1709 | 1776 | ||
1021 | 1710 | def test_contacts_dependency(self): | 1777 | self.assertEqual(self.ui.replications.get_children(), []) |
1022 | 1711 | """The contacts dependency is correct.""" | 1778 | self.assertFalse(self.ui.message.active) |
1023 | 1712 | self.assertTrue(self.ui.contacts.dependency is not None) | 1779 | self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR) |
1024 | 1713 | self.assertEqual(self.ui.contacts.dependency.package_name, | 1780 | |
1025 | 1714 | self.ui.EVOCOUCH_PKG) | 1781 | def test_empty_dict(self): |
1026 | 1715 | 1782 | """Handle empty dicts errors.""" | |
1027 | 1716 | 1783 | self.ui.on_replications_info_error(error_dict={}) | |
1028 | 1717 | class ServicesWithDCAndBindwoodTestCase(ServicesWithDesktopcouchTestCase): | 1784 | |
1029 | 1718 | """The test suite for the services panel.""" | 1785 | self.assertEqual(self.ui.replications.get_children(), []) |
1030 | 1719 | 1786 | self.assertFalse(self.ui.message.active) | |
1031 | 1720 | def setUp(self): | 1787 | self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR) |
1032 | 1721 | super(ServicesWithDCAndBindwoodTestCase, self).setUp() | 1788 | |
1033 | 1722 | self.ui.package_manager._installed[self.ui.BINDWOOD_PKG] = True | 1789 | def test_error_dict_none(self): |
1034 | 1723 | self.ui.load() | 1790 | """HGandle empty dicts errors.""" |
1035 | 1724 | 1791 | self.ui.on_replications_info_error(error_dict=None) | |
1036 | 1725 | def test_has_bindwood(self): | 1792 | |
1037 | 1726 | """Has bindwood installed?""" | 1793 | self.assertEqual(self.ui.replications.get_children(), []) |
1038 | 1727 | self.assertTrue(self.ui.has_bindwood) | 1794 | self.assertFalse(self.ui.message.active) |
1039 | 1728 | 1795 | self.assert_warning_correct(self.ui.message, gui.VALUE_ERROR) | |
979 | 1729 | def test_bookmarks_dependency(self): | ||
980 | 1730 | """The bookmarks dependency is correct.""" | ||
981 | 1731 | self.assertTrue(self.ui.bookmarks.dependency is None) | ||
982 | 1732 | |||
983 | 1733 | |||
984 | 1734 | class ServicesWithDCAndEvocouchTestCase(ServicesWithDesktopcouchTestCase): | ||
985 | 1735 | """The test suite for the services panel.""" | ||
986 | 1736 | |||
987 | 1737 | def setUp(self): | ||
988 | 1738 | super(ServicesWithDCAndEvocouchTestCase, self).setUp() | ||
989 | 1739 | self.ui.package_manager._installed[self.ui.EVOCOUCH_PKG] = True | ||
990 | 1740 | self.ui.load() | ||
991 | 1741 | |||
992 | 1742 | def test_has_evocouch(self): | ||
993 | 1743 | """Has evocoucg installed?""" | ||
994 | 1744 | self.assertTrue(self.ui.has_evocouch) | ||
995 | 1745 | |||
996 | 1746 | def test_contacts_dependency(self): | ||
997 | 1747 | """The bookmarks dependency is correct.""" | ||
998 | 1748 | self.assertTrue(self.ui.contacts.dependency is None) | ||
1040 | 1749 | 1796 | ||
1041 | 1750 | 1797 | ||
1042 | 1751 | class ManagementPanelTestCase(ControlPanelMixinTestCase): | 1798 | class ManagementPanelTestCase(ControlPanelMixinTestCase): |
1043 | 1752 | 1799 | ||
1044 | === modified file 'ubuntuone/controlpanel/integrationtests/test_dbus_service.py' | |||
1045 | --- ubuntuone/controlpanel/integrationtests/test_dbus_service.py 2010-12-23 18:20:56 +0000 | |||
1046 | +++ ubuntuone/controlpanel/integrationtests/test_dbus_service.py 2011-01-06 20:36:09 +0000 | |||
1047 | @@ -84,6 +84,11 @@ | |||
1048 | 84 | }, | 84 | }, |
1049 | 85 | ] | 85 | ] |
1050 | 86 | 86 | ||
1051 | 87 | SAMPLE_REPLICATIONS_INFO = [ | ||
1052 | 88 | {'replication_id': 'yadda', 'wait for it': 'awesome'}, | ||
1053 | 89 | {'replication_id': 'yoda', 'something else': 'awesome'}, | ||
1054 | 90 | ] | ||
1055 | 91 | |||
1056 | 87 | 92 | ||
1057 | 88 | class DBusServiceMainTestCase(mocker.MockerTestCase): | 93 | class DBusServiceMainTestCase(mocker.MockerTestCase): |
1058 | 89 | """Tests for the main function.""" | 94 | """Tests for the main function.""" |
1059 | @@ -166,6 +171,19 @@ | |||
1060 | 166 | """Configure a given volume.""" | 171 | """Configure a given volume.""" |
1061 | 167 | return self._process(volume_id) | 172 | return self._process(volume_id) |
1062 | 168 | 173 | ||
1063 | 174 | def replications_info(self): | ||
1064 | 175 | """Start the replication exclusion service if needed. | ||
1065 | 176 | |||
1066 | 177 | Return the replication info, which is a dictionary of (replication | ||
1067 | 178 | name, enabled). | ||
1068 | 179 | |||
1069 | 180 | """ | ||
1070 | 181 | return self._process(SAMPLE_REPLICATIONS_INFO) | ||
1071 | 182 | |||
1072 | 183 | def change_replication_settings(self, replication_id, settings): | ||
1073 | 184 | """Configure a given replication.""" | ||
1074 | 185 | return self._process(replication_id) | ||
1075 | 186 | |||
1076 | 169 | def query_bookmark_extension(self): | 187 | def query_bookmark_extension(self): |
1077 | 170 | """True if the bookmark extension has been installed.""" | 188 | """True if the bookmark extension has been installed.""" |
1078 | 171 | return self._process(False) | 189 | return self._process(False) |
1079 | @@ -258,13 +276,13 @@ | |||
1080 | 258 | self.assertEqual(expected, result) | 276 | self.assertEqual(expected, result) |
1081 | 259 | 277 | ||
1082 | 260 | 278 | ||
1085 | 261 | class OperationsTestCase(TestCase): | 279 | class BaseTestCase(TestCase): |
1086 | 262 | """Test for the DBus service operations.""" | 280 | """Base test case for the DBus service.""" |
1087 | 263 | 281 | ||
1088 | 264 | timeout = 3 | 282 | timeout = 3 |
1089 | 265 | 283 | ||
1090 | 266 | def setUp(self): | 284 | def setUp(self): |
1092 | 267 | super(OperationsTestCase, self).setUp() | 285 | super(BaseTestCase, self).setUp() |
1093 | 268 | dbus_service.init_mainloop() | 286 | dbus_service.init_mainloop() |
1094 | 269 | be = dbus_service.publish_backend(MockBackend()) | 287 | be = dbus_service.publish_backend(MockBackend()) |
1095 | 270 | self.addCleanup(be.remove_from_connection) | 288 | self.addCleanup(be.remove_from_connection) |
1096 | @@ -279,7 +297,7 @@ | |||
1097 | 279 | def tearDown(self): | 297 | def tearDown(self): |
1098 | 280 | self.backend = None | 298 | self.backend = None |
1099 | 281 | self.deferred = None | 299 | self.deferred = None |
1101 | 282 | super(OperationsTestCase, self).tearDown() | 300 | super(BaseTestCase, self).tearDown() |
1102 | 283 | 301 | ||
1103 | 284 | def got_error(self, *a): | 302 | def got_error(self, *a): |
1104 | 285 | """Some error happened in the DBus call.""" | 303 | """Some error happened in the DBus call.""" |
1105 | @@ -322,6 +340,10 @@ | |||
1106 | 322 | 340 | ||
1107 | 323 | return self.deferred | 341 | return self.deferred |
1108 | 324 | 342 | ||
1109 | 343 | |||
1110 | 344 | class OperationsTestCase(BaseTestCase): | ||
1111 | 345 | """Test for the DBus service operations.""" | ||
1112 | 346 | |||
1113 | 325 | def test_account_info_returned(self): | 347 | def test_account_info_returned(self): |
1114 | 326 | """The account info is successfully returned.""" | 348 | """The account info is successfully returned.""" |
1115 | 327 | 349 | ||
1116 | @@ -416,9 +438,9 @@ | |||
1117 | 416 | def test_volumes_info(self): | 438 | def test_volumes_info(self): |
1118 | 417 | """The volumes info is reported.""" | 439 | """The volumes info is reported.""" |
1119 | 418 | 440 | ||
1121 | 419 | def got_signal(volumes_dict): | 441 | def got_signal(volumes): |
1122 | 420 | """The correct info was received.""" | 442 | """The correct info was received.""" |
1124 | 421 | self.assertEqual(volumes_dict, SAMPLE_VOLUMES_INFO) | 443 | self.assertEqual(volumes, SAMPLE_VOLUMES_INFO) |
1125 | 422 | self.deferred.callback("success") | 444 | self.deferred.callback("success") |
1126 | 423 | 445 | ||
1127 | 424 | args = ("VolumesInfoReady", "VolumesInfoError", got_signal, | 446 | args = ("VolumesInfoReady", "VolumesInfoError", got_signal, |
1128 | @@ -439,6 +461,32 @@ | |||
1129 | 439 | expected_volume_id, {'subscribed': ''}) | 461 | expected_volume_id, {'subscribed': ''}) |
1130 | 440 | return self.assert_correct_method_call(*args) | 462 | return self.assert_correct_method_call(*args) |
1131 | 441 | 463 | ||
1132 | 464 | def test_replications_info(self): | ||
1133 | 465 | """The replications info is reported.""" | ||
1134 | 466 | |||
1135 | 467 | def got_signal(replications): | ||
1136 | 468 | """The correct info was received.""" | ||
1137 | 469 | self.assertEqual(replications, SAMPLE_REPLICATIONS_INFO) | ||
1138 | 470 | self.deferred.callback("success") | ||
1139 | 471 | |||
1140 | 472 | args = ("ReplicationsInfoReady", "ReplicationsInfoError", got_signal, | ||
1141 | 473 | self.backend.replications_info) | ||
1142 | 474 | return self.assert_correct_method_call(*args) | ||
1143 | 475 | |||
1144 | 476 | def test_change_replication_settings(self): | ||
1145 | 477 | """The replication settings are successfully changed.""" | ||
1146 | 478 | expected_replication_id = SAMPLE_REPLICATIONS_INFO[0]['replication_id'] | ||
1147 | 479 | |||
1148 | 480 | def got_signal(replication_id): | ||
1149 | 481 | """The correct replication was changed.""" | ||
1150 | 482 | self.assertEqual(replication_id, expected_replication_id) | ||
1151 | 483 | self.deferred.callback("success") | ||
1152 | 484 | |||
1153 | 485 | args = ("ReplicationSettingsChanged", "ReplicationSettingsChangeError", | ||
1154 | 486 | got_signal, self.backend.change_replication_settings, | ||
1155 | 487 | expected_replication_id, {'enabled': ''}) | ||
1156 | 488 | return self.assert_correct_method_call(*args) | ||
1157 | 489 | |||
1158 | 442 | def test_query_bookmarks_extension(self): | 490 | def test_query_bookmarks_extension(self): |
1159 | 443 | """The bookmarks extension is queried.""" | 491 | """The bookmarks extension is queried.""" |
1160 | 444 | 492 | ||
1161 | @@ -495,7 +543,7 @@ | |||
1162 | 495 | error_sig, success_sig, got_error_signal, method, *args) | 543 | error_sig, success_sig, got_error_signal, method, *args) |
1163 | 496 | 544 | ||
1164 | 497 | 545 | ||
1166 | 498 | class FileSyncTestCase(OperationsTestCase): | 546 | class FileSyncTestCase(BaseTestCase): |
1167 | 499 | """Test for the DBus service when requesting file sync status.""" | 547 | """Test for the DBus service when requesting file sync status.""" |
1168 | 500 | 548 | ||
1169 | 501 | def assert_correct_status_signal(self, status, sync_signal, | 549 | def assert_correct_status_signal(self, status, sync_signal, |
1170 | 502 | 550 | ||
1171 | === modified file 'ubuntuone/controlpanel/logger.py' | |||
1172 | --- ubuntuone/controlpanel/logger.py 2010-12-23 18:20:56 +0000 | |||
1173 | +++ ubuntuone/controlpanel/logger.py 2011-01-06 20:36:09 +0000 | |||
1174 | @@ -53,10 +53,7 @@ | |||
1175 | 53 | logger.addHandler(MAIN_HANDLER) | 53 | logger.addHandler(MAIN_HANDLER) |
1176 | 54 | if os.environ.get('DEBUG'): | 54 | if os.environ.get('DEBUG'): |
1177 | 55 | debug_handler = logging.StreamHandler(sys.stderr) | 55 | debug_handler = logging.StreamHandler(sys.stderr) |
1182 | 56 | if prefix is not None: | 56 | debug_handler.setFormatter(basic_formatter) |
1179 | 57 | fmt = prefix + "%(name)s - %(levelname)s\n%(message)s\n" | ||
1180 | 58 | formatter = logging.Formatter(fmt) | ||
1181 | 59 | debug_handler.setFormatter(formatter) | ||
1183 | 60 | logger.addHandler(debug_handler) | 57 | logger.addHandler(debug_handler) |
1184 | 61 | 58 | ||
1185 | 62 | return logger | 59 | return logger |
1186 | 63 | 60 | ||
1187 | === added file 'ubuntuone/controlpanel/replication_client.py' | |||
1188 | --- ubuntuone/controlpanel/replication_client.py 1970-01-01 00:00:00 +0000 | |||
1189 | +++ ubuntuone/controlpanel/replication_client.py 2011-01-06 20:36:09 +0000 | |||
1190 | @@ -0,0 +1,115 @@ | |||
1191 | 1 | # -*- coding: utf-8 -*- | ||
1192 | 2 | |||
1193 | 3 | # Authors: Natalia B. Bidart <nataliabidart@canonical.com> | ||
1194 | 4 | # | ||
1195 | 5 | # Copyright 2010 Canonical Ltd. | ||
1196 | 6 | # | ||
1197 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
1198 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
1199 | 9 | # by the Free Software Foundation. | ||
1200 | 10 | # | ||
1201 | 11 | # This program is distributed in the hope that it will be useful, but | ||
1202 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1203 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
1204 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
1205 | 15 | # | ||
1206 | 16 | # You should have received a copy of the GNU General Public License along | ||
1207 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1208 | 18 | |||
1209 | 19 | """Client to use replication services.""" | ||
1210 | 20 | |||
1211 | 21 | from twisted.internet.defer import Deferred, inlineCallbacks, returnValue | ||
1212 | 22 | |||
1213 | 23 | from ubuntuone.controlpanel.logger import setup_logging | ||
1214 | 24 | |||
1215 | 25 | |||
1216 | 26 | logger = setup_logging('replication_client') | ||
1217 | 27 | |||
1218 | 28 | BOOKMARKS = 'bookmarks' | ||
1219 | 29 | CONTACTS = 'contacts' | ||
1220 | 30 | # we should get this list from somewhere else | ||
1221 | 31 | REPLICATIONS = set([BOOKMARKS, CONTACTS]) | ||
1222 | 32 | |||
1223 | 33 | |||
1224 | 34 | class ReplicationError(Exception): | ||
1225 | 35 | """A replication error.""" | ||
1226 | 36 | |||
1227 | 37 | |||
1228 | 38 | class NoPairingRecord(ReplicationError): | ||
1229 | 39 | """There is no pairing record.""" | ||
1230 | 40 | |||
1231 | 41 | |||
1232 | 42 | class InvalidIdError(ReplicationError): | ||
1233 | 43 | """The replication id is not valid.""" | ||
1234 | 44 | |||
1235 | 45 | |||
1236 | 46 | class NotExcludedError(ReplicationError): | ||
1237 | 47 | """The replication can not be replicated since is not excluded.""" | ||
1238 | 48 | |||
1239 | 49 | |||
1240 | 50 | class AlreadyExcludedError(ReplicationError): | ||
1241 | 51 | """The replication can not be excluded since is already excluded.""" | ||
1242 | 52 | |||
1243 | 53 | |||
1244 | 54 | def get_replication_proxy(replication_module=None): | ||
1245 | 55 | """Return a proxy to the replication client.""" | ||
1246 | 56 | d = Deferred() | ||
1247 | 57 | if replication_module is None: | ||
1248 | 58 | # delay import in case DC is not installed at module import time | ||
1249 | 59 | # Unable to import 'desktopcouch.application.replication_services' | ||
1250 | 60 | # pylint: disable=F0401 | ||
1251 | 61 | from desktopcouch.application.replication_services \ | ||
1252 | 62 | import ubuntuone as replication_module | ||
1253 | 63 | try: | ||
1254 | 64 | result = replication_module.ReplicationExclusion() | ||
1255 | 65 | except ValueError: | ||
1256 | 66 | d.errback(NoPairingRecord()) | ||
1257 | 67 | else: | ||
1258 | 68 | d.callback(result) | ||
1259 | 69 | |||
1260 | 70 | return d | ||
1261 | 71 | |||
1262 | 72 | |||
1263 | 73 | @inlineCallbacks | ||
1264 | 74 | def get_replications(): | ||
1265 | 75 | """Retrieve the list of replications.""" | ||
1266 | 76 | yield get_replication_proxy() | ||
1267 | 77 | returnValue(REPLICATIONS) | ||
1268 | 78 | |||
1269 | 79 | |||
1270 | 80 | @inlineCallbacks | ||
1271 | 81 | def get_exclusions(): | ||
1272 | 82 | """Retrieve the list of exclusions.""" | ||
1273 | 83 | proxy = yield get_replication_proxy() | ||
1274 | 84 | result = proxy.all_exclusions() | ||
1275 | 85 | returnValue(result) | ||
1276 | 86 | |||
1277 | 87 | |||
1278 | 88 | @inlineCallbacks | ||
1279 | 89 | def replicate(replication_id): | ||
1280 | 90 | """Remove replication_id from the exclusions list.""" | ||
1281 | 91 | replications = yield get_replications() | ||
1282 | 92 | if replication_id not in replications: | ||
1283 | 93 | raise InvalidIdError(replication_id) | ||
1284 | 94 | |||
1285 | 95 | exclusions = yield get_exclusions() | ||
1286 | 96 | if replication_id not in exclusions: | ||
1287 | 97 | raise NotExcludedError(replication_id) | ||
1288 | 98 | |||
1289 | 99 | proxy = yield get_replication_proxy() | ||
1290 | 100 | yield proxy.replicate(replication_id) | ||
1291 | 101 | |||
1292 | 102 | |||
1293 | 103 | @inlineCallbacks | ||
1294 | 104 | def exclude(replication_id): | ||
1295 | 105 | """Add replication_id to the exclusions list.""" | ||
1296 | 106 | replications = yield get_replications() | ||
1297 | 107 | if replication_id not in replications: | ||
1298 | 108 | raise InvalidIdError(replication_id) | ||
1299 | 109 | |||
1300 | 110 | exclusions = yield get_exclusions() | ||
1301 | 111 | if replication_id in exclusions: | ||
1302 | 112 | raise AlreadyExcludedError(replication_id) | ||
1303 | 113 | |||
1304 | 114 | proxy = yield get_replication_proxy() | ||
1305 | 115 | yield proxy.exclude(replication_id) | ||
1306 | 0 | 116 | ||
1307 | === modified file 'ubuntuone/controlpanel/tests/__init__.py' | |||
1308 | --- ubuntuone/controlpanel/tests/__init__.py 2010-12-20 16:11:13 +0000 | |||
1309 | +++ ubuntuone/controlpanel/tests/__init__.py 2011-01-06 20:36:09 +0000 | |||
1310 | @@ -24,9 +24,157 @@ | |||
1311 | 24 | TOKEN = {u'consumer_key': u'xQ7xDAz', | 24 | TOKEN = {u'consumer_key': u'xQ7xDAz', |
1312 | 25 | u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy', | 25 | u'consumer_secret': u'KzCJWCTNbbntwfyCKKjomJDzlgqxLy', |
1313 | 26 | u'token_name': u'test', | 26 | u'token_name': u'test', |
1315 | 27 | u'token': u'GkInOfSMGwTXAUoVQwLUoPxElEEUdhsLVNTPhxHJDUIeHCPNEo', | 27 | u'token': u'ABCDEF01234-localtoken', |
1316 | 28 | u'token_secret': u'qFYImEtlczPbsCnYyuwLoPDlPEnvNcIktZphPQklAWrvyfFMV'} | 28 | u'token_secret': u'qFYImEtlczPbsCnYyuwLoPDlPEnvNcIktZphPQklAWrvyfFMV'} |
1317 | 29 | 29 | ||
1318 | 30 | SAMPLE_ACCOUNT_JSON = """ | ||
1319 | 31 | { | ||
1320 | 32 | "username": "andrewpz", | ||
1321 | 33 | "openid": "https://login.launchpad.net/+id/abcdefg", | ||
1322 | 34 | "first_name": "Andrew P.", | ||
1323 | 35 | "last_name": "Zoilo", | ||
1324 | 36 | "couchdb": { | ||
1325 | 37 | "host": "https://couchdb.one.ubuntu.com", | ||
1326 | 38 | "root": "https://couchdb.one.ubuntu.com/u/abc/def/12345", | ||
1327 | 39 | "dbpath": "u/abc/def/12345" | ||
1328 | 40 | }, | ||
1329 | 41 | "couchdb_root": "https://couchdb.one.ubuntu.com/u/abc/def/12345", | ||
1330 | 42 | "email": "andrewpz@protocultura.net",%s | ||
1331 | 43 | "nickname": "Andrew P. Zoilo", | ||
1332 | 44 | "id": 12345, | ||
1333 | 45 | "subscription": { | ||
1334 | 46 | "upgrade_available": false, | ||
1335 | 47 | "description": "Paid Plan, 50 GB of storage", | ||
1336 | 48 | "trial": false, | ||
1337 | 49 | "started": "2010-03-24T18:38:38Z", | ||
1338 | 50 | "is_paid": true, | ||
1339 | 51 | "expires": null, | ||
1340 | 52 | "qty": 1, | ||
1341 | 53 | "price": 0.0, | ||
1342 | 54 | "currency": null, | ||
1343 | 55 | "id": 654321, | ||
1344 | 56 | "name": "50 GB" | ||
1345 | 57 | } | ||
1346 | 58 | } | ||
1347 | 59 | """ | ||
1348 | 60 | |||
1349 | 61 | CURRENT_PLAN = "Ubuntu One Basic (2 GB) + 1 x 20-Pack with 20 GB (monthly)" | ||
1350 | 62 | SAMPLE_CURRENT_PLAN = '\n "current_plan": "%s",' % CURRENT_PLAN | ||
1351 | 63 | |||
1352 | 64 | SAMPLE_ACCOUNT_NO_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % '' | ||
1353 | 65 | SAMPLE_ACCOUNT_WITH_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % SAMPLE_CURRENT_PLAN | ||
1354 | 66 | |||
1355 | 67 | |||
1356 | 68 | SAMPLE_QUOTA_JSON = """ | ||
1357 | 69 | { | ||
1358 | 70 | "total": 53687091200, | ||
1359 | 71 | "used": 2350345156 | ||
1360 | 72 | } | ||
1361 | 73 | """ | ||
1362 | 74 | |||
1363 | 75 | EXPECTED_ACCOUNT_INFO = { | ||
1364 | 76 | "quota_used": "2350345156", | ||
1365 | 77 | "quota_total": "53687091200", | ||
1366 | 78 | "type": "Paid Plan, 50 GB of storage", | ||
1367 | 79 | "name": "Andrew P. Zoilo", | ||
1368 | 80 | "email": "andrewpz@protocultura.net", | ||
1369 | 81 | } | ||
1370 | 82 | |||
1371 | 83 | EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN = { | ||
1372 | 84 | "quota_used": "2350345156", | ||
1373 | 85 | "quota_total": "53687091200", | ||
1374 | 86 | "type": CURRENT_PLAN, | ||
1375 | 87 | "name": "Andrew P. Zoilo", | ||
1376 | 88 | "email": "andrewpz@protocultura.net", | ||
1377 | 89 | } | ||
1378 | 90 | |||
1379 | 91 | SAMPLE_DEVICES_JSON = """ | ||
1380 | 92 | [ | ||
1381 | 93 | { | ||
1382 | 94 | "token": "ABCDEF01234token", | ||
1383 | 95 | "description": "Ubuntu One @ darkstar", | ||
1384 | 96 | "kind": "Computer" | ||
1385 | 97 | }, | ||
1386 | 98 | { | ||
1387 | 99 | "token": "ABCDEF01234-localtoken", | ||
1388 | 100 | "description": "Ubuntu One @ localhost", | ||
1389 | 101 | "kind": "Computer" | ||
1390 | 102 | }, | ||
1391 | 103 | { | ||
1392 | 104 | "kind": "Phone", | ||
1393 | 105 | "description": "Nokia E65", | ||
1394 | 106 | "id": 1000 | ||
1395 | 107 | } | ||
1396 | 108 | ] | ||
1397 | 109 | """ | ||
1398 | 110 | |||
1399 | 111 | EXPECTED_DEVICES_INFO = [ | ||
1400 | 112 | { | ||
1401 | 113 | "device_id": "ComputerABCDEF01234token", | ||
1402 | 114 | "name": "Ubuntu One @ darkstar", | ||
1403 | 115 | "type": "Computer", | ||
1404 | 116 | "is_local": '', | ||
1405 | 117 | "configurable": '', | ||
1406 | 118 | }, | ||
1407 | 119 | { | ||
1408 | 120 | 'is_local': 'True', | ||
1409 | 121 | 'configurable': 'True', | ||
1410 | 122 | 'device_id': 'ComputerABCDEF01234-localtoken', | ||
1411 | 123 | 'limit_bandwidth': '', | ||
1412 | 124 | 'max_download_speed': '-1', | ||
1413 | 125 | 'max_upload_speed': '-1', | ||
1414 | 126 | 'name': 'Ubuntu One @ localhost', | ||
1415 | 127 | 'type': 'Computer' | ||
1416 | 128 | }, | ||
1417 | 129 | { | ||
1418 | 130 | "device_id": "Phone1000", | ||
1419 | 131 | "name": "Nokia E65", | ||
1420 | 132 | "type": "Phone", | ||
1421 | 133 | "configurable": '', | ||
1422 | 134 | "is_local": '', | ||
1423 | 135 | }, | ||
1424 | 136 | ] | ||
1425 | 137 | |||
1426 | 138 | SAMPLE_FOLDERS = [ | ||
1427 | 139 | {u'generation': u'2', u'node_id': u'341da068-81d8-437a-8f75-5bb9d86455ba', | ||
1428 | 140 | u'path': u'/home/tester/Public', u'subscribed': u'True', | ||
1429 | 141 | u'suggested_path': u'~/Public', | ||
1430 | 142 | u'type': u'UDF', u'volume_id': u'9ea892f8-15fa-4201-bdbf-8de99fa5f588'}, | ||
1431 | 143 | {u'generation': u'', u'node_id': u'11fbc86c-0d7a-49f5-ae83-8402caf66c6a', | ||
1432 | 144 | u'path': u'/home/tester/Documents', u'subscribed': u'', | ||
1433 | 145 | u'suggested_path': u'~/Documents', | ||
1434 | 146 | u'type': u'UDF', u'volume_id': u'2db262f5-a151-4c19-969c-bb5ced753c61'}, | ||
1435 | 147 | {u'generation': u'24', u'node_id': u'9ee0e130-a7c7-4d76-a5e3-5df506221b48', | ||
1436 | 148 | u'path': u'/home/tester/Pictures/Photos', u'subscribed': u'True', | ||
1437 | 149 | u'suggested_path': u'~/Pictures/Photos', | ||
1438 | 150 | u'type': u'UDF', u'volume_id': u'1deb2874-3d28-46ae-9999-d5f48de9f460'}, | ||
1439 | 151 | ] | ||
1440 | 152 | |||
1441 | 153 | SAMPLE_SHARES = [ | ||
1442 | 154 | {u'accepted': u'True', u'access_level': u'View', | ||
1443 | 155 | u'free_bytes': u'39892622746', u'generation': u'2704', | ||
1444 | 156 | u'name': u're', u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', | ||
1445 | 157 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1446 | 158 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', | ||
1447 | 159 | u'type': u'Share', u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, | ||
1448 | 160 | {u'accepted': u'True', u'access_level': u'Modify', | ||
1449 | 161 | u'free_bytes': u'39892622746', u'generation': u'2704', | ||
1450 | 162 | u'name': u'do', u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', | ||
1451 | 163 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1452 | 164 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', | ||
1453 | 165 | u'type': u'Share', u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, | ||
1454 | 166 | ] | ||
1455 | 167 | |||
1456 | 168 | SAMPLE_SHARED = [ | ||
1457 | 169 | {u'accepted': u'True', u'access_level': u'View', | ||
1458 | 170 | u'free_bytes': u'', u'generation': u'', | ||
1459 | 171 | u'name': u'bar', u'node_id': u'31e47530-9448-4f03-b4dc-4154fdf35225', | ||
1460 | 172 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1461 | 173 | u'path': u'/home/tester/Ubuntu One/bar', | ||
1462 | 174 | u'type': u'Shared', | ||
1463 | 175 | u'volume_id': u'79584900-517f-4dff-b2f3-20e8c1e79365'}, | ||
1464 | 176 | ] | ||
1465 | 177 | |||
1466 | 30 | 178 | ||
1467 | 31 | class TestCase(BaseTestCase): | 179 | class TestCase(BaseTestCase): |
1468 | 32 | """Basics for testing.""" | 180 | """Basics for testing.""" |
1469 | 33 | 181 | ||
1470 | === modified file 'ubuntuone/controlpanel/tests/test_backend.py' | |||
1471 | --- ubuntuone/controlpanel/tests/test_backend.py 2010-12-23 18:20:56 +0000 | |||
1472 | +++ ubuntuone/controlpanel/tests/test_backend.py 2011-01-06 20:36:09 +0000 | |||
1473 | @@ -25,9 +25,9 @@ | |||
1474 | 25 | from twisted.internet.defer import inlineCallbacks | 25 | from twisted.internet.defer import inlineCallbacks |
1475 | 26 | from ubuntuone.devtools.handlers import MementoHandler | 26 | from ubuntuone.devtools.handlers import MementoHandler |
1476 | 27 | 27 | ||
1480 | 28 | from ubuntuone.controlpanel import backend | 28 | from ubuntuone.controlpanel import backend, replication_client |
1481 | 29 | from ubuntuone.controlpanel.backend import (ACCOUNT_API, | 29 | from ubuntuone.controlpanel.backend import (bool_str, |
1482 | 30 | DEVICES_API, DEVICE_REMOVE_API, QUOTA_API, | 30 | ACCOUNT_API, DEVICES_API, DEVICE_REMOVE_API, QUOTA_API, |
1483 | 31 | FILE_SYNC_DISABLED, | 31 | FILE_SYNC_DISABLED, |
1484 | 32 | FILE_SYNC_DISCONNECTED, | 32 | FILE_SYNC_DISCONNECTED, |
1485 | 33 | FILE_SYNC_ERROR, | 33 | FILE_SYNC_ERROR, |
1486 | @@ -37,160 +37,21 @@ | |||
1487 | 37 | FILE_SYNC_UNKNOWN, | 37 | FILE_SYNC_UNKNOWN, |
1488 | 38 | MSG_KEY, STATUS_KEY, | 38 | MSG_KEY, STATUS_KEY, |
1489 | 39 | ) | 39 | ) |
1492 | 40 | 40 | from ubuntuone.controlpanel.tests import (TestCase, | |
1493 | 41 | from ubuntuone.controlpanel.tests import TestCase | 41 | EXPECTED_ACCOUNT_INFO, |
1494 | 42 | EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN, | ||
1495 | 43 | EXPECTED_DEVICES_INFO, | ||
1496 | 44 | SAMPLE_ACCOUNT_NO_CURRENT_PLAN, | ||
1497 | 45 | SAMPLE_ACCOUNT_WITH_CURRENT_PLAN, | ||
1498 | 46 | SAMPLE_DEVICES_JSON, | ||
1499 | 47 | SAMPLE_FOLDERS, | ||
1500 | 48 | SAMPLE_QUOTA_JSON, | ||
1501 | 49 | SAMPLE_SHARED, | ||
1502 | 50 | SAMPLE_SHARES, | ||
1503 | 51 | TOKEN, | ||
1504 | 52 | ) | ||
1505 | 42 | from ubuntuone.controlpanel.webclient import WebClientError | 53 | from ubuntuone.controlpanel.webclient import WebClientError |
1506 | 43 | 54 | ||
1507 | 44 | SAMPLE_CREDENTIALS = {"token": "ABC1234DEF"} | ||
1508 | 45 | |||
1509 | 46 | SAMPLE_ACCOUNT_JSON = """ | ||
1510 | 47 | { | ||
1511 | 48 | "username": "andrewpz", | ||
1512 | 49 | "openid": "https://login.launchpad.net/+id/abcdefg", | ||
1513 | 50 | "first_name": "Andrew P.", | ||
1514 | 51 | "last_name": "Zoilo", | ||
1515 | 52 | "couchdb": { | ||
1516 | 53 | "host": "https://couchdb.one.ubuntu.com", | ||
1517 | 54 | "root": "https://couchdb.one.ubuntu.com/u/abc/def/12345", | ||
1518 | 55 | "dbpath": "u/abc/def/12345" | ||
1519 | 56 | }, | ||
1520 | 57 | "couchdb_root": "https://couchdb.one.ubuntu.com/u/abc/def/12345", | ||
1521 | 58 | "email": "andrewpz@protocultura.net",%s | ||
1522 | 59 | "nickname": "Andrew P. Zoilo", | ||
1523 | 60 | "id": 12345, | ||
1524 | 61 | "subscription": { | ||
1525 | 62 | "upgrade_available": false, | ||
1526 | 63 | "description": "Paid Plan, 50 GB of storage", | ||
1527 | 64 | "trial": false, | ||
1528 | 65 | "started": "2010-03-24T18:38:38Z", | ||
1529 | 66 | "is_paid": true, | ||
1530 | 67 | "expires": null, | ||
1531 | 68 | "qty": 1, | ||
1532 | 69 | "price": 0.0, | ||
1533 | 70 | "currency": null, | ||
1534 | 71 | "id": 654321, | ||
1535 | 72 | "name": "50 GB" | ||
1536 | 73 | } | ||
1537 | 74 | } | ||
1538 | 75 | """ | ||
1539 | 76 | |||
1540 | 77 | CURRENT_PLAN = "Ubuntu One Basic (2 GB) + 1 x 20-Pack with 20 GB (monthly)" | ||
1541 | 78 | SAMPLE_CURRENT_PLAN = '\n "current_plan": "%s",' % CURRENT_PLAN | ||
1542 | 79 | |||
1543 | 80 | SAMPLE_ACCOUNT_NO_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % '' | ||
1544 | 81 | SAMPLE_ACCOUNT_WITH_CURRENT_PLAN = SAMPLE_ACCOUNT_JSON % SAMPLE_CURRENT_PLAN | ||
1545 | 82 | |||
1546 | 83 | |||
1547 | 84 | SAMPLE_QUOTA_JSON = """ | ||
1548 | 85 | { | ||
1549 | 86 | "total": 53687091200, | ||
1550 | 87 | "used": 2350345156 | ||
1551 | 88 | } | ||
1552 | 89 | """ | ||
1553 | 90 | |||
1554 | 91 | EXPECTED_ACCOUNT_INFO = { | ||
1555 | 92 | "quota_used": "2350345156", | ||
1556 | 93 | "quota_total": "53687091200", | ||
1557 | 94 | "type": "Paid Plan, 50 GB of storage", | ||
1558 | 95 | "name": "Andrew P. Zoilo", | ||
1559 | 96 | "email": "andrewpz@protocultura.net", | ||
1560 | 97 | } | ||
1561 | 98 | |||
1562 | 99 | EXPECTED_ACCOUNT_INFO_WITH_CURRENT_PLAN = { | ||
1563 | 100 | "quota_used": "2350345156", | ||
1564 | 101 | "quota_total": "53687091200", | ||
1565 | 102 | "type": CURRENT_PLAN, | ||
1566 | 103 | "name": "Andrew P. Zoilo", | ||
1567 | 104 | "email": "andrewpz@protocultura.net", | ||
1568 | 105 | } | ||
1569 | 106 | |||
1570 | 107 | SAMPLE_DEVICES_JSON = """ | ||
1571 | 108 | [ | ||
1572 | 109 | { | ||
1573 | 110 | "token": "ABCDEF01234token", | ||
1574 | 111 | "description": "Ubuntu One @ darkstar", | ||
1575 | 112 | "kind": "Computer" | ||
1576 | 113 | }, | ||
1577 | 114 | { | ||
1578 | 115 | "token": "ABC1234DEF", | ||
1579 | 116 | "description": "Ubuntu One @ localhost", | ||
1580 | 117 | "kind": "Computer" | ||
1581 | 118 | }, | ||
1582 | 119 | { | ||
1583 | 120 | "kind": "Phone", | ||
1584 | 121 | "description": "Nokia E65", | ||
1585 | 122 | "id": 1000 | ||
1586 | 123 | } | ||
1587 | 124 | ] | ||
1588 | 125 | """ | ||
1589 | 126 | |||
1590 | 127 | EXPECTED_DEVICES_INFO = [ | ||
1591 | 128 | { | ||
1592 | 129 | "device_id": "ComputerABCDEF01234token", | ||
1593 | 130 | "name": "Ubuntu One @ darkstar", | ||
1594 | 131 | "type": "Computer", | ||
1595 | 132 | "is_local": '', | ||
1596 | 133 | "configurable": '', | ||
1597 | 134 | }, | ||
1598 | 135 | { | ||
1599 | 136 | 'is_local': 'True', | ||
1600 | 137 | 'configurable': 'True', | ||
1601 | 138 | 'device_id': 'ComputerABC1234DEF', | ||
1602 | 139 | 'limit_bandwidth': '', | ||
1603 | 140 | 'max_download_speed': '-1', | ||
1604 | 141 | 'max_upload_speed': '-1', | ||
1605 | 142 | 'name': 'Ubuntu One @ localhost', | ||
1606 | 143 | 'type': 'Computer' | ||
1607 | 144 | }, | ||
1608 | 145 | { | ||
1609 | 146 | "device_id": "Phone1000", | ||
1610 | 147 | "name": "Nokia E65", | ||
1611 | 148 | "type": "Phone", | ||
1612 | 149 | "configurable": '', | ||
1613 | 150 | "is_local": '', | ||
1614 | 151 | }, | ||
1615 | 152 | ] | ||
1616 | 153 | |||
1617 | 154 | SAMPLE_FOLDERS = [ | ||
1618 | 155 | {u'generation': u'2', u'node_id': u'341da068-81d8-437a-8f75-5bb9d86455ba', | ||
1619 | 156 | u'path': u'/home/tester/Public', u'subscribed': u'True', | ||
1620 | 157 | u'suggested_path': u'~/Public', | ||
1621 | 158 | u'type': u'UDF', u'volume_id': u'9ea892f8-15fa-4201-bdbf-8de99fa5f588'}, | ||
1622 | 159 | {u'generation': u'', u'node_id': u'11fbc86c-0d7a-49f5-ae83-8402caf66c6a', | ||
1623 | 160 | u'path': u'/home/tester/Documents', u'subscribed': u'', | ||
1624 | 161 | u'suggested_path': u'~/Documents', | ||
1625 | 162 | u'type': u'UDF', u'volume_id': u'2db262f5-a151-4c19-969c-bb5ced753c61'}, | ||
1626 | 163 | {u'generation': u'24', u'node_id': u'9ee0e130-a7c7-4d76-a5e3-5df506221b48', | ||
1627 | 164 | u'path': u'/home/tester/Pictures/Photos', u'subscribed': u'True', | ||
1628 | 165 | u'suggested_path': u'~/Pictures/Photos', | ||
1629 | 166 | u'type': u'UDF', u'volume_id': u'1deb2874-3d28-46ae-9999-d5f48de9f460'}, | ||
1630 | 167 | ] | ||
1631 | 168 | |||
1632 | 169 | SAMPLE_SHARES = [ | ||
1633 | 170 | {u'accepted': u'True', u'access_level': u'View', | ||
1634 | 171 | u'free_bytes': u'39892622746', u'generation': u'2704', | ||
1635 | 172 | u'name': u're', u'node_id': u'c483f419-ed28-490a-825d-a8c074e2d795', | ||
1636 | 173 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1637 | 174 | u'path': u'/home/tester/.local/share/ubuntuone/shares/re from Other User', | ||
1638 | 175 | u'type': u'Share', u'volume_id': u'4a1b263b-a2b3-4f66-9e66-4cd18050810d'}, | ||
1639 | 176 | {u'accepted': u'True', u'access_level': u'Modify', | ||
1640 | 177 | u'free_bytes': u'39892622746', u'generation': u'2704', | ||
1641 | 178 | u'name': u'do', u'node_id': u'84544ea4-aefe-4f91-9bb9-ed7b0a805baf', | ||
1642 | 179 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1643 | 180 | u'path': u'/home/tester/.local/share/ubuntuone/shares/do from Other User', | ||
1644 | 181 | u'type': u'Share', u'volume_id': u'7d130dfe-98b2-4bd5-8708-9eeba9838ac0'}, | ||
1645 | 182 | ] | ||
1646 | 183 | |||
1647 | 184 | SAMPLE_SHARED = [ | ||
1648 | 185 | {u'accepted': u'True', u'access_level': u'View', | ||
1649 | 186 | u'free_bytes': u'', u'generation': u'', | ||
1650 | 187 | u'name': u'bar', u'node_id': u'31e47530-9448-4f03-b4dc-4154fdf35225', | ||
1651 | 188 | u'other_username': u'otheruser', u'other_visible_name': u'Other User', | ||
1652 | 189 | u'path': u'/home/tester/Ubuntu One/bar', | ||
1653 | 190 | u'type': u'Shared', | ||
1654 | 191 | u'volume_id': u'79584900-517f-4dff-b2f3-20e8c1e79365'}, | ||
1655 | 192 | ] | ||
1656 | 193 | |||
1657 | 194 | 55 | ||
1658 | 195 | class MockWebClient(object): | 56 | class MockWebClient(object): |
1659 | 196 | """A mock webclient.""" | 57 | """A mock webclient.""" |
1660 | @@ -213,7 +74,7 @@ | |||
1661 | 213 | class MockDBusClient(object): | 74 | class MockDBusClient(object): |
1662 | 214 | """A mock dbus_client module.""" | 75 | """A mock dbus_client module.""" |
1663 | 215 | 76 | ||
1665 | 216 | creds = SAMPLE_CREDENTIALS | 77 | creds = TOKEN |
1666 | 217 | throttling = False | 78 | throttling = False |
1667 | 218 | limits = {"download": -1, "upload": -1} | 79 | limits = {"download": -1, "upload": -1} |
1668 | 219 | file_sync = True | 80 | file_sync = True |
1669 | @@ -292,6 +153,36 @@ | |||
1670 | 292 | return SAMPLE_SHARED | 153 | return SAMPLE_SHARED |
1671 | 293 | 154 | ||
1672 | 294 | 155 | ||
1673 | 156 | class MockReplicationClient(object): | ||
1674 | 157 | """A mock replication_client module.""" | ||
1675 | 158 | |||
1676 | 159 | BOOKMARKS = 'awesome' | ||
1677 | 160 | CONTACTS = 'legendary' | ||
1678 | 161 | |||
1679 | 162 | replications = set([BOOKMARKS, CONTACTS, 'other']) | ||
1680 | 163 | exclusions = set([CONTACTS]) | ||
1681 | 164 | |||
1682 | 165 | def get_replications(self): | ||
1683 | 166 | """Grab the list of replications in this machine.""" | ||
1684 | 167 | return MockReplicationClient.replications | ||
1685 | 168 | |||
1686 | 169 | def get_exclusions(self): | ||
1687 | 170 | """Grab the list of exclusions in this machine.""" | ||
1688 | 171 | return MockReplicationClient.exclusions | ||
1689 | 172 | |||
1690 | 173 | def replicate(self, replication_id): | ||
1691 | 174 | """Remove replication_id from the exclusions list.""" | ||
1692 | 175 | if replication_id not in MockReplicationClient.replications: | ||
1693 | 176 | raise replication_client.ReplicationError(replication_id) | ||
1694 | 177 | MockReplicationClient.exclusions.remove(replication_id) | ||
1695 | 178 | |||
1696 | 179 | def exclude(self, replication_id): | ||
1697 | 180 | """Add replication_id to the exclusions list.""" | ||
1698 | 181 | if replication_id not in MockReplicationClient.replications: | ||
1699 | 182 | raise replication_client.ReplicationError(replication_id) | ||
1700 | 183 | MockReplicationClient.exclusions.add(replication_id) | ||
1701 | 184 | |||
1702 | 185 | |||
1703 | 295 | class BackendBasicTestCase(TestCase): | 186 | class BackendBasicTestCase(TestCase): |
1704 | 296 | """Simple tests for the backend.""" | 187 | """Simple tests for the backend.""" |
1705 | 297 | 188 | ||
1706 | @@ -301,13 +192,14 @@ | |||
1707 | 301 | super(BackendBasicTestCase, self).setUp() | 192 | super(BackendBasicTestCase, self).setUp() |
1708 | 302 | self.patch(backend, "WebClient", MockWebClient) | 193 | self.patch(backend, "WebClient", MockWebClient) |
1709 | 303 | self.patch(backend, "dbus_client", MockDBusClient()) | 194 | self.patch(backend, "dbus_client", MockDBusClient()) |
1711 | 304 | self.local_token = "Computer" + SAMPLE_CREDENTIALS["token"] | 195 | self.patch(backend, "replication_client", MockReplicationClient()) |
1712 | 196 | self.local_token = "Computer" + TOKEN["token"] | ||
1713 | 305 | self.be = backend.ControlBackend() | 197 | self.be = backend.ControlBackend() |
1714 | 306 | 198 | ||
1715 | 307 | self.memento = MementoHandler() | 199 | self.memento = MementoHandler() |
1716 | 308 | backend.logger.addHandler(self.memento) | 200 | backend.logger.addHandler(self.memento) |
1717 | 309 | 201 | ||
1719 | 310 | MockDBusClient.creds = SAMPLE_CREDENTIALS | 202 | MockDBusClient.creds = TOKEN |
1720 | 311 | 203 | ||
1721 | 312 | def test_backend_creation(self): | 204 | def test_backend_creation(self): |
1722 | 313 | """The backend instance is successfully created.""" | 205 | """The backend instance is successfully created.""" |
1723 | @@ -317,7 +209,7 @@ | |||
1724 | 317 | def test_get_token(self): | 209 | def test_get_token(self): |
1725 | 318 | """The get_token method returns the right token.""" | 210 | """The get_token method returns the right token.""" |
1726 | 319 | token = yield self.be.get_token() | 211 | token = yield self.be.get_token() |
1728 | 320 | self.assertEqual(token, SAMPLE_CREDENTIALS["token"]) | 212 | self.assertEqual(token, TOKEN["token"]) |
1729 | 321 | 213 | ||
1730 | 322 | @inlineCallbacks | 214 | @inlineCallbacks |
1731 | 323 | def test_device_is_local(self): | 215 | def test_device_is_local(self): |
1732 | @@ -388,12 +280,12 @@ | |||
1733 | 388 | result = yield self.be.remove_device(device_id) | 280 | result = yield self.be.remove_device(device_id) |
1734 | 389 | self.assertEqual(result, device_id) | 281 | self.assertEqual(result, device_id) |
1735 | 390 | # credentials were not cleared | 282 | # credentials were not cleared |
1737 | 391 | self.assertEqual(MockDBusClient.creds, SAMPLE_CREDENTIALS) | 283 | self.assertEqual(MockDBusClient.creds, TOKEN) |
1738 | 392 | 284 | ||
1739 | 393 | @inlineCallbacks | 285 | @inlineCallbacks |
1740 | 394 | def test_remove_device_clear_credentials_if_local_device(self): | 286 | def test_remove_device_clear_credentials_if_local_device(self): |
1741 | 395 | """The remove_device method clears the credentials if is local.""" | 287 | """The remove_device method clears the credentials if is local.""" |
1743 | 396 | apiurl = DEVICE_REMOVE_API % ('computer', SAMPLE_CREDENTIALS['token']) | 288 | apiurl = DEVICE_REMOVE_API % ('computer', TOKEN['token']) |
1744 | 397 | # pylint: disable=E1101 | 289 | # pylint: disable=E1101 |
1745 | 398 | self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON | 290 | self.be.wc.results[apiurl] = SAMPLE_DEVICES_JSON |
1746 | 399 | yield self.be.remove_device(self.local_token) | 291 | yield self.be.remove_device(self.local_token) |
1747 | @@ -487,10 +379,10 @@ | |||
1748 | 487 | """The volume settings can be changed.""" | 379 | """The volume settings can be changed.""" |
1749 | 488 | fid = '0123-4567' | 380 | fid = '0123-4567' |
1750 | 489 | 381 | ||
1752 | 490 | yield self.be.change_volume_settings(fid, {'subscribed': True}) | 382 | yield self.be.change_volume_settings(fid, {'subscribed': 'True'}) |
1753 | 491 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) | 383 | self.assertEqual(MockDBusClient.subscribed_folders, [fid]) |
1754 | 492 | 384 | ||
1756 | 493 | yield self.be.change_volume_settings(fid, {'subscribed': False}) | 385 | yield self.be.change_volume_settings(fid, {'subscribed': ''}) |
1757 | 494 | self.assertEqual(MockDBusClient.subscribed_folders, []) | 386 | self.assertEqual(MockDBusClient.subscribed_folders, []) |
1758 | 495 | 387 | ||
1759 | 496 | @inlineCallbacks | 388 | @inlineCallbacks |
1760 | @@ -671,3 +563,64 @@ | |||
1761 | 671 | 563 | ||
1762 | 672 | self.be.disable_files() | 564 | self.be.disable_files() |
1763 | 673 | self.assertFalse(MockDBusClient.file_sync) | 565 | self.assertFalse(MockDBusClient.file_sync) |
1764 | 566 | |||
1765 | 567 | |||
1766 | 568 | class BackendReplicationsTestCase(BackendBasicTestCase): | ||
1767 | 569 | """Replications tests for the backend.""" | ||
1768 | 570 | |||
1769 | 571 | @inlineCallbacks | ||
1770 | 572 | def test_replications_info(self): | ||
1771 | 573 | """The replications_info method exercises its callback.""" | ||
1772 | 574 | result = yield self.be.replications_info() | ||
1773 | 575 | |||
1774 | 576 | # replications_info will use exclusions information | ||
1775 | 577 | expected = [] | ||
1776 | 578 | for name in MockReplicationClient.replications: | ||
1777 | 579 | enabled = bool_str(name not in MockReplicationClient.exclusions) | ||
1778 | 580 | dependency = '' | ||
1779 | 581 | if name == MockReplicationClient.BOOKMARKS: | ||
1780 | 582 | dependency = backend.BOOKMARKS_PKG | ||
1781 | 583 | elif name == MockReplicationClient.CONTACTS: | ||
1782 | 584 | dependency = backend.CONTACTS_PKG | ||
1783 | 585 | |||
1784 | 586 | item = {'replication_id': name, 'name': name, | ||
1785 | 587 | 'enabled': enabled, 'dependency': dependency} | ||
1786 | 588 | expected.append(item) | ||
1787 | 589 | self.assertEqual(sorted(expected), sorted(result)) | ||
1788 | 590 | |||
1789 | 591 | @inlineCallbacks | ||
1790 | 592 | def test_change_replication_settings(self): | ||
1791 | 593 | """The replication settings can be changed.""" | ||
1792 | 594 | rid = '0123-4567' | ||
1793 | 595 | MockReplicationClient.replications.add(rid) | ||
1794 | 596 | self.addCleanup(lambda: MockReplicationClient.replications.remove(rid)) | ||
1795 | 597 | |||
1796 | 598 | yield self.be.change_replication_settings(rid, {'enabled': ''}) | ||
1797 | 599 | self.assertIn(rid, MockReplicationClient.exclusions) | ||
1798 | 600 | |||
1799 | 601 | yield self.be.change_replication_settings(rid, {'enabled': 'True'}) | ||
1800 | 602 | self.assertNotIn(rid, MockReplicationClient.exclusions) | ||
1801 | 603 | |||
1802 | 604 | @inlineCallbacks | ||
1803 | 605 | def test_change_replication_settings_not_in_replications(self): | ||
1804 | 606 | """The settings can not be changed for an item not in replications.""" | ||
1805 | 607 | rid = '0123-4567' | ||
1806 | 608 | assert rid not in MockReplicationClient.replications | ||
1807 | 609 | |||
1808 | 610 | d = self.be.change_replication_settings(rid, {'enabled': 'True'}) | ||
1809 | 611 | yield self.assertFailure(d, replication_client.ReplicationError) | ||
1810 | 612 | |||
1811 | 613 | d = self.be.change_replication_settings(rid, {'enabled': ''}) | ||
1812 | 614 | yield self.assertFailure(d, replication_client.ReplicationError) | ||
1813 | 615 | |||
1814 | 616 | @inlineCallbacks | ||
1815 | 617 | def test_change_replication_settings_no_setting(self): | ||
1816 | 618 | """The change replication settings does not fail on empty settings.""" | ||
1817 | 619 | rid = '0123-4567' | ||
1818 | 620 | MockReplicationClient.replications.add(rid) | ||
1819 | 621 | self.addCleanup(lambda: MockReplicationClient.replications.remove(rid)) | ||
1820 | 622 | |||
1821 | 623 | prior = MockReplicationClient.exclusions.copy() | ||
1822 | 624 | yield self.be.change_replication_settings(rid, {}) | ||
1823 | 625 | |||
1824 | 626 | self.assertEqual(MockReplicationClient.exclusions, prior) | ||
1825 | 674 | 627 | ||
1826 | === added file 'ubuntuone/controlpanel/tests/test_replication_client.py' | |||
1827 | --- ubuntuone/controlpanel/tests/test_replication_client.py 1970-01-01 00:00:00 +0000 | |||
1828 | +++ ubuntuone/controlpanel/tests/test_replication_client.py 2011-01-06 20:36:09 +0000 | |||
1829 | @@ -0,0 +1,160 @@ | |||
1830 | 1 | # -*- coding: utf-8 -*- | ||
1831 | 2 | |||
1832 | 3 | # Authors: Natalia B. Bidart <natalia.bidart@canonical.com> | ||
1833 | 4 | # | ||
1834 | 5 | # Copyright 2010 Canonical Ltd. | ||
1835 | 6 | # | ||
1836 | 7 | # This program is free software: you can redistribute it and/or modify it | ||
1837 | 8 | # under the terms of the GNU General Public License version 3, as published | ||
1838 | 9 | # by the Free Software Foundation. | ||
1839 | 10 | # | ||
1840 | 11 | # This program is distributed in the hope that it will be useful, but | ||
1841 | 12 | # WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1842 | 13 | # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
1843 | 14 | # PURPOSE. See the GNU General Public License for more details. | ||
1844 | 15 | # | ||
1845 | 16 | # You should have received a copy of the GNU General Public License along | ||
1846 | 17 | # with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1847 | 18 | |||
1848 | 19 | """Tests for the DBus service when accessing desktopcouch replications.""" | ||
1849 | 20 | |||
1850 | 21 | from twisted.internet.defer import inlineCallbacks | ||
1851 | 22 | |||
1852 | 23 | from ubuntuone.controlpanel import replication_client | ||
1853 | 24 | from ubuntuone.controlpanel.tests import TestCase | ||
1854 | 25 | |||
1855 | 26 | EXCLUSIONS = set() | ||
1856 | 27 | |||
1857 | 28 | |||
1858 | 29 | class FakedReplication(object): | ||
1859 | 30 | """Faked a DC replication exclusion.""" | ||
1860 | 31 | |||
1861 | 32 | def __init__(self): | ||
1862 | 33 | self.all_exclusions = lambda: EXCLUSIONS | ||
1863 | 34 | self.replicate = EXCLUSIONS.remove | ||
1864 | 35 | self.exclude = EXCLUSIONS.add | ||
1865 | 36 | |||
1866 | 37 | |||
1867 | 38 | class FakedReplicationModule(object): | ||
1868 | 39 | """Faked a DC replication module.""" | ||
1869 | 40 | |||
1870 | 41 | ReplicationExclusion = FakedReplication | ||
1871 | 42 | |||
1872 | 43 | |||
1873 | 44 | class ReplicationsTestCase(TestCase): | ||
1874 | 45 | """Test for the replications client methods.""" | ||
1875 | 46 | |||
1876 | 47 | def setUp(self): | ||
1877 | 48 | super(ReplicationsTestCase, self).setUp() | ||
1878 | 49 | |||
1879 | 50 | orig_get_proxy = replication_client.get_replication_proxy | ||
1880 | 51 | |||
1881 | 52 | def get_proxy(): | ||
1882 | 53 | """Fake the proxy getter.""" | ||
1883 | 54 | return orig_get_proxy(replication_module=FakedReplicationModule()) | ||
1884 | 55 | |||
1885 | 56 | self.patch(replication_client, 'get_replication_proxy', get_proxy) | ||
1886 | 57 | |||
1887 | 58 | def tearDown(self): | ||
1888 | 59 | EXCLUSIONS.clear() | ||
1889 | 60 | super(ReplicationsTestCase, self).tearDown() | ||
1890 | 61 | |||
1891 | 62 | @inlineCallbacks | ||
1892 | 63 | def test_no_pairing_record(self): | ||
1893 | 64 | """Handle ValueError from replication layer.""" | ||
1894 | 65 | |||
1895 | 66 | def no_pairing_record(*args, **kwargs): | ||
1896 | 67 | """Fail with ValueError.""" | ||
1897 | 68 | raise ValueError('No pairing record.') | ||
1898 | 69 | |||
1899 | 70 | self.patch(FakedReplicationModule, 'ReplicationExclusion', | ||
1900 | 71 | no_pairing_record) | ||
1901 | 72 | |||
1902 | 73 | yield self.assertFailure(replication_client.get_replications(), | ||
1903 | 74 | replication_client.NoPairingRecord) | ||
1904 | 75 | |||
1905 | 76 | @inlineCallbacks | ||
1906 | 77 | def test_get_replications(self): | ||
1907 | 78 | """Replications are correctly retrieved.""" | ||
1908 | 79 | result = yield replication_client.get_replications() | ||
1909 | 80 | self.assertEqual(result, replication_client.REPLICATIONS) | ||
1910 | 81 | |||
1911 | 82 | @inlineCallbacks | ||
1912 | 83 | def test_get_exclusions(self): | ||
1913 | 84 | """Exclusions are correctly retrieved.""" | ||
1914 | 85 | replications = yield replication_client.get_replications() | ||
1915 | 86 | for rep in replications: | ||
1916 | 87 | yield replication_client.exclude(rep) | ||
1917 | 88 | |||
1918 | 89 | result = yield replication_client.get_exclusions() | ||
1919 | 90 | self.assertEqual(result, replications) | ||
1920 | 91 | |||
1921 | 92 | @inlineCallbacks | ||
1922 | 93 | def test_replicate(self): | ||
1923 | 94 | """Replicate a service is correct.""" | ||
1924 | 95 | replications = yield replication_client.get_replications() | ||
1925 | 96 | rid = list(replications)[0] | ||
1926 | 97 | yield replication_client.exclude(rid) | ||
1927 | 98 | |||
1928 | 99 | yield replication_client.replicate(rid) | ||
1929 | 100 | exclusions = yield replication_client.get_exclusions() | ||
1930 | 101 | self.assertNotIn(rid, exclusions) | ||
1931 | 102 | |||
1932 | 103 | @inlineCallbacks | ||
1933 | 104 | def test_replicate_name_not_in_replications(self): | ||
1934 | 105 | """Replicate a service fails if not in replications.""" | ||
1935 | 106 | replications = yield replication_client.get_replications() | ||
1936 | 107 | rid = 'not in replications' | ||
1937 | 108 | assert rid not in replications | ||
1938 | 109 | |||
1939 | 110 | yield self.assertFailure(replication_client.replicate(rid), | ||
1940 | 111 | replication_client.InvalidIdError) | ||
1941 | 112 | |||
1942 | 113 | @inlineCallbacks | ||
1943 | 114 | def test_replicate_name_not_in_exclusions(self): | ||
1944 | 115 | """Replicate a service fails if not in exclusions.""" | ||
1945 | 116 | replications = yield replication_client.get_replications() | ||
1946 | 117 | rid = list(replications)[0] | ||
1947 | 118 | assert rid in replications | ||
1948 | 119 | |||
1949 | 120 | exclusions = yield replication_client.get_exclusions() | ||
1950 | 121 | assert rid not in exclusions | ||
1951 | 122 | |||
1952 | 123 | yield self.assertFailure(replication_client.replicate(rid), | ||
1953 | 124 | replication_client.NotExcludedError) | ||
1954 | 125 | |||
1955 | 126 | @inlineCallbacks | ||
1956 | 127 | def test_exclude(self): | ||
1957 | 128 | """Excluding a service is correct.""" | ||
1958 | 129 | replications = yield replication_client.get_replications() | ||
1959 | 130 | rid = list(replications)[0] | ||
1960 | 131 | yield replication_client.exclude(rid) | ||
1961 | 132 | yield replication_client.replicate(rid) | ||
1962 | 133 | |||
1963 | 134 | yield replication_client.exclude(rid) | ||
1964 | 135 | exclusions = yield replication_client.get_exclusions() | ||
1965 | 136 | self.assertIn(rid, exclusions) | ||
1966 | 137 | |||
1967 | 138 | @inlineCallbacks | ||
1968 | 139 | def test_exclude_name_not_in_replications(self): | ||
1969 | 140 | """Excluding a service fails if not in replications.""" | ||
1970 | 141 | replications = yield replication_client.get_replications() | ||
1971 | 142 | rid = 'not in replications' | ||
1972 | 143 | assert rid not in replications | ||
1973 | 144 | |||
1974 | 145 | yield self.assertFailure(replication_client.exclude(rid), | ||
1975 | 146 | replication_client.InvalidIdError) | ||
1976 | 147 | |||
1977 | 148 | @inlineCallbacks | ||
1978 | 149 | def test_exclude_name_in_exclusions(self): | ||
1979 | 150 | """Excluding a service fails if already on exclusions.""" | ||
1980 | 151 | replications = yield replication_client.get_replications() | ||
1981 | 152 | rid = list(replications)[0] | ||
1982 | 153 | assert rid in replications | ||
1983 | 154 | |||
1984 | 155 | yield replication_client.exclude(rid) | ||
1985 | 156 | exclusions = yield replication_client.get_exclusions() | ||
1986 | 157 | assert rid in exclusions | ||
1987 | 158 | |||
1988 | 159 | yield self.assertFailure(replication_client.exclude(rid), | ||
1989 | 160 | replication_client.AlreadyExcludedError) |