support multi when picklise object
[tiramisu.git] / test / test_state.py
1 from autopath import do_autopath
2 do_autopath()
3
4 from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
5     IntOption, IPOption, NetmaskOption, StrOption, OptionDescription, \
6     DynOptionDescription
7 from tiramisu.config import Config, GroupConfig, MetaConfig
8 from tiramisu.setting import groups, owners
9 from tiramisu.storage import delete_session
10 from tiramisu.error import ConfigError
11 from pickle import dumps, loads
12 from py.test import raises
13
14
15 def return_value(value=None):
16     return value
17
18
19 def _get_slots(opt):
20     slots = set()
21     for subclass in opt.__class__.__mro__:
22         if subclass is not object:
23             slots.update(subclass.__slots__)
24     return slots
25
26
27 def _no_state(opt):
28     for attr in _get_slots(opt):
29         if 'state' in attr:
30             try:
31                 getattr(opt, attr)
32             except:
33                 pass
34             else:
35                 raise Exception('opt should have already attribute {0}'.format(attr))
36
37
38 def _diff_opt(opt1, opt2):
39     attr1 = set(_get_slots(opt1))
40     attr2 = set(_get_slots(opt2))
41     diff1 = attr1 - attr2
42     diff2 = attr2 - attr1
43     if diff1 != set():
44         raise Exception('more attribute in opt1 {0}'.format(list(diff1)))
45     if diff2 != set():
46         raise Exception('more attribute in opt2 {0}'.format(list(diff2)))
47     for attr in attr1:
48         if attr in ['_cache_paths', '_cache_consistencies']:
49             continue
50         err1 = False
51         err2 = False
52         val1 = None
53         val2 = None
54         try:
55             val1 = getattr(opt1, attr)
56             msg1 = "exists"
57         except:
58             err1 = True
59             msg1 = "not exists"
60
61         try:
62             val2 = getattr(opt2, attr)
63             msg2 = "exists"
64         except:
65             err2 = True
66             msg2 = "not exists"
67
68         if not err1 == err2:
69             raise ValueError("{0} {1} before but {2} after for {3}".format(attr, msg1, msg2, opt1.impl_getname()))
70         if val1 is None:
71             assert val1 == val2
72         elif attr == '_children':
73             assert val1[0] == val2[0]
74             for index, _opt in enumerate(val1[1]):
75                 assert _opt._name == val2[1][index]._name
76         elif attr == '_requires':
77             if val1 == val2 == []:
78                 pass
79             else:
80                 assert val1[0][0][0]._name == val2[0][0][0]._name
81                 assert val1[0][0][1:] == val2[0][0][1:]
82         elif attr == '_opt':
83             assert val1._name == val2._name
84         elif attr == '_consistencies':
85             # dict is only a cache
86             if isinstance(val1, list):
87                 for index, consistency in enumerate(val1):
88                     assert consistency[0] == val2[index][0]
89                     for idx, opt in enumerate(consistency[1]):
90                         assert opt._name == val2[index][1][idx]._name
91         elif attr == '_val_call':
92             for idx, v in enumerate(val1):
93                 if v is None:
94                     assert val2[idx] is None
95                 else:
96                     assert v[0] == val2[idx][0]
97                     if len(v) == 2:
98                         if v[1] is not None:
99                             for key, values in v[1].items():
100                                 for i, value in enumerate(values):
101                                     if isinstance(value, tuple) and value[0] is not None:
102                                         assert v[1][key][i][0].impl_getname() == val2[idx][1][key][i][0].impl_getname()
103                                         assert v[1][key][i][1] == val2[idx][1][key][i][1]
104                                     else:
105                                         assert v[1][key][i] == val2[idx][1][key][i]
106                         else:
107                             assert v[1] == val2[idx][1]
108         elif attr == '_master_slaves':
109             assert val1.master.impl_getname() == val2.master.impl_getname()
110             sval1 = [opt.impl_getname() for opt in val1.slaves]
111             sval2 = [opt.impl_getname() for opt in val2.slaves]
112             assert sval1 == sval2
113         elif attr == '_subdyn':
114             try:
115                 assert val1.impl_getname() == val2.impl_getname()
116             except AttributeError:
117                 assert val1 == val2
118         else:
119             assert val1 == val2
120
121
122 def _diff_opts(opt1, opt2):
123     _diff_opt(opt1, opt2)
124     if isinstance(opt1, OptionDescription) or isinstance(opt1, DynOptionDescription):
125         children1 = set([opt.impl_getname() for opt in opt1._impl_getchildren(dyn=False)])
126         children2 = set([opt.impl_getname() for opt in opt2._impl_getchildren(dyn=False)])
127         diff1 = children1 - children2
128         diff2 = children2 - children1
129         if diff1 != set():
130             raise Exception('more attribute in opt1 {0}'.format(list(diff1)))
131         if diff2 != set():
132             raise Exception('more attribute in opt2 {0}'.format(list(diff2)))
133         for child in children1:
134             _diff_opts(opt1._getattr(child, dyn=False), opt2._getattr(child, dyn=False))
135
136
137 def _diff_conf(cfg1, cfg2):
138     attr1 = set(_get_slots(cfg1))
139     attr2 = set(_get_slots(cfg2))
140     diff1 = attr1 - attr2
141     diff2 = attr2 - attr1
142     if diff1 != set():
143         raise Exception('more attribute in cfg1 {0}'.format(list(diff1)))
144     if diff2 != set():
145         raise Exception('more attribute in cfg2 {0}'.format(list(diff2)))
146     for attr in attr1:
147         if attr in ('_impl_context', '__weakref__'):
148             continue
149         err1 = False
150         err2 = False
151         val1 = None
152         val2 = None
153         try:
154             val1 = getattr(cfg1, attr)
155         except:
156             err1 = True
157
158         try:
159             val2 = getattr(cfg2, attr)
160         except:
161             err2 = True
162         assert err1 == err2
163         if val1 is None:
164             assert val1 == val2
165         elif attr == '_impl_values':
166             assert cfg1.cfgimpl_get_values().get_modified_values() == cfg2.cfgimpl_get_values().get_modified_values()
167         elif attr == '_impl_settings':
168             assert cfg1.cfgimpl_get_settings().get_modified_properties() == cfg2.cfgimpl_get_settings().get_modified_properties()
169             assert cfg1.cfgimpl_get_settings().get_modified_permissives() == cfg2.cfgimpl_get_settings().get_modified_permissives()
170         elif attr == '_impl_descr':
171             _diff_opt(cfg1.cfgimpl_get_description(), cfg2.cfgimpl_get_description())
172         elif attr == '_impl_children':
173             for index, _opt in enumerate(val1):
174                 _diff_conf(_opt, val2[index])
175         else:
176             assert val1 == val2
177
178
179 def test_diff_opt():
180     b = BoolOption('b', '')
181     u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
182     s = SymLinkOption('s', u)
183     o = OptionDescription('o', '', [b, u, s])
184     o1 = OptionDescription('o1', '', [o])
185
186     a = dumps(o1)
187     q = loads(a)
188     _diff_opts(o1, q)
189
190
191 def test_diff_opt_multi():
192     b = BoolOption('b', '', multi=True)
193     o = OptionDescription('o', '', [b])
194     o1 = OptionDescription('o1', '', [o])
195
196     a = dumps(o1)
197     q = loads(a)
198     _diff_opt(o1, q)
199     _diff_opt(o1.o, q.o)
200     _diff_opt(o1.o.b, q.o.b)
201
202
203 def test_only_optiondescription():
204     b = BoolOption('b', '')
205     b
206     raises(SystemError, "a = dumps(b)")
207
208
209 def test_diff_opt_cache():
210     b = BoolOption('b', '')
211     u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
212     u.impl_add_consistency('not_equal', b)
213     s = SymLinkOption('s', u)
214     o = OptionDescription('o', '', [b, u, s])
215     o1 = OptionDescription('o1', '', [o])
216     o1.impl_build_cache_consistency()
217     o1.impl_build_cache_option()
218
219     a = dumps(o1)
220     q = loads(a)
221     _diff_opts(o1, q)
222
223
224 def test_diff_opt_callback():
225     b = BoolOption('b', '', callback=return_value)
226     b2 = BoolOption('b2', '', callback=return_value, callback_params={'': ('yes',)})
227     b3 = BoolOption('b3', '', callback=return_value, callback_params={'': ('yes', (b, False)), 'value': ('no',)})
228     b4 = BoolOption("b4", "", callback=return_value, callback_params={'': ((None,),), 'value': ('string',)})
229     o = OptionDescription('o', '', [b, b2, b3, b4])
230     o1 = OptionDescription('o1', '', [o])
231     o1.impl_build_cache_consistency()
232     o1.impl_build_cache_option()
233
234     a = dumps(o1)
235     q = loads(a)
236     _diff_opts(o1, q)
237
238
239 def test_no_state_attr():
240     # all _state_xxx attributes should be deleted
241     b = BoolOption('b', '')
242     u = UnicodeOption('u', '', requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
243     s = SymLinkOption('s', u)
244     o = OptionDescription('o', '', [b, u, s])
245     o1 = OptionDescription('o1', '', [o])
246
247     a = dumps(o1)
248     q = loads(a)
249     _no_state(q)
250     _no_state(q.o)
251     _no_state(q.o.b)
252     _no_state(q.o.u)
253     _no_state(q.o.s)
254
255
256 def test_state_config():
257     val1 = BoolOption('val1', "")
258     maconfig = OptionDescription('rootconfig', '', [val1])
259     try:
260         cfg = Config(maconfig, persistent=True, session_id='29090931')
261     except ValueError:
262         cfg = Config(maconfig, session_id='29090931')
263         cfg._impl_test = True
264     a = dumps(cfg)
265     q = loads(a)
266     _diff_opts(cfg.cfgimpl_get_description(), q.cfgimpl_get_description())
267     _diff_conf(cfg, q)
268     try:
269         delete_session('config', '29090931')
270     except ConfigError:
271         pass
272
273
274 def test_state_config2():
275     a = IPOption('a', '')
276     b = NetmaskOption('b', '')
277     dod1 = OptionDescription('dod1', '', [a, b])
278     b.impl_add_consistency('ip_netmask', a)
279     od1 = OptionDescription('od1', '', [dod1])
280     st1 = StrOption('st1', "", multi=True)
281     st2 = StrOption('st2', "", multi=True)
282     st3 = StrOption('st3', "", multi=True, callback=return_value, callback_params={'': ((st2, False),)})
283     stm = OptionDescription('st1', '', [st1, st2, st3])
284     stm.impl_set_group_type(groups.master)
285     st = OptionDescription('st', '', [stm])
286     od = OptionDescription('od', '', [st])
287     od2 = OptionDescription('od', '', [od, od1])
288     try:
289         cfg = Config(od2, persistent=True, session_id='29090939')
290     except ValueError:
291         cfg = Config(od2, session_id='29090939')
292         cfg._impl_test = True
293     a = dumps(cfg)
294     q = loads(a)
295     _diff_opts(cfg.cfgimpl_get_description(), q.cfgimpl_get_description())
296     _diff_conf(cfg, q)
297     try:
298         delete_session('config', '29090939')
299     except ConfigError:
300         pass
301
302
303 def test_state_properties():
304     val1 = BoolOption('val1', "")
305     maconfig = OptionDescription('rootconfig', '', [val1])
306     try:
307         cfg = Config(maconfig, persistent=True, session_id='29090932')
308     except ValueError:
309         cfg = Config(maconfig, session_id='29090932')
310         cfg._impl_test = True
311     cfg.read_write()
312     cfg.cfgimpl_get_settings()[val1].append('test')
313     a = dumps(cfg)
314     q = loads(a)
315     _diff_conf(cfg, q)
316     try:
317         delete_session('config', '29090932')
318     except ConfigError:
319         pass
320
321
322 def test_state_values():
323     val1 = BoolOption('val1', "")
324     maconfig = OptionDescription('rootconfig', '', [val1])
325     try:
326         cfg = Config(maconfig, persistent=True, session_id='29090933')
327     except ValueError:
328         cfg = Config(maconfig, session_id='29090933')
329         cfg._impl_test = True
330     cfg.val1 = True
331     a = dumps(cfg)
332     q = loads(a)
333     _diff_conf(cfg, q)
334     q.val1 = False
335     assert cfg.val1 is True
336     assert q.val1 is False
337     try:
338         delete_session('config', '29090933')
339     except ConfigError:
340         pass
341
342
343 def test_state_values_owner():
344     val1 = BoolOption('val1', "")
345     maconfig = OptionDescription('rootconfig', '', [val1])
346     try:
347         cfg = Config(maconfig, persistent=True, session_id='29090934')
348     except ValueError:
349         cfg = Config(maconfig, session_id='29090934')
350         cfg._impl_test = True
351     owners.addowner('newowner')
352     cfg.cfgimpl_get_settings().setowner(owners.newowner)
353     cfg.val1 = True
354     a = dumps(cfg)
355     q = loads(a)
356     _diff_conf(cfg, q)
357     q.val1 = False
358     nval1 = q.cfgimpl_get_description().val1
359     assert q.getowner(nval1) == owners.newowner
360     try:
361         delete_session('config', '29090934')
362     except ConfigError:
363         pass
364
365
366 def test_state_metaconfig():
367     i1 = IntOption('i1', '')
368     od1 = OptionDescription('od1', '', [i1])
369     od2 = OptionDescription('od2', '', [od1])
370     conf1 = Config(od2, session_id='29090935')
371     conf1._impl_test = True
372     conf2 = Config(od2, session_id='29090936')
373     conf2._impl_test = True
374     meta = MetaConfig([conf1, conf2], session_id='29090937')
375     meta._impl_test = True
376     raises(ConfigError, "dumps(meta)")
377     try:
378         delete_session('config', '29090935')
379         delete_session('config', '29090936')
380         delete_session('config', '29090937')
381     except ConfigError:
382         pass
383
384
385 def test_state_groupconfig():
386     i1 = IntOption('i1', '')
387     od1 = OptionDescription('od1', '', [i1])
388     od2 = OptionDescription('od2', '', [od1])
389     conf1 = Config(od2, session_id='29090935')
390     conf1._impl_test = True
391     conf2 = Config(od2, session_id='29090936')
392     conf2._impl_test = True
393     meta = GroupConfig([conf1, conf2], session_id='29090937')
394     meta._impl_test = True
395     a = dumps(meta)
396     q = loads(a)
397     _diff_conf(meta, q)
398     try:
399         delete_session('config', '29090935')
400         delete_session('config', '29090936')
401         delete_session('config', '29090937')
402     except ConfigError:
403         pass
404
405
406 def test_state_unkown_setting_owner():
407     """load an unknow _owner, should create it"""
408     assert not 'supernewuser' in owners.__dict__
409     loads("""ccopy_reg
410 _reconstructor
411 p0
412 (ctiramisu.setting
413 Settings
414 p1
415 c__builtin__
416 object
417 p2
418 Ntp3
419 Rp4
420 (dp5
421 S'_owner'
422 p6
423 S'supernewuser'
424 p7
425 sS'_p_'
426 p8
427 g0
428 (ctiramisu.storage.dictionary.setting
429 Settings
430 p9
431 g2
432 Ntp10
433 Rp11
434 (dp12
435 S'_cache'
436 p13
437 (dp14
438 sS'_permissives'
439 p15
440 (dp16
441 sS'_properties'
442 p17
443 (dp18
444 sbsb.
445 .""")
446     assert 'supernewuser' in owners.__dict__