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