Merge lp:~tealeg/landscape-client/ui-storage into lp:~landscape/landscape-client/trunk
- ui-storage
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Alberto Donato |
Approved revision: | 482 |
Merged at revision: | 467 |
Proposed branch: | lp:~tealeg/landscape-client/ui-storage |
Merge into: | lp:~landscape/landscape-client/trunk |
Diff against target: |
1891 lines (+1196/-327) 12 files modified
glib-2.0/schemas/com.canonical.landscape-client-settings.gschema.xml (+37/-0) landscape/ui/controller/configuration.py (+11/-35) landscape/ui/controller/tests/test_configuration.py (+5/-5) landscape/ui/lib/polkit.py (+3/-2) landscape/ui/model/configuration/mechanism.py (+2/-1) landscape/ui/model/configuration/proxy.py (+5/-2) landscape/ui/model/configuration/state.py (+329/-144) landscape/ui/model/configuration/tests/test_state.py (+458/-137) landscape/ui/model/configuration/tests/test_uisettings.py (+189/-0) landscape/ui/model/configuration/uisettings.py (+57/-0) landscape/ui/tests/helpers.py (+95/-0) setupui.py (+5/-1) |
To merge this branch: | bzr merge lp:~tealeg/landscape-client/ui-storage |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Donato (community) | Approve | ||
Free Ekanayaka (community) | Approve | ||
Review via email: mp+94393@code.launchpad.net |
Commit message
Description of the change
The second part of the fix for bug #931937,
This branch does the following:
1. Removes the TestedGoodState and TestedBadState to reflect the decision not to tackne testing of configurations in this phase.
2. Performs 3 stages of data setup:
i. use code level defaults in the VirginState
ii. overwrite user visible values with current values in GSettings (VirginState -> Initialised)
iii. overwrite either hosted or local values from the configuration file values (VirginState -> Initialised)
3. Persist data in two places:
i. write all user visible data back to GSettings.
ii. write either hosted or local values to the configuration file.
Alberto Donato (ack) wrote : | # |
Looks great! +1
Just minor stylistic notes:
#1:
+ if self._computer_
you could use "if not self._computer_
#2:
+ self.assertEqua
please use assertTrue here.
#3:
+ self.config_string = "[client]\n" \
please use parentheses rather than breaking with \
+ assert(
+ "com.canonical.
same here
Thanks!
- 483. By Geoff Teale
-
removed unused GSettings event handlers
- 484. By Geoff Teale
-
Added docstring (from Free's review)
- 485. By Geoff Teale
-
Docstring and comments on complex get/set machinary (from Free's review)
- 486. By Geoff Teale
-
Simplify empty value comparisons (from Ack's review).
- 487. By Geoff Teale
-
Replace assertEqual(True, ... with assertTrue(... (from Ack's review).
- 488. By Geoff Teale
-
Use brackets instead of line continuation (from Ack's review).
Preview Diff
1 | === added directory 'glib-2.0' |
2 | === added directory 'glib-2.0/schemas' |
3 | === added file 'glib-2.0/schemas/com.canonical.landscape-client-settings.gschema.xml' |
4 | --- glib-2.0/schemas/com.canonical.landscape-client-settings.gschema.xml 1970-01-01 00:00:00 +0000 |
5 | +++ glib-2.0/schemas/com.canonical.landscape-client-settings.gschema.xml 2012-02-29 16:50:20 +0000 |
6 | @@ -0,0 +1,37 @@ |
7 | +<?xml version="1.0" encoding="utf-8"?> |
8 | +<schemalist> |
9 | + <schema id="com.canonical.landscape-client-settings" path="/com/canonical/landscape-client-settings/"> |
10 | + <key type="b" name="is-hosted"> |
11 | + <default>true</default> |
12 | + <summary>Whether the client settings UI currently set to a hosted client configuration.</summary> |
13 | + </key> |
14 | + <key type="s" name="computer-title"> |
15 | + <default></default> |
16 | + <summary>The title to register the machine with.</summary> |
17 | + </key> |
18 | + <key type="s" name="hosted-landscape-host"> |
19 | + <default>canonical.landscape.com</default> |
20 | + <summary>The hostname of the Canonical hosted landscape system.</summary> |
21 | + </key> |
22 | + <key type="s" name="hosted-account-name"> |
23 | + <default></default> |
24 | + <summary>An account name for use with the Canonical hosted landscape system.</summary> |
25 | + </key> |
26 | + <key type="s" name="hosted-password"> |
27 | + <default></default> |
28 | + <summary>A password for use with the Canonical hosted landscape system</summary> |
29 | + </key> |
30 | + <key type="s" name="local-landscape-host"> |
31 | + <default></default> |
32 | + <summary>The hostname of the local landscape system.</summary> |
33 | + </key> |
34 | + <key type="s" name="local-account-name"> |
35 | + <default></default> |
36 | + <summary>An account name for use with the local landscape system.</summary> |
37 | + </key> |
38 | + <key type="s" name="local-password"> |
39 | + <default></default> |
40 | + <summary>A password for use with the local landscape system</summary> |
41 | + </key> |
42 | + </schema> |
43 | +</schemalist> |
44 | |
45 | === modified file 'landscape/ui/controller/configuration.py' |
46 | --- landscape/ui/controller/configuration.py 2012-02-03 18:10:57 +0000 |
47 | +++ landscape/ui/controller/configuration.py 2012-02-29 16:50:20 +0000 |
48 | @@ -1,6 +1,9 @@ |
49 | import socket |
50 | import threading |
51 | from landscape.ui.model.registration.proxy import RegistrationProxy |
52 | +from landscape.ui.model.configuration.state import ( |
53 | + derive_url_from_host_name, derive_ping_url_from_host_name, |
54 | + derive_server_host_name_from_url) |
55 | |
56 | |
57 | class ConfigControllerLockError(Exception): |
58 | @@ -65,7 +68,7 @@ |
59 | """ |
60 | Default machine name to FQDN. |
61 | """ |
62 | - if self._computer_title is None: |
63 | + if self._computer_title in ("", None): |
64 | self._computer_title = self.getfqdn() |
65 | |
66 | def default_dedicated(self): |
67 | @@ -78,9 +81,8 @@ |
68 | self._server_host_name = self._initial_server_host_name |
69 | else: |
70 | self._server_host_name = self.DEFAULT_SERVER_HOST_NAME |
71 | - self._url = self._derive_url_from_host_name( |
72 | - self._server_host_name) |
73 | - self._ping_url = self._derive_ping_url_from_host_name( |
74 | + self._url = derive_url_from_host_name(self._server_host_name) |
75 | + self._ping_url = derive_ping_url_from_host_name( |
76 | self._server_host_name) |
77 | self.modify() |
78 | |
79 | @@ -91,10 +93,8 @@ |
80 | """ |
81 | if self._server_host_name != self.HOSTED_HOST_NAME: |
82 | self._server_host_name = self.HOSTED_HOST_NAME |
83 | - self._url = self._derive_url_from_host_name( |
84 | - self._server_host_name) |
85 | - self._ping_url = self._derive_ping_url_from_host_name( |
86 | - self._server_host_name) |
87 | + self._url = derive_url_from_host_name(self._server_host_name) |
88 | + self._ping_url = derive_ping_url_from_host_name(self._server_host_name) |
89 | self._account_name = self._initial_account_name |
90 | self.modify() |
91 | |
92 | @@ -117,7 +117,7 @@ |
93 | self._ping_url = self._configuration.ping_url |
94 | if self._url: |
95 | self._server_host_name = \ |
96 | - self._derive_server_host_name_from_url(self._url) |
97 | + derive_server_host_name_from_url(self._url) |
98 | else: |
99 | self._server_host_name = self.HOSTED_HOST_NAME |
100 | self._initial_server_host_name = self._server_host_name |
101 | @@ -143,29 +143,6 @@ |
102 | self._lock.release() |
103 | return lock_state |
104 | |
105 | - def _derive_server_host_name_from_url(self, url): |
106 | - "Extract the hostname part from a URL." |
107 | - try: |
108 | - without_protocol = url[url.index("://") + 3:] |
109 | - except ValueError: |
110 | - without_protocol = url |
111 | - try: |
112 | - return without_protocol[:without_protocol.index("/")] |
113 | - except ValueError: |
114 | - return without_protocol |
115 | - |
116 | - def _derive_url_from_host_name(self, host_name): |
117 | - "Extrapolate a url from a host name." |
118 | - #Reuse this code to make sure it's a proper host name |
119 | - host_name = self._derive_server_host_name_from_url(host_name) |
120 | - return "https://" + host_name + "/message-system" |
121 | - |
122 | - def _derive_ping_url_from_host_name(self, host_name): |
123 | - "Extrapolate a ping_url from a host name." |
124 | - #Reuse this code to make sure it's a proper host name |
125 | - host_name = self._derive_server_host_name_from_url(host_name) |
126 | - return "http://" + host_name + "/ping" |
127 | - |
128 | def _get_server_host_name(self): |
129 | return self._server_host_name |
130 | |
131 | @@ -178,9 +155,8 @@ |
132 | if value != self.HOSTED_HOST_NAME: |
133 | self._initial_server_host_name = value |
134 | self._server_host_name = value |
135 | - self._url = self._derive_url_from_host_name( |
136 | - self._server_host_name) |
137 | - self._ping_url = self._derive_ping_url_from_host_name( |
138 | + self._url = derive_url_from_host_name(self._server_host_name) |
139 | + self._ping_url = derive_ping_url_from_host_name( |
140 | self._server_host_name) |
141 | self.modify() |
142 | self._lock.release() |
143 | |
144 | === modified file 'landscape/ui/controller/tests/test_configuration.py' |
145 | --- landscape/ui/controller/tests/test_configuration.py 2012-02-06 22:29:12 +0000 |
146 | +++ landscape/ui/controller/tests/test_configuration.py 2012-02-29 16:50:20 +0000 |
147 | @@ -224,19 +224,19 @@ |
148 | dedicated. |
149 | """ |
150 | self.controller.load() |
151 | - self.assertEqual(None, self.controller.account_name) |
152 | - self.assertEqual(None, self.controller.registration_password) |
153 | + self.assertEqual("", self.controller.account_name) |
154 | + self.assertEqual("", self.controller.registration_password) |
155 | self.assertEqual("landscape.canonical.com", |
156 | self.controller.server_host_name) |
157 | self.controller.account_name = "Bungle" |
158 | self.controller.default_dedicated() |
159 | self.assertEqual("standalone", self.controller.account_name) |
160 | - self.assertEqual(None, self.controller.registration_password) |
161 | + self.assertEqual("", self.controller.registration_password) |
162 | self.assertEqual("landscape.localdomain", |
163 | self.controller.server_host_name) |
164 | self.controller.default_hosted() |
165 | - self.assertEqual(None, self.controller.account_name) |
166 | - self.assertEqual(None, self.controller.registration_password) |
167 | + self.assertEqual("", self.controller.account_name) |
168 | + self.assertEqual("", self.controller.registration_password) |
169 | self.assertEqual("landscape.canonical.com", |
170 | self.controller.server_host_name) |
171 | self.controller.default_dedicated() |
172 | |
173 | === modified file 'landscape/ui/lib/polkit.py' |
174 | --- landscape/ui/lib/polkit.py 2012-01-23 09:52:49 +0000 |
175 | +++ landscape/ui/lib/polkit.py 2012-02-29 16:50:20 +0000 |
176 | @@ -1,7 +1,8 @@ |
177 | import dbus |
178 | import dbus.service |
179 | import dbus.glib |
180 | -import gobject |
181 | + |
182 | +from gi.repository import GObject |
183 | |
184 | |
185 | class PolicyKitMechanism(dbus.service.Object): |
186 | @@ -111,5 +112,5 @@ |
187 | """ |
188 | Invoke a L{gobject.MainLoop} to process incoming DBus events. |
189 | """ |
190 | - mainloop = gobject.MainLoop() |
191 | + mainloop = GObject.MainLoop() |
192 | mainloop.run() |
193 | |
194 | === modified file 'landscape/ui/model/configuration/mechanism.py' |
195 | --- landscape/ui/model/configuration/mechanism.py 2012-01-24 10:12:49 +0000 |
196 | +++ landscape/ui/model/configuration/mechanism.py 2012-02-29 16:50:20 +0000 |
197 | @@ -81,8 +81,9 @@ |
198 | except AttributeError: |
199 | return "" |
200 | if value is None: |
201 | - return None |
202 | + return "" |
203 | return str(value) |
204 | + return "" |
205 | |
206 | @dbus.service.method(INTERFACE_NAME, |
207 | in_signature="ss", |
208 | |
209 | === modified file 'landscape/ui/model/configuration/proxy.py' |
210 | --- landscape/ui/model/configuration/proxy.py 2012-01-24 10:10:31 +0000 |
211 | +++ landscape/ui/model/configuration/proxy.py 2012-02-29 16:50:20 +0000 |
212 | @@ -22,7 +22,8 @@ |
213 | The canonical case for this is L{landscape-client-settings-ui}. |
214 | """ |
215 | |
216 | - def __init__(self, bus=None, interface=None): |
217 | + def __init__(self, bus=None, interface=None, loadargs=[]): |
218 | + self._loadargs = loadargs |
219 | if bus is None: |
220 | self._bus = dbus.SystemBus() |
221 | else: |
222 | @@ -34,7 +35,9 @@ |
223 | self._interface = interface |
224 | |
225 | def load(self, arglist): |
226 | - if arglist is None or len(arglist) == 0: |
227 | + if arglist is None: |
228 | + arglist = self._loadargs |
229 | + if len(arglist) == 0: |
230 | al = "" |
231 | else: |
232 | al = chr(0x1e).join(arglist) |
233 | |
234 | === modified file 'landscape/ui/model/configuration/state.py' |
235 | --- landscape/ui/model/configuration/state.py 2012-02-23 11:38:49 +0000 |
236 | +++ landscape/ui/model/configuration/state.py 2012-02-29 16:50:20 +0000 |
237 | @@ -1,3 +1,74 @@ |
238 | +import copy |
239 | +import socket |
240 | + |
241 | +from landscape.ui.model.configuration.proxy import ConfigurationProxy |
242 | + |
243 | + |
244 | +HOSTED_LANDSCAPE_HOST = "landscape.canonical.com" |
245 | +LOCAL_LANDSCAPE_HOST = "" |
246 | + |
247 | +HOSTED_ACCOUNT_NAME = "" |
248 | +LOCAL_ACCOUNT_NAME = "" |
249 | + |
250 | +HOSTED_PASSWORD = "" |
251 | +LOCAL_PASSWORD = "" |
252 | + |
253 | +HOSTED = "hosted" |
254 | +LOCAL = "local" |
255 | +IS_HOSTED = "is-hosted" |
256 | +COMPUTER_TITLE = "computer-title" |
257 | +LANDSCAPE_HOST = "landscape-host" |
258 | +ACCOUNT_NAME = "account-name" |
259 | +PASSWORD = "password" |
260 | + |
261 | + |
262 | +def get_fqdn(): |
263 | + """ |
264 | + Wrap socket.getfqdn so we can test reliably. |
265 | + """ |
266 | + return socket.getfqdn() |
267 | + |
268 | + |
269 | +DEFAULT_DATA = { |
270 | + IS_HOSTED: True, |
271 | + COMPUTER_TITLE: get_fqdn(), |
272 | + HOSTED: { |
273 | + LANDSCAPE_HOST: HOSTED_LANDSCAPE_HOST, |
274 | + ACCOUNT_NAME: HOSTED_ACCOUNT_NAME, |
275 | + PASSWORD: HOSTED_PASSWORD, |
276 | + }, |
277 | + LOCAL: { |
278 | + LANDSCAPE_HOST: LOCAL_LANDSCAPE_HOST, |
279 | + ACCOUNT_NAME: LOCAL_ACCOUNT_NAME, |
280 | + PASSWORD: LOCAL_PASSWORD, |
281 | + } |
282 | +} |
283 | + |
284 | + |
285 | +def derive_server_host_name_from_url(url): |
286 | + "Extract the hostname part from a URL." |
287 | + try: |
288 | + without_protocol = url[url.index("://") + 3:] |
289 | + except ValueError: |
290 | + without_protocol = url |
291 | + try: |
292 | + return without_protocol[:without_protocol.index("/")] |
293 | + except ValueError: |
294 | + return without_protocol |
295 | + |
296 | + |
297 | +def derive_url_from_host_name(host_name): |
298 | + "Extrapolate a url from a host name." |
299 | + #Reuse this code to make sure it's a proper host name |
300 | + host_name = derive_server_host_name_from_url(host_name) |
301 | + return "https://" + host_name + "/message-system" |
302 | + |
303 | + |
304 | +def derive_ping_url_from_host_name(host_name): |
305 | + "Extrapolate a ping_url from a host name." |
306 | + #Reuse this code to make sure it's a proper host name |
307 | + host_name = derive_server_host_name_from_url(host_name) |
308 | + return "http://" + host_name + "/ping" |
309 | |
310 | |
311 | class StateError(Exception): |
312 | @@ -9,15 +80,68 @@ |
313 | |
314 | class ConfigurationState(object): |
315 | """ |
316 | - Abstract base class for states used in the L{ConfigurationModel}. |
317 | + Base class for states used in the L{ConfigurationModel}. |
318 | """ |
319 | + def __init__(self, data, proxy, uisettings): |
320 | + self._data = copy.deepcopy(data) |
321 | + self._proxy = proxy |
322 | + self._uisettings = uisettings |
323 | + |
324 | + def get(self, *args): |
325 | + """ |
326 | + Retrieve only valid values from two level dictionary based tree. |
327 | + |
328 | + This mainly served to pick up programming errors and could easily be |
329 | + replaced with a simpler scheme. |
330 | + """ |
331 | + arglen = len(args) |
332 | + if arglen > 2 or arglen == 0: |
333 | + raise TypeError( |
334 | + "get() takes either 1 or 2 keys (%d given)" % arglen) |
335 | + if arglen == 2: # We're looking for a leaf on a branch |
336 | + sub_dict = None |
337 | + if args[0] in [HOSTED, LOCAL]: |
338 | + sub_dict = self._data.get(args[0], {}) |
339 | + sub_dict = self._data[args[0]] |
340 | + if not isinstance(sub_dict, dict): |
341 | + raise KeyError( |
342 | + "Compound key [%s][%s] is invalid. The data type " + |
343 | + "returned from the first index was %s." % |
344 | + sub_dict.__class__.__name__) |
345 | + return sub_dict.get(args[1], None) |
346 | + else: # we looking for a leaf at the root |
347 | + if args[0] in (IS_HOSTED, COMPUTER_TITLE): |
348 | + return self._data.get(args[0], None) |
349 | + else: |
350 | + raise KeyError("Key [%s] is invalid. " % args[0]) |
351 | + |
352 | + def set(self, *args): |
353 | + """ |
354 | + Set only valid values from two level dictionary based tree. |
355 | + |
356 | + This mainly served to pick up programming errors and could easily be |
357 | + replaced with a simpler scheme. |
358 | + """ |
359 | + arglen = len(args) |
360 | + if arglen < 2 or arglen > 3: |
361 | + raise TypeError("set() takes either 1 or 2 keys and exactly 1 " + |
362 | + "value (%d arguments given)" % arglen) |
363 | + if arglen == 2: # We're setting a leaf attached to the root |
364 | + self._data[args[0]] = args[1] |
365 | + else: # We're setting a leaf on a branch |
366 | + sub_dict = None |
367 | + if args[0] in [HOSTED, LOCAL]: |
368 | + sub_dict = self._data.get(args[0], {}) |
369 | + if not isinstance(sub_dict, dict): |
370 | + raise KeyError("Compound key [%s][%s] is invalid. The data " + |
371 | + "type returned from the first index was %s." |
372 | + % sub_dict.__class__.__name__) |
373 | + sub_dict[args[1]] = args[2] |
374 | + self._data[args[0]] = sub_dict |
375 | |
376 | def load_data(self): |
377 | raise NotImplementedError |
378 | |
379 | - def test(self, test_method): |
380 | - raise NotImplementedError |
381 | - |
382 | def modify(self): |
383 | raise NotImplementedError |
384 | |
385 | @@ -28,16 +152,32 @@ |
386 | raise NotImplementedError |
387 | |
388 | |
389 | -class ModifiableHelper(object): |
390 | +class Helper(object): |
391 | + """ |
392 | + Base class for all state transition helpers. |
393 | + |
394 | + It is assumed that the Helper classes are "friends" of the |
395 | + L{ConfigurationState} classes and can have some knowledge of their |
396 | + internals. They shouldn't be visible to users of the |
397 | + L{ConfigurationState}s and in general we should avoid seeing the |
398 | + L{ConfigurationState}'s _data attribute outside this module. |
399 | + """ |
400 | + |
401 | + def __init__(self, state): |
402 | + self._state = state |
403 | + |
404 | + |
405 | +class ModifiableHelper(Helper): |
406 | """ |
407 | Allow a L{ConfigurationState}s to be modified. |
408 | """ |
409 | |
410 | def modify(self): |
411 | - return ModifiedState() |
412 | - |
413 | - |
414 | -class UnloadableHelper(object): |
415 | + return ModifiedState(self._state._data, self._state._proxy, |
416 | + self._state._uisettings) |
417 | + |
418 | + |
419 | +class UnloadableHelper(Helper): |
420 | """ |
421 | Disallow loading of data into a L{ConfigurationModel}. |
422 | """ |
423 | @@ -48,7 +188,7 @@ |
424 | " cannot be transitioned via load_data()") |
425 | |
426 | |
427 | -class UnmodifiableHelper(object): |
428 | +class UnmodifiableHelper(Helper): |
429 | """ |
430 | Disallow modification of a L{ConfigurationState}. |
431 | """ |
432 | @@ -59,39 +199,17 @@ |
433 | " cannot transition via modify()") |
434 | |
435 | |
436 | -class TestableHelper(object): |
437 | - """ |
438 | - Allow testing of a L{ConfigurationModel}. |
439 | - """ |
440 | - |
441 | - def test(self, test_method): |
442 | - if test_method(): |
443 | - return TestedGoodState() |
444 | - else: |
445 | - return TestedBadState() |
446 | - |
447 | - |
448 | -class UntestableHelper(object): |
449 | - """ |
450 | - Disallow testing of a L{ConfigurationModel}. |
451 | - """ |
452 | - |
453 | - def test(self, test_method): |
454 | - raise StateError("A ConfigurationModel in " + |
455 | - self.__class__.__name__ + |
456 | - " cannot transition via test()") |
457 | - |
458 | - |
459 | -class RevertableHelper(object): |
460 | +class RevertableHelper(Helper): |
461 | """ |
462 | Allow reverting of a L{ConfigurationModel}. |
463 | """ |
464 | |
465 | def revert(self): |
466 | - return InitialisedState() |
467 | - |
468 | - |
469 | -class UnrevertableHelper(object): |
470 | + return InitialisedState(self._state._data, self._state._proxy, |
471 | + self._state._uisettings) |
472 | + |
473 | + |
474 | +class UnrevertableHelper(Helper): |
475 | """ |
476 | Disallow reverting of a L{ConfigurationModel}. |
477 | """ |
478 | @@ -102,16 +220,50 @@ |
479 | " cannot transition via revert()") |
480 | |
481 | |
482 | -class PersistableHelper(object): |
483 | +class PersistableHelper(Helper): |
484 | """ |
485 | Allow a L{ConfigurationModel} to persist. |
486 | """ |
487 | |
488 | + def _save_to_uisettings(self): |
489 | + self._state._uisettings.set_is_hosted(self._state.get(IS_HOSTED)) |
490 | + self._state._uisettings.set_computer_title( |
491 | + self._state.get(COMPUTER_TITLE)) |
492 | + self._state._uisettings.set_hosted_account_name( |
493 | + self._state.get(HOSTED, ACCOUNT_NAME)) |
494 | + self._state._uisettings.set_hosted_password( |
495 | + self._state.get(HOSTED, PASSWORD)) |
496 | + self._state._uisettings.set_local_landscape_host( |
497 | + self._state.get(LOCAL, LANDSCAPE_HOST)) |
498 | + self._state._uisettings.set_local_account_name( |
499 | + self._state.get(LOCAL, ACCOUNT_NAME)) |
500 | + self._state._uisettings.set_local_password( |
501 | + self._state.get(LOCAL, PASSWORD)) |
502 | + |
503 | + def _save_to_config(self): |
504 | + if self._state.get(IS_HOSTED): |
505 | + first_key = HOSTED |
506 | + else: |
507 | + first_key = LOCAL |
508 | + self._state._proxy.url = derive_url_from_host_name( |
509 | + self._state.get(first_key, LANDSCAPE_HOST)) |
510 | + self._state._proxy.ping_url = derive_ping_url_from_host_name( |
511 | + self._state.get(first_key, LANDSCAPE_HOST)) |
512 | + self._state._proxy.account_name = \ |
513 | + self._state.get(first_key, ACCOUNT_NAME) |
514 | + self._state._proxy.registration_password = \ |
515 | + self._state.get(first_key, PASSWORD) |
516 | + self._state._proxy.computer_title = self._state.get(COMPUTER_TITLE) |
517 | + self._state._proxy.write() |
518 | + |
519 | def persist(self): |
520 | - return InitialisedState() |
521 | - |
522 | - |
523 | -class UnpersistableHelper(object): |
524 | + self._save_to_uisettings() |
525 | + self._save_to_config() |
526 | + return InitialisedState(self._state._data, self._state._proxy, |
527 | + self._state._uisettings) |
528 | + |
529 | + |
530 | +class UnpersistableHelper(Helper): |
531 | """ |
532 | Disallow persistence of a L{ConfigurationModel}. |
533 | """ |
534 | @@ -125,70 +277,20 @@ |
535 | class ModifiedState(ConfigurationState): |
536 | """ |
537 | The state of a L{ConfigurationModel} whenever the user has modified some |
538 | - data but hasn't yet L{test}ed or L{revert}ed. |
539 | - """ |
540 | - |
541 | - _modifiable_helper = ModifiableHelper() |
542 | - _revertable_helper = RevertableHelper() |
543 | - _testable_helper = TestableHelper() |
544 | - _unpersistable_helper = UnpersistableHelper() |
545 | - |
546 | - def modify(self): |
547 | - return self._modifiable_helper.modify() |
548 | - |
549 | - def revert(self): |
550 | - return self._revertable_helper.revert() |
551 | - |
552 | - def test(self, test_method): |
553 | - return self._testable_helper.test(test_method) |
554 | - |
555 | - def persist(self): |
556 | - return self._unpersistable_helper.persist() |
557 | - |
558 | - |
559 | -class TestedState(ConfigurationState): |
560 | - """ |
561 | - A superclass for the two possible L{TestedStates} (L{TestedGoodState} and |
562 | - L{TestedBadState}). |
563 | - """ |
564 | - |
565 | - _untestable_helper = UntestableHelper() |
566 | - _unloadable_helper = UnloadableHelper() |
567 | - _modifiable_helper = ModifiableHelper() |
568 | - _revertable_helper = RevertableHelper() |
569 | - |
570 | - def test(self, test_method): |
571 | - return self._untestable_helper.test(test_method) |
572 | - |
573 | - def load_data(self): |
574 | - return self._unloadable_helper.load_data() |
575 | - |
576 | - def modify(self): |
577 | - return self._modifiable_helper.modify() |
578 | - |
579 | - def revert(self): |
580 | - return self._revertable_helper.revert() |
581 | - |
582 | - |
583 | -class TestedBadState(TestedState): |
584 | - """ |
585 | - The state of a L{ConfigurationModel} after it has been L{test}ed but that |
586 | - L{test} has failed for some reason. |
587 | - """ |
588 | - |
589 | - _unpersistable_helper = UnpersistableHelper() |
590 | - |
591 | - def persist(self): |
592 | - return self._unpersistable_helper.persist() |
593 | - |
594 | - |
595 | -class TestedGoodState(TestedState): |
596 | - """ |
597 | - The state of a L{ConfigurationModel} after it has been L{test}ed |
598 | - successfully. |
599 | - """ |
600 | - |
601 | - _persistable_helper = PersistableHelper() |
602 | + data but hasn't yet L{persist}ed or L{revert}ed. |
603 | + """ |
604 | + |
605 | + def __init__(self, data, proxy, uisettings): |
606 | + super(ModifiedState, self).__init__(data, proxy, uisettings) |
607 | + self._modifiable_helper = ModifiableHelper(self) |
608 | + self._revertable_helper = RevertableHelper(self) |
609 | + self._persistable_helper = PersistableHelper(self) |
610 | + |
611 | + def modify(self): |
612 | + return self._modifiable_helper.modify() |
613 | + |
614 | + def revert(self): |
615 | + return self._revertable_helper.revert() |
616 | |
617 | def persist(self): |
618 | return self._persistable_helper.persist() |
619 | @@ -202,10 +304,45 @@ |
620 | finally defaults should be applied where necessary. |
621 | """ |
622 | |
623 | - _modifiable_helper = ModifiableHelper() |
624 | - _unrevertable_helper = UnrevertableHelper() |
625 | - _testable_helper = TestableHelper() |
626 | - _unpersistable_helper = UnpersistableHelper() |
627 | + def __init__(self, data, proxy, uisettings): |
628 | + super(InitialisedState, self).__init__(data, proxy, uisettings) |
629 | + self._modifiable_helper = ModifiableHelper(self) |
630 | + self._unrevertable_helper = UnrevertableHelper(self) |
631 | + self._unpersistable_helper = UnpersistableHelper(self) |
632 | + self._load_uisettings_data() |
633 | + self._load_live_data() |
634 | + |
635 | + def _load_uisettings_data(self): |
636 | + self.set(IS_HOSTED, self._uisettings.get_is_hosted()) |
637 | + computer_title = self._uisettings.get_computer_title() |
638 | + if computer_title: |
639 | + self.set(COMPUTER_TITLE, computer_title) |
640 | + self.set(HOSTED, LANDSCAPE_HOST, |
641 | + self._uisettings.get_hosted_landscape_host()) |
642 | + self.set(HOSTED, ACCOUNT_NAME, |
643 | + self._uisettings.get_hosted_account_name()) |
644 | + self.set(HOSTED, PASSWORD, self._uisettings.get_hosted_password()) |
645 | + self.set(LOCAL, LANDSCAPE_HOST, |
646 | + self._uisettings.get_local_landscape_host()) |
647 | + self.set(LOCAL, ACCOUNT_NAME, |
648 | + self._uisettings.get_local_account_name()) |
649 | + self.set(LOCAL, PASSWORD, self._uisettings.get_local_password()) |
650 | + |
651 | + def _load_live_data(self): |
652 | + self._proxy.load(None) |
653 | + computer_title = self._proxy.computer_title |
654 | + if computer_title: |
655 | + self.set(COMPUTER_TITLE, computer_title) |
656 | + url = self._proxy.url |
657 | + if url.find(HOSTED_LANDSCAPE_HOST) > -1: |
658 | + self.set(IS_HOSTED, True) |
659 | + self.set(HOSTED, ACCOUNT_NAME, self._proxy.account_name) |
660 | + self.set(HOSTED, PASSWORD, self._proxy.registration_password) |
661 | + else: |
662 | + self.set(IS_HOSTED, False) |
663 | + self.set(LOCAL, LANDSCAPE_HOST, |
664 | + derive_server_host_name_from_url(url)) |
665 | + self.set(LOCAL, ACCOUNT_NAME, self._proxy.account_name) |
666 | |
667 | def load_data(self): |
668 | return self |
669 | @@ -216,9 +353,6 @@ |
670 | def revert(self): |
671 | return self._unrevertable_helper.revert() |
672 | |
673 | - def test(self, test_method): |
674 | - return self._testable_helper.test(test_method) |
675 | - |
676 | def persist(self): |
677 | return self._unpersistable_helper.persist() |
678 | |
679 | @@ -229,16 +363,14 @@ |
680 | upon it. |
681 | """ |
682 | |
683 | - _untestable_helper = UntestableHelper() |
684 | - _unmodifiable_helper = UnmodifiableHelper() |
685 | - _unrevertable_helper = UnrevertableHelper() |
686 | - _unpersistable_helper = UnpersistableHelper() |
687 | + def __init__(self, proxy, uisettings): |
688 | + super(VirginState, self).__init__(DEFAULT_DATA, proxy, uisettings) |
689 | + self._unmodifiable_helper = UnmodifiableHelper(self) |
690 | + self._unrevertable_helper = UnrevertableHelper(self) |
691 | + self._unpersistable_helper = UnpersistableHelper(self) |
692 | |
693 | def load_data(self): |
694 | - return InitialisedState() |
695 | - |
696 | - def test(self, test_method): |
697 | - return self._untestable_helper.test(test_method) |
698 | + return InitialisedState(self._data, self._proxy, self._uisettings) |
699 | |
700 | def modify(self): |
701 | return self._unmodifiable_helper.modify() |
702 | @@ -266,29 +398,15 @@ |
703 | |
704 | VirginState --(load_data)--> InitialisedState |
705 | InitialisedState --(modify)-----> ModifiedState |
706 | - InitialisedState --(test)-------> TestedGoodState |
707 | - InitialisedState --(test)-------> TestedBadState |
708 | ModifiedState --(revert)-----> InitialisedState |
709 | ModifiedState --(modify)-----> ModifiedState |
710 | - ModifiedState --(test)-------> TestedGoodState |
711 | - ModifiedState --(test)-------> TestedBadState |
712 | - TestedGoodState --(revert)-----> InitialisedState |
713 | - TestedGoodState --(persist)----> InitialisedState |
714 | - TestedGoodState --(modify)-----> ModifiedState |
715 | - TestedBadState --(revert)-----> InitialisedState |
716 | - TestedBadState --(modify)-----> ModifiedState |
717 | + ModifiedState --(persist)----> InitialisedState |
718 | """ |
719 | |
720 | - def __init__(self, test_method=None): |
721 | - self._current_state = VirginState() |
722 | - if test_method: |
723 | - self._test_method = test_method |
724 | - else: |
725 | - self._test_method = self._test |
726 | - |
727 | - def _test(self): |
728 | - # TODO, dump this and use something real |
729 | - return True |
730 | + def __init__(self, proxy=None, proxy_loadargs=[], uisettings=None): |
731 | + if not proxy: |
732 | + proxy = ConfigurationProxy(loadargs=proxy_loadargs) |
733 | + self._current_state = VirginState(proxy, uisettings) |
734 | |
735 | def get_state(self): |
736 | """ |
737 | @@ -299,9 +417,6 @@ |
738 | def load_data(self): |
739 | self._current_state = self._current_state.load_data() |
740 | |
741 | - def test(self): |
742 | - self._current_state = self._current_state.test(self._test_method) |
743 | - |
744 | def modify(self): |
745 | self._current_state = self._current_state.modify() |
746 | |
747 | @@ -310,3 +425,73 @@ |
748 | |
749 | def persist(self): |
750 | self._current_state = self._current_state.persist() |
751 | + |
752 | + def _get_is_hosted(self): |
753 | + return self._current_state.get(IS_HOSTED) |
754 | + |
755 | + def _set_is_hosted(self, value): |
756 | + self._current_state.set(IS_HOSTED, value) |
757 | + |
758 | + is_hosted = property(_get_is_hosted, _set_is_hosted) |
759 | + |
760 | + def _get_computer_title(self): |
761 | + return self._current_state.get(COMPUTER_TITLE) |
762 | + |
763 | + def _set_computer_title(self, value): |
764 | + self._current_state.set(COMPUTER_TITLE, value) |
765 | + |
766 | + computer_title = property(_get_computer_title, _set_computer_title) |
767 | + |
768 | + def _get_hosted_landscape_host(self): |
769 | + return self._current_state.get(HOSTED, LANDSCAPE_HOST) |
770 | + |
771 | + def _set_hosted_landscape_host(self, value): |
772 | + self._current_state.set(HOSTED, LANDSCAPE_HOST, value) |
773 | + |
774 | + hosted_landscape_host = property(_get_hosted_landscape_host, |
775 | + _set_hosted_landscape_host) |
776 | + |
777 | + def _get_local_landscape_host(self): |
778 | + return self._current_state.get(LOCAL, LANDSCAPE_HOST) |
779 | + |
780 | + def _set_local_landscape_host(self, value): |
781 | + self._current_state.set(LOCAL, LANDSCAPE_HOST, value) |
782 | + |
783 | + local_landscape_host = property(_get_local_landscape_host, |
784 | + _set_local_landscape_host) |
785 | + |
786 | + def _get_hosted_account_name(self): |
787 | + return self._current_state.get(HOSTED, ACCOUNT_NAME) |
788 | + |
789 | + def _set_hosted_account_name(self, value): |
790 | + self._current_state.set(HOSTED, ACCOUNT_NAME, value) |
791 | + |
792 | + hosted_account_name = property(_get_hosted_account_name, |
793 | + _set_hosted_account_name) |
794 | + |
795 | + def _get_local_account_name(self): |
796 | + return self._current_state.get(LOCAL, ACCOUNT_NAME) |
797 | + |
798 | + def _set_local_account_name(self, value): |
799 | + self._current_state.set(LOCAL, ACCOUNT_NAME, value) |
800 | + |
801 | + local_account_name = property(_get_local_account_name, |
802 | + _set_local_account_name) |
803 | + |
804 | + def _get_hosted_password(self): |
805 | + return self._current_state.get(HOSTED, PASSWORD) |
806 | + |
807 | + def _set_hosted_password(self, value): |
808 | + self._current_state.set(HOSTED, PASSWORD, value) |
809 | + |
810 | + hosted_password = property(_get_hosted_password, |
811 | + _set_hosted_password) |
812 | + |
813 | + def _get_local_password(self): |
814 | + return self._current_state.get(LOCAL, PASSWORD) |
815 | + |
816 | + def _set_local_password(self, value): |
817 | + self._current_state.set(LOCAL, PASSWORD, value) |
818 | + |
819 | + local_password = property(_get_local_password, |
820 | + _set_local_password) |
821 | |
822 | === modified file 'landscape/ui/model/configuration/tests/test_state.py' |
823 | --- landscape/ui/model/configuration/tests/test_state.py 2012-02-21 10:37:58 +0000 |
824 | +++ landscape/ui/model/configuration/tests/test_state.py 2012-02-29 16:50:20 +0000 |
825 | @@ -1,7 +1,293 @@ |
826 | from landscape.tests.helpers import LandscapeTest |
827 | +from landscape.ui.model.configuration.uisettings import UISettings |
828 | +import landscape.ui.model.configuration.state |
829 | from landscape.ui.model.configuration.state import ( |
830 | ConfigurationModel, StateError, VirginState, InitialisedState, |
831 | - TestedGoodState, TestedBadState, ModifiedState) |
832 | + ModifiedState, IS_HOSTED, HOSTED, LOCAL, HOSTED_LANDSCAPE_HOST, |
833 | + LANDSCAPE_HOST, COMPUTER_TITLE) |
834 | +from landscape.ui.tests.helpers import ConfigurationProxyHelper, FakeGSettings |
835 | + |
836 | + |
837 | +class ConfigurationModelTest(LandscapeTest): |
838 | + """ |
839 | + Test the internal data handling of the L{ConfigurationModel} without |
840 | + loading external data. |
841 | + """ |
842 | + |
843 | + helpers = [ConfigurationProxyHelper] |
844 | + |
845 | + default_data = {"is-hosted": True, |
846 | + "computer-title": "", |
847 | + "hosted-landscape-host": "", |
848 | + "hosted-account-name": "", |
849 | + "hosted-password": "", |
850 | + "local-landscape-host": "", |
851 | + "local-account-name": "", |
852 | + "local-password": "" |
853 | + } |
854 | + |
855 | + def setUp(self): |
856 | + self.config_string = "" |
857 | + landscape.ui.model.configuration.state.DEFAULT_DATA[COMPUTER_TITLE] \ |
858 | + = "bound.to.lose" |
859 | + super(ConfigurationModelTest, self).setUp() |
860 | + |
861 | + def tearDown(self): |
862 | + super(ConfigurationModelTest, self).tearDown() |
863 | + self.proxy = None |
864 | + |
865 | + def test_get(self): |
866 | + """ |
867 | + Test that L{get} correctly extracts data from the internal data storage |
868 | + of the L{ConfigurationState}s associated with a L{ConfigurationModel}. |
869 | + """ |
870 | + settings = FakeGSettings(data=self.default_data) |
871 | + uisettings = UISettings(settings) |
872 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
873 | + state = model.get_state() |
874 | + self.assertTrue(state.get(IS_HOSTED)) |
875 | + self.assertEqual(HOSTED_LANDSCAPE_HOST, |
876 | + state.get(HOSTED, LANDSCAPE_HOST)) |
877 | + self.assertRaises(TypeError, state.get, IS_HOSTED, HOSTED, |
878 | + LANDSCAPE_HOST) |
879 | + self.assertRaises(KeyError, state.get, LANDSCAPE_HOST) |
880 | + self.assertRaises(KeyError, state.get, IS_HOSTED, LANDSCAPE_HOST) |
881 | + |
882 | + def test_set(self): |
883 | + """ |
884 | + Test that L{set} correctly sets data in the internal data storage of |
885 | + the L{ConfigurationState}s associated with a L{ConfigurationModel}. |
886 | + """ |
887 | + settings = FakeGSettings(data=self.default_data) |
888 | + uisettings = UISettings(settings) |
889 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
890 | + state = model.get_state() |
891 | + state.set(IS_HOSTED, True) |
892 | + self.assertTrue(state.get(IS_HOSTED)) |
893 | + state.set(IS_HOSTED, False) |
894 | + self.assertFalse(state.get(IS_HOSTED)) |
895 | + self.assertEqual("", state.get(LOCAL, LANDSCAPE_HOST)) |
896 | + state.set(LOCAL, LANDSCAPE_HOST, "goodison.park") |
897 | + self.assertEqual("goodison.park", state.get(LOCAL, LANDSCAPE_HOST)) |
898 | + |
899 | + def test_virginal(self): |
900 | + """ |
901 | + Test that the L{ConfigurationModel} is created with default data. This |
902 | + should be managed via L{VirginState} (hence the name), but this should |
903 | + not be exposed and is not explicitly tested here (see |
904 | + L{StateTransitionTest}). |
905 | + """ |
906 | + settings = FakeGSettings(data=self.default_data) |
907 | + uisettings = UISettings(settings) |
908 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
909 | + self.assertTrue(model.is_hosted) |
910 | + self.assertEqual(HOSTED_LANDSCAPE_HOST, model.hosted_landscape_host) |
911 | + self.assertEqual("bound.to.lose", model.computer_title) |
912 | + self.assertEqual("", model.local_landscape_host) |
913 | + self.assertEqual("", model.hosted_account_name) |
914 | + self.assertEqual("", model.local_account_name) |
915 | + self.assertEqual("", model.hosted_password) |
916 | + |
917 | + def test_is_hosted_property(self): |
918 | + """ |
919 | + Test we can use the L{is_hosted} property to set and get that data on |
920 | + the current L{ConfigurationState}. |
921 | + """ |
922 | + settings = FakeGSettings(data=self.default_data) |
923 | + uisettings = UISettings(settings) |
924 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
925 | + model.load_data() |
926 | + self.assertTrue(model.is_hosted) |
927 | + model.is_hosted = False |
928 | + self.assertFalse(model.is_hosted) |
929 | + |
930 | + def test_computer_title_property(self): |
931 | + """ |
932 | + Test that we can use the L{computer_title} property to set and get that |
933 | + data on the current L{ConfigurationState}. |
934 | + """ |
935 | + settings = FakeGSettings(data=self.default_data) |
936 | + uisettings = UISettings(settings) |
937 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
938 | + model.load_data() |
939 | + self.assertEqual("bound.to.lose", model.computer_title) |
940 | + model.computer_title = "bound.to.win" |
941 | + self.assertEqual("bound.to.win", model.computer_title) |
942 | + |
943 | + def test_hosted_landscape_host_property(self): |
944 | + """ |
945 | + Test we can use the L{hosted_landscape_host} property to set and get |
946 | + that data on the current L{ConfigurationState}. |
947 | + """ |
948 | + settings = FakeGSettings(data=self.default_data) |
949 | + uisettings = UISettings(settings) |
950 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
951 | + self.assertEqual(HOSTED_LANDSCAPE_HOST, model.hosted_landscape_host) |
952 | + model.hosted_landscape_host = "foo" |
953 | + self.assertEqual("foo", model.hosted_landscape_host) |
954 | + |
955 | + def test_hosted_account_name_property(self): |
956 | + """ |
957 | + Test we can use the L{hosted_account_name} property to set and get |
958 | + that data on the current L{ConfigurationState}. |
959 | + """ |
960 | + settings = FakeGSettings(data=self.default_data) |
961 | + uisettings = UISettings(settings) |
962 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
963 | + self.assertEqual("", model.hosted_account_name) |
964 | + model.hosted_account_name = "foo" |
965 | + self.assertEqual("foo", model.hosted_account_name) |
966 | + |
967 | + def test_hosted_password_property(self): |
968 | + """ |
969 | + Test we can use the L{hosted_password} property to set and get |
970 | + that data on the current L{ConfigurationState}. |
971 | + """ |
972 | + settings = FakeGSettings(data=self.default_data) |
973 | + uisettings = UISettings(settings) |
974 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
975 | + self.assertEqual("", model.hosted_password) |
976 | + model.hosted_password = "foo" |
977 | + self.assertEqual("foo", model.hosted_password) |
978 | + |
979 | + def test_local_landscape_host_property(self): |
980 | + """ |
981 | + Test we can use the L{local_landscape_host} property to set and get |
982 | + that data on the current L{ConfigurationState}. |
983 | + """ |
984 | + settings = FakeGSettings(data=self.default_data) |
985 | + uisettings = UISettings(settings) |
986 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
987 | + self.assertEqual("", model.local_landscape_host) |
988 | + model.local_landscape_host = "foo" |
989 | + self.assertEqual("foo", model.local_landscape_host) |
990 | + |
991 | + def test_local_account_name_property(self): |
992 | + """ |
993 | + Test we can use the L{local_account_name} property to set and get |
994 | + that data on the current L{ConfigurationState}. |
995 | + """ |
996 | + settings = FakeGSettings(data=self.default_data) |
997 | + uisettings = UISettings(settings) |
998 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
999 | + self.assertEqual("", model.local_account_name) |
1000 | + model.local_account_name = "foo" |
1001 | + self.assertEqual("foo", model.local_account_name) |
1002 | + |
1003 | + def test_local_password_property(self): |
1004 | + """ |
1005 | + Test we can use the L{local_password} property to set and get |
1006 | + that data on the current L{ConfigurationState}. |
1007 | + """ |
1008 | + settings = FakeGSettings(data=self.default_data) |
1009 | + uisettings = UISettings(settings) |
1010 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1011 | + self.assertEqual("", model.local_password) |
1012 | + model.local_password = "foo" |
1013 | + self.assertEqual("foo", model.local_password) |
1014 | + |
1015 | + |
1016 | +class ConfigurationModelHostedTest(LandscapeTest): |
1017 | + """ |
1018 | + Test the L{ConfigurationModel} is correctly initialised when the live |
1019 | + configuration is set for a hosted account. |
1020 | + |
1021 | + Note the multilayer data loading: |
1022 | + |
1023 | + 1. Internal state is defaulted. |
1024 | + 2. UISettings data is loaded. |
1025 | + 3. Live configuration is loaded. |
1026 | + """ |
1027 | + |
1028 | + helpers = [ConfigurationProxyHelper] |
1029 | + |
1030 | + default_data = {"is-hosted": True, |
1031 | + "computer-title": "bound.to.lose", |
1032 | + "hosted-landscape-host": "landscape.canonical.com", |
1033 | + "hosted-account-name": "Sparklehorse", |
1034 | + "hosted-password": "Vivadixiesubmarinetransmissionplot", |
1035 | + "local-landscape-host": "the.local.machine", |
1036 | + "local-account-name": "CrazyHorse", |
1037 | + "local-password": "RustNeverSleeps" |
1038 | + } |
1039 | + |
1040 | + def setUp(self): |
1041 | + self.config_string = "[client]\n" \ |
1042 | + "data_path = /var/lib/landscape/client/\n" \ |
1043 | + "http_proxy = http://proxy.localdomain:3192\n" \ |
1044 | + "tags = a_tag\n" \ |
1045 | + "url = https://landscape.canonical.com/message-system\n" \ |
1046 | + "account_name = foo\n" \ |
1047 | + "registration_password = boink\n" \ |
1048 | + "computer_title = baz\n" \ |
1049 | + "https_proxy = https://proxy.localdomain:6192\n" \ |
1050 | + "ping_url = http://landscape.canonical.com/ping\n" |
1051 | + |
1052 | + super(ConfigurationModelHostedTest, self).setUp() |
1053 | + |
1054 | + def test_initialised_hosted(self): |
1055 | + """ |
1056 | + Test the L{ConfigurationModel} is correctly initialised from a proxy |
1057 | + and defaults with hosted data. |
1058 | + """ |
1059 | + settings = FakeGSettings(data=self.default_data) |
1060 | + uisettings = UISettings(settings) |
1061 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1062 | + model.load_data() |
1063 | + self.assertTrue(model.is_hosted) |
1064 | + self.assertEqual("landscape.canonical.com", |
1065 | + model.hosted_landscape_host) |
1066 | + self.assertEqual("the.local.machine", model.local_landscape_host) |
1067 | + self.assertEqual("foo", model.hosted_account_name) |
1068 | + self.assertEqual("CrazyHorse", model.local_account_name) |
1069 | + self.assertEqual("boink", model.hosted_password) |
1070 | + |
1071 | + |
1072 | +class ConfigurationModelLocalTest(LandscapeTest): |
1073 | + |
1074 | + helpers = [ConfigurationProxyHelper] |
1075 | + |
1076 | + default_data = {"is-hosted": True, |
1077 | + "computer-title": "bound.to.lose", |
1078 | + "hosted-landscape-host": "landscape.canonical.com", |
1079 | + "hosted-account-name": "Sparklehorse", |
1080 | + "hosted-password": "Vivadixiesubmarinetransmissionplot", |
1081 | + "local-landscape-host": "the.local.machine", |
1082 | + "local-account-name": "CrazyHorse", |
1083 | + "local-password": "RustNeverSleeps" |
1084 | + } |
1085 | + |
1086 | + def setUp(self): |
1087 | + self.config_string = "[client]\n" \ |
1088 | + "data_path = /var/lib/landscape/client/\n" \ |
1089 | + "http_proxy = http://proxy.localdomain:3192\n" \ |
1090 | + "tags = a_tag\n" \ |
1091 | + "url = https://landscape.localdomain/message-system\n" \ |
1092 | + "account_name = foo\n" \ |
1093 | + "registration_password = boink\n" \ |
1094 | + "computer_title = baz\n" \ |
1095 | + "https_proxy = \n" \ |
1096 | + "ping_url = http://landscape.localdomain/ping\n" |
1097 | + |
1098 | + super(ConfigurationModelLocalTest, self).setUp() |
1099 | + |
1100 | + def test_initialised_local(self): |
1101 | + """ |
1102 | + Test the L{ConfigurationModel} is correctly initialised from a proxy |
1103 | + and defaults with local data. |
1104 | + """ |
1105 | + settings = FakeGSettings(data=self.default_data) |
1106 | + uisettings = UISettings(settings) |
1107 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1108 | + model.load_data() |
1109 | + self.assertFalse(model.is_hosted) |
1110 | + self.assertEqual("landscape.canonical.com", |
1111 | + model.hosted_landscape_host) |
1112 | + self.assertEqual("landscape.localdomain", model.local_landscape_host) |
1113 | + self.assertEqual("Sparklehorse", model.hosted_account_name) |
1114 | + self.assertEqual("foo", model.local_account_name) |
1115 | + self.assertEqual("Vivadixiesubmarinetransmissionplot", |
1116 | + model.hosted_password) |
1117 | |
1118 | |
1119 | class StateTransitionTest(LandscapeTest): |
1120 | @@ -10,12 +296,30 @@ |
1121 | L{ConfigurationModel}. |
1122 | """ |
1123 | |
1124 | + helpers = [ConfigurationProxyHelper] |
1125 | + |
1126 | + def setUp(self): |
1127 | + self.config_string = "" |
1128 | + self.default_data = { |
1129 | + "is-hosted": True, |
1130 | + "computer-title": "bound.to.lose", |
1131 | + "hosted-landscape-host": "landscape.canonical.com", |
1132 | + "hosted-account-name": "Sparklehorse", |
1133 | + "hosted-password": "Vivadixiesubmarinetransmissionplot", |
1134 | + "local-landscape-host": "the.local.machine", |
1135 | + "local-account-name": "CrazyHorse", |
1136 | + "local-password": "RustNeverSleeps" |
1137 | + } |
1138 | + super(StateTransitionTest, self).setUp() |
1139 | + |
1140 | def test_load_data_transitions(self): |
1141 | """ |
1142 | Test that the L{ConfigurationModel} correctly changes state as we call |
1143 | L{load_data}. |
1144 | """ |
1145 | - model = ConfigurationModel() |
1146 | + settings = FakeGSettings(data=self.default_data) |
1147 | + uisettings = UISettings(settings) |
1148 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1149 | self.assertTrue(isinstance(model.get_state(), VirginState)) |
1150 | model.load_data() |
1151 | self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1152 | @@ -24,54 +328,14 @@ |
1153 | self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1154 | self.assertIs(initialised, model.get_state()) |
1155 | |
1156 | - def test_testing_a_virgin_raises(self): |
1157 | - """ |
1158 | - Test that calling L{test} on a L{ConfigurationModel} in L{VirginState} |
1159 | - raises an error. |
1160 | - """ |
1161 | - model = ConfigurationModel() |
1162 | - self.assertTrue(isinstance(model.get_state(), VirginState)) |
1163 | - self.assertRaises(StateError, model.test) |
1164 | - |
1165 | - def test_load_data_on_tested_state_raises(self): |
1166 | - """ |
1167 | - Test that calling L{load_data} on a L{ConfigurationModel} in either one |
1168 | - of the two L{TestedState} subclasses (L{TestedGoodState} or |
1169 | - L{TestedBadState}) will raise a L{StateError}. |
1170 | - """ |
1171 | - test_succeed = lambda: True |
1172 | - test_fail = lambda: False |
1173 | - model = ConfigurationModel(test_method=test_succeed) |
1174 | - model.load_data() |
1175 | - model.test() |
1176 | - self.assertRaises(StateError, model.load_data) |
1177 | - model = ConfigurationModel(test_method=test_fail) |
1178 | - model.load_data() |
1179 | - model.test() |
1180 | - self.assertRaises(StateError, model.load_data) |
1181 | - |
1182 | - def test_test_transition(self): |
1183 | - """ |
1184 | - Test that the L{ConfigurationModel} transitions to a L{TestedGoodState} |
1185 | - or a L{TestedBadState} when L{test} is called. |
1186 | - """ |
1187 | - test_succeed = lambda: True |
1188 | - test_fail = lambda: False |
1189 | - model = ConfigurationModel(test_method=test_succeed) |
1190 | - model.load_data() |
1191 | - model.test() |
1192 | - self.assertTrue(isinstance(model.get_state(), TestedGoodState)) |
1193 | - model = ConfigurationModel(test_method=test_fail) |
1194 | - model.load_data() |
1195 | - model.test() |
1196 | - self.assertTrue(isinstance(model.get_state(), TestedBadState)) |
1197 | - |
1198 | def test_modifying_a_virgin_raises(self): |
1199 | """ |
1200 | Test that attempting a L{modify} a L{ConfigurationModel} in |
1201 | L{VirginState} raises a L{StateError}. |
1202 | """ |
1203 | - model = ConfigurationModel() |
1204 | + settings = FakeGSettings(data=self.default_data) |
1205 | + uisettings = UISettings(settings) |
1206 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1207 | self.assertRaises(StateError, model.modify) |
1208 | |
1209 | def test_initialised_state_is_modifiable(self): |
1210 | @@ -79,50 +343,28 @@ |
1211 | Test that the L{ConfigurationModel} transitions to L{ModifiedState} |
1212 | whenever L{modify} is called on it in L{InitialisedState}. |
1213 | """ |
1214 | - model = ConfigurationModel() |
1215 | + settings = FakeGSettings(data=self.default_data) |
1216 | + uisettings = UISettings(settings) |
1217 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1218 | model.load_data() |
1219 | + self.assertTrue(model.is_hosted) |
1220 | + model.is_hosted = False |
1221 | + self.assertFalse(model.is_hosted) |
1222 | model.modify() |
1223 | self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1224 | + self.assertFalse(model.is_hosted) |
1225 | |
1226 | def test_modified_state_is_modifiable(self): |
1227 | """ |
1228 | Test that the L{ConfigurationModel} transitions to L{ModifiedState} |
1229 | whenever L{modify} is called on it in L{ModifiedState}. |
1230 | """ |
1231 | - model = ConfigurationModel() |
1232 | - model.load_data() |
1233 | - model.modify() |
1234 | - self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1235 | - model.modify() |
1236 | - self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1237 | - |
1238 | - def test_modified_state_is_testable(self): |
1239 | - """ |
1240 | - Test that the L{ConfigurationModel} can be transitioned via L{test} |
1241 | - when it is in the L{ModifiedState}. |
1242 | - """ |
1243 | - model = ConfigurationModel() |
1244 | - model.load_data() |
1245 | - model.modify() |
1246 | - model.test() |
1247 | - self.assertTrue(isinstance(model.get_state(), TestedGoodState)) |
1248 | - |
1249 | - def test_tested_states_are_modifiable(self): |
1250 | - """ |
1251 | - Test that the L{ConfigurationModel} transitions to L{ModifiedState} |
1252 | - whenever L{modify} is called on it in a subclass of L{TestedState} |
1253 | - (L{TestedGoodState} or L{TestedBadState}). |
1254 | - """ |
1255 | - test_succeed = lambda: True |
1256 | - test_fail = lambda: False |
1257 | - model = ConfigurationModel(test_method=test_succeed) |
1258 | - model.load_data() |
1259 | - model.test() |
1260 | - model.modify() |
1261 | - self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1262 | - model = ConfigurationModel(test_method=test_fail) |
1263 | - model.load_data() |
1264 | - model.test() |
1265 | + settings = FakeGSettings(data=self.default_data) |
1266 | + uisettings = UISettings(settings) |
1267 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1268 | + model.load_data() |
1269 | + model.modify() |
1270 | + self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1271 | model.modify() |
1272 | self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1273 | |
1274 | @@ -131,7 +373,9 @@ |
1275 | Test that calling L{revert} on a L{ConfigurationModel} in |
1276 | L{VirginState} raises a L{StateError}. |
1277 | """ |
1278 | - model = ConfigurationModel() |
1279 | + settings = FakeGSettings(data=self.default_data) |
1280 | + uisettings = UISettings(settings) |
1281 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1282 | self.assertRaises(StateError, model.revert) |
1283 | |
1284 | def test_initialiased_state_is_unrevertable(self): |
1285 | @@ -139,7 +383,9 @@ |
1286 | Test that calling L{revert} on a L{ConfigurationModel} in |
1287 | L{InitialisedState} raises a L{StateError}. |
1288 | """ |
1289 | - model = ConfigurationModel() |
1290 | + settings = FakeGSettings(data=self.default_data) |
1291 | + uisettings = UISettings(settings) |
1292 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1293 | model.load_data() |
1294 | self.assertRaises(StateError, model.revert) |
1295 | |
1296 | @@ -148,36 +394,43 @@ |
1297 | Test that a L{ConfigurationModel} in L{ModifiedState} can be |
1298 | transitioned via L{revert} to L{InitialisedState}. |
1299 | """ |
1300 | - model = ConfigurationModel() |
1301 | + settings = FakeGSettings(data=self.default_data) |
1302 | + uisettings = UISettings(settings) |
1303 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1304 | model.load_data() |
1305 | model.modify() |
1306 | model.revert() |
1307 | self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1308 | |
1309 | - def test_tested_states_are_revertable(self): |
1310 | - """ |
1311 | - Test that a L{ConfigurationModel} in one of the two L{TestedState}s can |
1312 | - be transitioned via L{revert} to L{InitialisedState}. |
1313 | - """ |
1314 | - test_succeed = lambda: True |
1315 | - test_fail = lambda: False |
1316 | - model = ConfigurationModel(test_method=test_succeed) |
1317 | - model.load_data() |
1318 | - model.test() |
1319 | - model.revert() |
1320 | - self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1321 | - model = ConfigurationModel(test_method=test_fail) |
1322 | - model.load_data() |
1323 | - model.test() |
1324 | - model.revert() |
1325 | - self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1326 | + def test_reverting_reverts_data(self): |
1327 | + """ |
1328 | + Test that transitioning via L{revert} causes the original |
1329 | + L{InitialisedState} to be restored. |
1330 | + """ |
1331 | + settings = FakeGSettings(data=self.default_data) |
1332 | + uisettings = UISettings(settings) |
1333 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1334 | + model.load_data() |
1335 | + self.assertEqual(HOSTED_LANDSCAPE_HOST, model.hosted_landscape_host) |
1336 | + self.assertEqual("CrazyHorse", model.local_account_name) |
1337 | + model.hosted_landscape_host = "foo" |
1338 | + model.local_account_name = "bar" |
1339 | + model.modify() |
1340 | + self.assertEqual("foo", model.hosted_landscape_host) |
1341 | + self.assertEqual("bar", model.local_account_name) |
1342 | + model.revert() |
1343 | + self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1344 | + self.assertEqual(HOSTED_LANDSCAPE_HOST, model.hosted_landscape_host) |
1345 | + self.assertEqual("CrazyHorse", model.local_account_name) |
1346 | |
1347 | def test_persisting_a_virgin_raises(self): |
1348 | """ |
1349 | Test that a L{ConfigurationModel} in L{VirginState} will raise a |
1350 | L{StateError} when you attempt to transition it with L{persist}. |
1351 | """ |
1352 | - model = ConfigurationModel() |
1353 | + settings = FakeGSettings(data=self.default_data) |
1354 | + uisettings = UISettings(settings) |
1355 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1356 | self.assertRaises(StateError, model.persist) |
1357 | |
1358 | def test_persisting_initialised_state_raises(self): |
1359 | @@ -185,39 +438,107 @@ |
1360 | Test that a L{ConfigurationModel} in L{IntialisedState} will raise a |
1361 | L{StateError} when you attempt to transition it with L{persist}. |
1362 | """ |
1363 | - model = ConfigurationModel() |
1364 | - model.load_data() |
1365 | - self.assertRaises(StateError, model.persist) |
1366 | - |
1367 | - def test_persisting_modified_state_raises(self): |
1368 | - """ |
1369 | - Test that a L{ConfigurationModel} in L{InitialisedState} will raise a |
1370 | - L{StateError} when you attempt to transition it with L{persist}. |
1371 | - """ |
1372 | - model = ConfigurationModel() |
1373 | - model.load_data() |
1374 | - model.modify() |
1375 | - self.assertRaises(StateError, model.persist) |
1376 | - |
1377 | - def test_persisting_tested_bad_state_raises(self): |
1378 | - """ |
1379 | - Test that a L{ConfigurationModel} in L{TestedBadState} will raise a |
1380 | - L{StateError} when you attempt to transition it with L{persist}. |
1381 | - """ |
1382 | - test_fail = lambda: False |
1383 | - model = ConfigurationModel(test_method=test_fail) |
1384 | - model.load_data() |
1385 | - model.test() |
1386 | - self.assertRaises(StateError, model.persist) |
1387 | - |
1388 | - def test_persist_tested_good_state(self): |
1389 | - """ |
1390 | - Test that a L{ConfigurationModel} in L{TestedGoodState} can be |
1391 | - transitioned via L{persist} to a L{IntialisedState}. |
1392 | - """ |
1393 | - test_succeed = lambda: True |
1394 | - model = ConfigurationModel(test_method=test_succeed) |
1395 | - model.load_data() |
1396 | - model.test() |
1397 | - model.persist() |
1398 | - self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1399 | + settings = FakeGSettings(data=self.default_data) |
1400 | + uisettings = UISettings(settings) |
1401 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1402 | + model.load_data() |
1403 | + self.assertRaises(StateError, model.persist) |
1404 | + |
1405 | + def test_persisting_modified_is_allowed(self): |
1406 | + """ |
1407 | + Test that a L{ConfigurationModel} in L{ModifiedState} will allow itself |
1408 | + to be transitioned with L{persist}. |
1409 | + """ |
1410 | + settings = FakeGSettings(data=self.default_data) |
1411 | + uisettings = UISettings(settings) |
1412 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1413 | + model.load_data() |
1414 | + model.modify() |
1415 | + model.persist() |
1416 | + self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1417 | + |
1418 | + def test_persisting_saves_data_to_uisettings(self): |
1419 | + settings = FakeGSettings(data=self.default_data) |
1420 | + uisettings = UISettings(settings) |
1421 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1422 | + model.load_data() |
1423 | + self.assertTrue(uisettings.get_is_hosted()) |
1424 | + self.assertEqual("Sparklehorse", uisettings.get_hosted_account_name()) |
1425 | + self.assertEqual("Vivadixiesubmarinetransmissionplot", |
1426 | + uisettings.get_hosted_password()) |
1427 | + self.assertEqual("the.local.machine", |
1428 | + uisettings.get_local_landscape_host()) |
1429 | + self.assertEqual("CrazyHorse", uisettings.get_local_account_name()) |
1430 | + self.assertEqual("RustNeverSleeps", uisettings.get_local_password()) |
1431 | + model.is_hosted = False |
1432 | + model.hosted_account_name = "ThomasPaine" |
1433 | + model.hosted_password = "TheAgeOfReason" |
1434 | + model.local_landscape_host = "another.local.machine" |
1435 | + model.local_account_name = "ThomasHobbes" |
1436 | + model.local_password = "TheLeviathan" |
1437 | + model.modify() |
1438 | + self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1439 | + model.persist() |
1440 | + self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1441 | + self.assertFalse(uisettings.get_is_hosted()) |
1442 | + self.assertEqual("ThomasPaine", uisettings.get_hosted_account_name()) |
1443 | + self.assertEqual("TheAgeOfReason", uisettings.get_hosted_password()) |
1444 | + self.assertEqual("another.local.machine", |
1445 | + uisettings.get_local_landscape_host()) |
1446 | + self.assertEqual("ThomasHobbes", uisettings.get_local_account_name()) |
1447 | + self.assertEqual("TheLeviathan", uisettings.get_local_password()) |
1448 | + |
1449 | + |
1450 | +class StateTransitionWithExistingConfigTest(LandscapeTest): |
1451 | + """ |
1452 | + Test that we handle existing configuration data correctly when |
1453 | + transitioning through L{ConfigurationModel} states. |
1454 | + """ |
1455 | + |
1456 | + helpers = [ConfigurationProxyHelper] |
1457 | + |
1458 | + def setUp(self): |
1459 | + self.config_string = ( |
1460 | + "[client]\n" |
1461 | + "data_path = /var/lib/landscape/client/\n" |
1462 | + "http_proxy = http://proxy.localdomain:3192\n" |
1463 | + "tags = a_tag\n" |
1464 | + "url = https://landscape.canonical.com/message-system\n" |
1465 | + "account_name = Sparklehorse\n" |
1466 | + "registration_password = Vivadixiesubmarinetransmissionplot\n" |
1467 | + "computer_title = baz\n" |
1468 | + "https_proxy = https://proxy.localdomain:6192\n" |
1469 | + "ping_url = http://landscape.canonical.com/ping\n") |
1470 | + self.default_data = { |
1471 | + "is-hosted": True, |
1472 | + "computer-title": "bound.to.lose", |
1473 | + "hosted-landscape-host": "landscape.canonical.com", |
1474 | + "hosted-account-name": "Sparklehorse", |
1475 | + "hosted-password": "Vivadixiesubmarinetransmissionplot", |
1476 | + "local-landscape-host": "the.local.machine", |
1477 | + "local-account-name": "CrazyHorse", |
1478 | + "local-password": "RustNeverSleeps" |
1479 | + } |
1480 | + super(StateTransitionWithExistingConfigTest, self).setUp() |
1481 | + |
1482 | + def test_persisting_saves_data_to_proxy(self): |
1483 | + settings = FakeGSettings(data=self.default_data) |
1484 | + uisettings = UISettings(settings) |
1485 | + model = ConfigurationModel(proxy=self.proxy, uisettings=uisettings) |
1486 | + model.load_data() |
1487 | + self.assertEqual("Sparklehorse", self.proxy.account_name) |
1488 | + self.assertEqual("Vivadixiesubmarinetransmissionplot", |
1489 | + self.proxy.registration_password) |
1490 | + model.is_hosted = False |
1491 | + model.local_account_name = "ThomasPaine" |
1492 | + model.local_password = "TheAgeOfReason" |
1493 | + model.modify() |
1494 | + self.assertTrue(isinstance(model.get_state(), ModifiedState)) |
1495 | + model.persist() |
1496 | + self.assertTrue(isinstance(model.get_state(), InitialisedState)) |
1497 | + self.assertFalse(model.is_hosted) |
1498 | + self.assertEqual("https://the.local.machine/message-system", |
1499 | + self.proxy.url) |
1500 | + self.assertEqual("http://the.local.machine/ping", self.proxy.ping_url) |
1501 | + self.assertEqual("ThomasPaine", self.proxy.account_name) |
1502 | + self.assertEqual("TheAgeOfReason", self.proxy.registration_password) |
1503 | |
1504 | === added file 'landscape/ui/model/configuration/tests/test_uisettings.py' |
1505 | --- landscape/ui/model/configuration/tests/test_uisettings.py 1970-01-01 00:00:00 +0000 |
1506 | +++ landscape/ui/model/configuration/tests/test_uisettings.py 2012-02-29 16:50:20 +0000 |
1507 | @@ -0,0 +1,189 @@ |
1508 | +from landscape.tests.helpers import LandscapeTest |
1509 | +from landscape.ui.tests.helpers import FakeGSettings |
1510 | +from landscape.ui.model.configuration.uisettings import UISettings |
1511 | + |
1512 | + |
1513 | +class UISettingsTest(LandscapeTest): |
1514 | + |
1515 | + default_data = {"is-hosted": True, |
1516 | + "computer-title": "bound.to.lose", |
1517 | + "hosted-landscape-host": "landscape.canonical.com", |
1518 | + "hosted-account-name": "Sparklehorse", |
1519 | + "hosted-password": "Vivadixiesubmarinetransmissionplot", |
1520 | + "local-landscape-host": "the.local.machine", |
1521 | + "local-account-name": "CrazyHorse", |
1522 | + "local-password": "RustNeverSleeps" |
1523 | + } |
1524 | + |
1525 | + def test_setup(self): |
1526 | + """ |
1527 | + Test that the L{GSettings.Client} is correctly initialised. |
1528 | + """ |
1529 | + settings = FakeGSettings(data=self.default_data) |
1530 | + UISettings(settings) |
1531 | + self.assertTrue(settings.was_called_with_args( |
1532 | + "new", UISettings.BASE_KEY)) |
1533 | + |
1534 | + def test_get_is_hosted(self): |
1535 | + """ |
1536 | + Test that the L{get_is_hosted} value is correctly fetched from the |
1537 | + L{GSettings.Client}. |
1538 | + """ |
1539 | + settings = FakeGSettings(data=self.default_data) |
1540 | + uisettings = UISettings(settings) |
1541 | + self.assertTrue(uisettings.get_is_hosted()) |
1542 | + |
1543 | + def test_set_is_hosted(self): |
1544 | + """ |
1545 | + Test that we can correctly use L{set_is_hosted} to write the |
1546 | + L{is_hosted} value to the L{GSettings.Client}. |
1547 | + """ |
1548 | + settings = FakeGSettings(data=self.default_data) |
1549 | + uisettings = UISettings(settings) |
1550 | + self.assertTrue(uisettings.get_is_hosted()) |
1551 | + uisettings.set_is_hosted(False) |
1552 | + self.assertFalse(uisettings.get_is_hosted()) |
1553 | + self.assertTrue(settings.was_called_with_args( |
1554 | + "set_boolean", "is-hosted", False)) |
1555 | + |
1556 | + def test_get_computer_title(self): |
1557 | + """ |
1558 | + Test that the L{get_computer_title} value is correctly fetched |
1559 | + from the L{GSettings.Client}. |
1560 | + """ |
1561 | + settings = FakeGSettings(data=self.default_data) |
1562 | + uisettings = UISettings(settings) |
1563 | + self.assertEqual("bound.to.lose", |
1564 | + uisettings.get_computer_title()) |
1565 | + |
1566 | + def test_set_computer_title(self): |
1567 | + """ |
1568 | + Test that L{set_computer_title} correctly sets the value of |
1569 | + L{computer_title} in the L{GSettings.Client}. |
1570 | + """ |
1571 | + settings = FakeGSettings(data=self.default_data) |
1572 | + uisettings = UISettings(settings) |
1573 | + self.assertEqual("bound.to.lose", uisettings.get_computer_title()) |
1574 | + uisettings.set_computer_title("Bang") |
1575 | + self.assertEqual("Bang", uisettings.get_computer_title()) |
1576 | + |
1577 | + def test_get_hosted_landscape_host(self): |
1578 | + """ |
1579 | + Test that the L{get_hosted_landscape_host} value is correctly fetched |
1580 | + from the L{GSettings.Client}. |
1581 | + """ |
1582 | + settings = FakeGSettings(data=self.default_data) |
1583 | + uisettings = UISettings(settings) |
1584 | + self.assertEqual("landscape.canonical.com", |
1585 | + uisettings.get_hosted_landscape_host()) |
1586 | + |
1587 | + # NOTE: There is no facility to set the hosted-landscape-host |
1588 | + |
1589 | + def test_get_hosted_account_name(self): |
1590 | + """ |
1591 | + Test that the L{get_hosted_account_name} value is correctly fetched |
1592 | + from the L{GSettings.Client}. |
1593 | + """ |
1594 | + settings = FakeGSettings(data=self.default_data) |
1595 | + uisettings = UISettings(settings) |
1596 | + self.assertEqual("Sparklehorse", |
1597 | + uisettings.get_hosted_account_name()) |
1598 | + |
1599 | + def test_set_hosted_account_name(self): |
1600 | + """ |
1601 | + Test that L{set_hosted_account_name} correctly sets the value of |
1602 | + L{hosted_account_name} in the L{GSettings.Client}. |
1603 | + """ |
1604 | + settings = FakeGSettings(data=self.default_data) |
1605 | + uisettings = UISettings(settings) |
1606 | + self.assertEqual("Sparklehorse", uisettings.get_hosted_account_name()) |
1607 | + uisettings.set_hosted_account_name("Bang") |
1608 | + self.assertEqual("Bang", uisettings.get_hosted_account_name()) |
1609 | + |
1610 | + def test_get_hosted_password(self): |
1611 | + """ |
1612 | + Test that the L{get_hosted_password} value is correctly fetched |
1613 | + from the L{GSettings.Client}. |
1614 | + """ |
1615 | + settings = FakeGSettings(data=self.default_data) |
1616 | + uisettings = UISettings(settings) |
1617 | + self.assertEqual("Vivadixiesubmarinetransmissionplot", |
1618 | + uisettings.get_hosted_password()) |
1619 | + |
1620 | + def test_set_hosted_password(self): |
1621 | + """ |
1622 | + Test that L{set_hosted_password} correctly sets the value of |
1623 | + L{hosted_password} in the L{GSettings.Client}. |
1624 | + """ |
1625 | + settings = FakeGSettings(data=self.default_data) |
1626 | + uisettings = UISettings(settings) |
1627 | + self.assertEqual("Vivadixiesubmarinetransmissionplot", |
1628 | + uisettings.get_hosted_password()) |
1629 | + uisettings.set_hosted_password("Bang") |
1630 | + self.assertEqual("Bang", uisettings.get_hosted_password()) |
1631 | + |
1632 | + def test_get_local_landscape_host(self): |
1633 | + """ |
1634 | + Test that the L{get_local_landscape_host} value is correctly fetched |
1635 | + from the L{GSettings.Client}. |
1636 | + """ |
1637 | + settings = FakeGSettings(data=self.default_data) |
1638 | + uisettings = UISettings(settings) |
1639 | + self.assertEqual("the.local.machine", |
1640 | + uisettings.get_local_landscape_host()) |
1641 | + |
1642 | + def test_set_local_landscape_host(self): |
1643 | + """ |
1644 | + Test that L{set_local_landscape_host} correctly sets the value of |
1645 | + L{local_landscape_host} in the L{GSettings.Client}. |
1646 | + """ |
1647 | + settings = FakeGSettings(data=self.default_data) |
1648 | + uisettings = UISettings(settings) |
1649 | + self.assertEqual("the.local.machine", |
1650 | + uisettings.get_local_landscape_host()) |
1651 | + uisettings.set_local_landscape_host("Bang") |
1652 | + self.assertEqual("Bang", uisettings.get_local_landscape_host()) |
1653 | + |
1654 | + def test_get_local_account_name(self): |
1655 | + """ |
1656 | + Test that the L{get_local_account_name} value is correctly fetched |
1657 | + from the L{GSettings.Client}. |
1658 | + """ |
1659 | + settings = FakeGSettings(data=self.default_data) |
1660 | + uisettings = UISettings(settings) |
1661 | + self.assertEqual("CrazyHorse", |
1662 | + uisettings.get_local_account_name()) |
1663 | + |
1664 | + def test_set_local_account_name(self): |
1665 | + """ |
1666 | + Test that L{set_local_account_name} correctly sets the value of |
1667 | + L{local_account_name} in the L{GSettings.Client}. |
1668 | + """ |
1669 | + settings = FakeGSettings(data=self.default_data) |
1670 | + uisettings = UISettings(settings) |
1671 | + self.assertEqual("CrazyHorse", |
1672 | + uisettings.get_local_account_name()) |
1673 | + uisettings.set_local_account_name("Bang") |
1674 | + self.assertEqual("Bang", uisettings.get_local_account_name()) |
1675 | + |
1676 | + def test_get_local_password(self): |
1677 | + """ |
1678 | + Test that the L{get_local_password} value is correctly fetched |
1679 | + from the L{GSettings.Client}. |
1680 | + """ |
1681 | + settings = FakeGSettings(data=self.default_data) |
1682 | + uisettings = UISettings(settings) |
1683 | + self.assertEqual("RustNeverSleeps", |
1684 | + uisettings.get_local_password()) |
1685 | + |
1686 | + def test_set_local_password(self): |
1687 | + """ |
1688 | + Test that L{set_local_password} correctly sets the value of |
1689 | + L{local_password} in the L{GSettings.Client}. |
1690 | + """ |
1691 | + settings = FakeGSettings(data=self.default_data) |
1692 | + uisettings = UISettings(settings) |
1693 | + self.assertEqual("RustNeverSleeps", |
1694 | + uisettings.get_local_password()) |
1695 | + uisettings.set_local_password("Bang") |
1696 | + self.assertEqual("Bang", uisettings.get_local_password()) |
1697 | |
1698 | === added file 'landscape/ui/model/configuration/uisettings.py' |
1699 | --- landscape/ui/model/configuration/uisettings.py 1970-01-01 00:00:00 +0000 |
1700 | +++ landscape/ui/model/configuration/uisettings.py 2012-02-29 16:50:20 +0000 |
1701 | @@ -0,0 +1,57 @@ |
1702 | +class UISettings(object): |
1703 | + """ |
1704 | + A very thin wrapper around L{GSettings} to avoid having to know the |
1705 | + L{BaseKey} and type information elsewhere. In some future version it would |
1706 | + be right to bind to change events here so we can react to people changing |
1707 | + the settings in dconf, for now that is overkill. |
1708 | + """ |
1709 | + |
1710 | + BASE_KEY = "com.canonical.landscape-client-settings" |
1711 | + |
1712 | + def __init__(self, settings): |
1713 | + self.settings = settings.new(self.BASE_KEY) |
1714 | + |
1715 | + def get_is_hosted(self): |
1716 | + return self.settings.get_boolean("is-hosted") |
1717 | + |
1718 | + def set_is_hosted(self, value): |
1719 | + self.settings.set_boolean("is-hosted", value) |
1720 | + |
1721 | + def get_computer_title(self): |
1722 | + return self.settings.get_string("computer-title") |
1723 | + |
1724 | + def set_computer_title(self, value): |
1725 | + self.settings.set_string("computer-title", value) |
1726 | + |
1727 | + def get_hosted_landscape_host(self): |
1728 | + return self.settings.get_string("hosted-landscape-host") |
1729 | + |
1730 | + def get_hosted_account_name(self): |
1731 | + return self.settings.get_string("hosted-account-name") |
1732 | + |
1733 | + def set_hosted_account_name(self, value): |
1734 | + self.settings.set_string("hosted-account-name", value) |
1735 | + |
1736 | + def get_hosted_password(self): |
1737 | + return self.settings.get_string("hosted-password") |
1738 | + |
1739 | + def set_hosted_password(self, value): |
1740 | + self.settings.set_string("hosted-password", value) |
1741 | + |
1742 | + def get_local_landscape_host(self): |
1743 | + return self.settings.get_string("local-landscape-host") |
1744 | + |
1745 | + def set_local_landscape_host(self, value): |
1746 | + self.settings.set_string("local-landscape-host", value) |
1747 | + |
1748 | + def get_local_account_name(self): |
1749 | + return self.settings.get_string("local-account-name") |
1750 | + |
1751 | + def set_local_account_name(self, value): |
1752 | + self.settings.set_string("local-account-name", value) |
1753 | + |
1754 | + def get_local_password(self): |
1755 | + return self.settings.get_string("local-password") |
1756 | + |
1757 | + def set_local_password(self, value): |
1758 | + self.settings.set_string("local-password", value) |
1759 | |
1760 | === modified file 'landscape/ui/tests/helpers.py' |
1761 | --- landscape/ui/tests/helpers.py 2012-01-26 12:40:16 +0000 |
1762 | +++ landscape/ui/tests/helpers.py 2012-02-29 16:50:20 +0000 |
1763 | @@ -1,3 +1,6 @@ |
1764 | +import os |
1765 | + |
1766 | +from lxml import etree |
1767 | import dbus |
1768 | |
1769 | from landscape.configuration import LandscapeSetupConfiguration |
1770 | @@ -50,3 +53,95 @@ |
1771 | def tear_down(self, test_case): |
1772 | if not dbus_test_should_skip: |
1773 | test_case.mechanism.remove_from_connection() |
1774 | + |
1775 | + |
1776 | +class FakeGSettings(object): |
1777 | + """ |
1778 | + This class impersonates a real L{gi.repostiroy.Gio.GSettings} |
1779 | + object to allow for testing code that utilises it without setting values in |
1780 | + the live DConf. |
1781 | + """ |
1782 | + |
1783 | + calls = {} |
1784 | + |
1785 | + def __init__(self, data={}): |
1786 | + self.set_data(data) |
1787 | + tree = etree.parse( |
1788 | + os.path.join( |
1789 | + os.path.dirname(os.path.abspath(__file__)), |
1790 | + "../../../", |
1791 | + "glib-2.0/schemas/", |
1792 | + "com.canonical.landscape-client-settings.gschema.xml")) |
1793 | + root = tree.getroot() |
1794 | + self.schema = root.find("schema") |
1795 | + assert(self.schema.attrib["id"] == |
1796 | + "com.canonical.landscape-client-settings") |
1797 | + self.keys = {} |
1798 | + for key in self.schema.findall("key"): |
1799 | + self.keys[key.attrib["name"]] = key.attrib["type"] |
1800 | + |
1801 | + def check_key_data(self, name, gstype): |
1802 | + if name in self.keys: |
1803 | + if self.keys[name] == gstype: |
1804 | + return True |
1805 | + else: |
1806 | + raise ValueError("The GSchema file says %s is a %s, " + |
1807 | + "but you asked for a %s" % |
1808 | + (name, self.keys[name], gstype)) |
1809 | + else: |
1810 | + raise KeyError("Can't find %s in the GSchema file!" % name) |
1811 | + |
1812 | + def get_value(self, name, gstype): |
1813 | + if self.check_key_data(name, gstype): |
1814 | + return self.data[name] |
1815 | + |
1816 | + def set_value(self, name, gstype, value): |
1817 | + if self.check_key_data(name, gstype): |
1818 | + self.data[name] = value |
1819 | + |
1820 | + def set_data(self, data): |
1821 | + self.data = data |
1822 | + |
1823 | + def _call(self, name, *args): |
1824 | + [count, arglist] = self.calls.get(name, (0, [])) |
1825 | + count += 1 |
1826 | + arglist.append(self._args_to_string(*args)) |
1827 | + self.calls[name] = [count, arglist] |
1828 | + |
1829 | + def _args_to_string(self, *args): |
1830 | + return "|".join([str(arg) for arg in args]) |
1831 | + |
1832 | + def new(self, key): |
1833 | + self._call("new", key) |
1834 | + return self |
1835 | + |
1836 | + def connect(self, signal, callback, *args): |
1837 | + self._call("connect", signal, callback, *args) |
1838 | + |
1839 | + def get_boolean(self, name): |
1840 | + self._call("get_boolean", name) |
1841 | + return self.get_value(name, "b") |
1842 | + |
1843 | + def set_boolean(self, name, value): |
1844 | + self._call("set_boolean", name, value) |
1845 | + self.set_value(name, "b", value) |
1846 | + |
1847 | + def get_string(self, name): |
1848 | + self._call("get_string", name) |
1849 | + return self.get_value(name, "s") |
1850 | + |
1851 | + def set_string(self, name, value): |
1852 | + self._call("set_string", name, value) |
1853 | + self.set_value(name, "s", value) |
1854 | + |
1855 | + def was_called(self, name): |
1856 | + return self.calls.haskey(name) |
1857 | + |
1858 | + def was_called_with_args(self, name, *args): |
1859 | + try: |
1860 | + [count, arglist] = self.calls.get(name, (0, [])) |
1861 | + except KeyError: |
1862 | + return False |
1863 | + |
1864 | + expected_args = self._args_to_string(*args) |
1865 | + return expected_args in arglist |
1866 | |
1867 | === modified file 'scripts/landscape-client-registration-mechanism' (properties changed: -x to +x) |
1868 | === modified file 'scripts/landscape-client-settings-mechanism' (properties changed: -x to +x) |
1869 | === modified file 'setupui.py' |
1870 | --- setupui.py 2012-01-19 14:06:45 +0000 |
1871 | +++ setupui.py 2012-02-29 16:50:20 +0000 |
1872 | @@ -39,6 +39,7 @@ |
1873 | ff = open(service_path, "w") |
1874 | ff.write(output) |
1875 | ff.close() |
1876 | + os.system("glib-compile-schemas /usr/share/glib-2.0/schemas/") |
1877 | |
1878 | |
1879 | pkit_description = \ |
1880 | @@ -76,7 +77,10 @@ |
1881 | ('/usr/share/applications/', |
1882 | ['applications/landscape-client-settings.desktop']), |
1883 | ('/usr/share/icons/hicolor/scalable/apps/', |
1884 | - ['icons/preferences-management-service.svg'])], |
1885 | + ['icons/preferences-management-service.svg']), |
1886 | + ('/usr/share/glib-2.0/schemas/', |
1887 | + ['glib-2.0/schemas/com.canonical.landscape-client-settings.gschema.xml']) |
1888 | + ], |
1889 | scripts=['scripts/landscape-client-settings-mechanism', |
1890 | 'scripts/landscape-client-registration-mechanism', |
1891 | "scripts/landscape-client-settings-ui"], |
Great stuff, +1!
[1]
+class UISettings(object):
Please add a class docstring here.
[2]
+ def get(self, *args):
and
+ def set(self, *args):
Please add method docstrings explaining what these methods do in detail, as they seem to have non trivial logic.
[3]
+ settings = FakeGSettings( data=self. default_ data) settings) del(proxy= self.proxy, uisettings= uisettings)
+ uisettings = UISettings(
+ model = ConfigurationMo
There are a lot of these, I guess they could be moved to setUp, unless you prefer to have them there because they need slightly different parameters for each test or you like to have less context for a test.