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