consistency is now check not_equal if one option has PropertiesOptionError
[tiramisu.git] / test / test_requires.py
1 # coding: utf-8
2 from autopath import do_autopath
3 do_autopath()
4
5 from copy import copy
6 from tiramisu.setting import groups
7 from tiramisu import setting
8 setting.expires_time = 1
9 from tiramisu.option import IPOption, OptionDescription, BoolOption, IntOption, StrOption
10 from tiramisu.config import Config
11 from tiramisu.error import PropertiesOptionError, RequirementError
12 from py.test import raises
13
14
15 def test_requires():
16     a = BoolOption('activate_service', '', True)
17     b = IPOption('ip_address_service', '',
18                  requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
19     od = OptionDescription('service', '', [a, b])
20     c = Config(od)
21     c.read_write()
22     c.ip_address_service
23     c.activate_service = False
24     props = []
25     try:
26         c.ip_address_service
27     except PropertiesOptionError as err:
28         props = err.proptype
29     assert props == ['disabled']
30     c.activate_service = True
31     c.ip_address_service
32
33
34 def test_requires_with_requires():
35     a = BoolOption('activate_service', '', True)
36     b = IPOption('ip_address_service', '',
37                  requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
38     od = OptionDescription('service', '', [a, b])
39     c = Config(od)
40     c.read_write()
41     c.cfgimpl_get_settings()[b].append('test')
42     c.ip_address_service
43     c.activate_service = False
44     props = []
45     try:
46         c.ip_address_service
47     except PropertiesOptionError as err:
48         props = err.proptype
49     assert props == ['disabled']
50     c.activate_service = True
51     c.ip_address_service
52
53
54 def test_requires_invalid():
55     a = BoolOption('activate_service', '', True)
56     a
57     raises(ValueError, "IPOption('ip_address_service', '', requires='string')")
58     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'unknown': True}])")
59     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False}])")
60     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'action': 'disabled'}])")
61     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'expected': False, 'action': 'disabled'}])")
62     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'inverse': 'string'}])")
63     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'transitive': 'string'}])")
64     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'same_action': 'string'}])")
65     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': 'string', 'expected': False, 'action': 'disabled'}])")
66     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': 'string', 'action': 'disabled'}])")
67
68
69 def test_requires_same_action():
70     a = BoolOption('activate_service', '', True)
71     b = BoolOption('activate_service_web', '', True,
72                    requires=[{'option': a, 'expected': False, 'action': 'new'}])
73
74     d = IPOption('ip_address_service_web', '',
75                  requires=[{'option': b, 'expected': False,
76                             'action': 'disabled', 'inverse': False,
77                             'transitive': True, 'same_action': False}])
78     od = OptionDescription('service', '', [a, b, d])
79     c = Config(od)
80     c.read_write()
81     c.cfgimpl_get_settings().append('new')
82     c.activate_service
83     c.activate_service_web
84     c.ip_address_service_web
85     c.activate_service = False
86     #
87     props = []
88     try:
89         c.activate_service_web
90     except PropertiesOptionError as err:
91         props = err.proptype
92     assert props == ['new']
93     #
94     props = []
95     try:
96         c.ip_address_service_web
97     except PropertiesOptionError as err:
98         props = err.proptype
99     assert props == ['disabled']
100
101
102 def test_multiple_requires():
103     a = StrOption('activate_service', '')
104     b = IPOption('ip_address_service', '',
105                  requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'},
106                            {'option': a, 'expected': 'ok', 'action': 'disabled'}])
107     od = OptionDescription('service', '', [a, b])
108     c = Config(od)
109     c.read_write()
110     c.ip_address_service
111     c.activate_service = 'yes'
112     props = []
113     try:
114         c.ip_address_service
115     except PropertiesOptionError as err:
116         props = err.proptype
117     assert props == ['disabled']
118
119     c.activate_service = 'ok'
120     props = []
121     try:
122         c.ip_address_service
123     except PropertiesOptionError as err:
124         props = err.proptype
125     assert props == ['disabled']
126
127     c.activate_service = 'no'
128     c.ip_address_service
129
130
131 def test_multiple_requires_cumulative():
132     a = StrOption('activate_service', '')
133     b = IPOption('ip_address_service', '',
134                  requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'},
135                            {'option': a, 'expected': 'yes', 'action': 'hidden'}])
136     od = OptionDescription('service', '', [a, b])
137     c = Config(od)
138     c.read_write()
139     c.ip_address_service
140     c.activate_service = 'yes'
141     props = []
142     try:
143         c.ip_address_service
144     except PropertiesOptionError as err:
145         props = err.proptype
146     assert set(props) == set(['hidden', 'disabled'])
147
148     c.activate_service = 'ok'
149     c.ip_address_service
150
151     c.activate_service = 'no'
152     c.ip_address_service
153
154
155 def test_multiple_requires_cumulative_inverse():
156     a = StrOption('activate_service', '')
157     b = IPOption('ip_address_service', '',
158                  requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True},
159                            {'option': a, 'expected': 'yes', 'action': 'hidden', 'inverse': True}])
160     od = OptionDescription('service', '', [a, b])
161     c = Config(od)
162     c.read_write()
163     props = []
164     try:
165         c.ip_address_service
166     except PropertiesOptionError as err:
167         props = err.proptype
168     assert set(props) == set(['hidden', 'disabled'])
169     c.activate_service = 'yes'
170     c.ip_address_service
171
172     c.activate_service = 'ok'
173     props = []
174     try:
175         c.ip_address_service
176     except PropertiesOptionError as err:
177         props = err.proptype
178     assert set(props) == set(['hidden', 'disabled'])
179
180     c.activate_service = 'no'
181     props = []
182     try:
183         c.ip_address_service
184     except PropertiesOptionError as err:
185         props = err.proptype
186     assert set(props) == set(['hidden', 'disabled'])
187
188
189 def test_multiple_requires_inverse():
190     a = StrOption('activate_service', '')
191     b = IPOption('ip_address_service', '',
192                  requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True},
193                            {'option': a, 'expected': 'ok', 'action': 'disabled', 'inverse': True}])
194     od = OptionDescription('service', '', [a, b])
195     c = Config(od)
196     c.read_write()
197     props = []
198     try:
199         c.ip_address_service
200     except PropertiesOptionError as err:
201         props = err.proptype
202     assert props == ['disabled']
203
204     c.activate_service = 'yes'
205     c.ip_address_service
206
207     c.activate_service = 'ok'
208     c.ip_address_service
209
210     c.activate_service = 'no'
211     props = []
212     try:
213         c.ip_address_service
214     except PropertiesOptionError as err:
215         props = err.proptype
216     assert props == ['disabled']
217
218
219 def test_requires_transitive():
220     a = BoolOption('activate_service', '', True)
221     b = BoolOption('activate_service_web', '', True,
222                    requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
223
224     d = IPOption('ip_address_service_web', '',
225                  requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
226     od = OptionDescription('service', '', [a, b, d])
227     c = Config(od)
228     c.read_write()
229     c.activate_service
230     c.activate_service_web
231     c.ip_address_service_web
232     c.activate_service = False
233     #
234     props = []
235     try:
236         c.activate_service_web
237     except PropertiesOptionError as err:
238         props = err.proptype
239     assert props == ['disabled']
240     #
241     props = []
242     try:
243         c.ip_address_service_web
244     except PropertiesOptionError as err:
245         props = err.proptype
246     assert props == ['disabled']
247
248
249 def test_requires_transitive_owner():
250     a = BoolOption('activate_service', '', True)
251     b = BoolOption('activate_service_web', '', True,
252                    requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
253
254     d = IPOption('ip_address_service_web', '',
255                  requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
256     od = OptionDescription('service', '', [a, b, d])
257     c = Config(od)
258     c.read_write()
259     c.activate_service
260     c.activate_service_web
261     c.ip_address_service_web
262     #no more default value
263     c.ip_address_service_web = '1.1.1.1'
264     c.activate_service = False
265     props = []
266     try:
267         c.ip_address_service_web
268     except PropertiesOptionError as err:
269         props = err.proptype
270     assert props == ['disabled']
271
272
273 def test_requires_transitive_bis():
274     a = BoolOption('activate_service', '', True)
275     abis = BoolOption('activate_service_bis', '', True)
276     b = BoolOption('activate_service_web', '', True,
277                    requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}])
278
279     d = IPOption('ip_address_service_web', '',
280                  requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}])
281     od = OptionDescription('service', '', [a, abis, b, d])
282     c = Config(od)
283     c.read_write()
284     #
285     c.activate_service_web
286     c.ip_address_service_web
287     c.activate_service = False
288     #
289     props = []
290     try:
291         c.activate_service_web
292     except PropertiesOptionError as err:
293         props = err.proptype
294     assert props == ['disabled']
295     #
296     props = []
297     try:
298         c.ip_address_service_web
299     except PropertiesOptionError as err:
300         props = err.proptype
301     assert props == ['disabled']
302
303
304 def test_requires_transitive_hidden_disabled():
305     a = BoolOption('activate_service', '', True)
306     b = BoolOption('activate_service_web', '', True,
307                    requires=[{'option': a, 'expected': False, 'action': 'hidden'}])
308     d = IPOption('ip_address_service_web', '',
309                  requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
310     od = OptionDescription('service', '', [a, b, d])
311     c = Config(od)
312     c.read_write()
313     c.activate_service
314     c.activate_service_web
315     c.ip_address_service_web
316     c.activate_service = False
317     #
318     props = []
319     try:
320         c.activate_service_web
321     except PropertiesOptionError as err:
322         props = err.proptype
323     assert props == ['hidden']
324     raises(RequirementError, 'c.ip_address_service_web')
325
326
327 def test_requires_not_transitive():
328     a = BoolOption('activate_service', '', True)
329     b = BoolOption('activate_service_web', '', True,
330                    requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
331     d = IPOption('ip_address_service_web', '',
332                  requires=[{'option': b, 'expected': False,
333                             'action': 'disabled', 'transitive': False}])
334     od = OptionDescription('service', '', [a, b, d])
335     c = Config(od)
336     c.read_write()
337     c.activate_service
338     c.activate_service_web
339     c.ip_address_service_web
340     c.activate_service = False
341     #
342     props = []
343     try:
344         c.activate_service_web
345     except PropertiesOptionError as err:
346         props = err.proptype
347     assert props == ['disabled']
348     #
349     c.ip_address_service_web
350
351
352 def test_requires_None():
353     a = BoolOption('activate_service', '')
354     b = IPOption('ip_address_service', '',
355                  requires=[{'option': a, 'expected': None, 'action': 'disabled'}])
356     od = OptionDescription('service', '', [a, b])
357     c = Config(od)
358     c.read_write()
359     props = []
360     try:
361         c.ip_address_service
362     except PropertiesOptionError as err:
363         props = err.proptype
364     assert props == ['disabled']
365     c.activate_service = False
366     c.ip_address_service
367
368
369 def test_requires_multi_disabled():
370     a = BoolOption('activate_service', '')
371     b = IntOption('num_service', '')
372     c = IPOption('ip_address_service', '',
373                  requires=[{'option': a, 'expected': True, 'action': 'disabled'},
374                            {'option': b, 'expected': 1, 'action': 'disabled'}])
375     od = OptionDescription('service', '', [a, b, c])
376     c = Config(od)
377     c.read_write()
378
379     c.ip_address_service
380
381     c.activate_service = True
382     props = []
383     try:
384         c.ip_address_service
385     except PropertiesOptionError as err:
386         props = err.proptype
387     assert props == ['disabled']
388
389     c.activate_service = False
390     c.ip_address_service
391
392     c.num_service = 1
393     props = []
394     try:
395         c.ip_address_service
396     except PropertiesOptionError as err:
397         props = err.proptype
398     assert props == ['disabled']
399
400     c.activate_service = True
401     props = []
402     try:
403         c.ip_address_service
404     except PropertiesOptionError as err:
405         props = err.proptype
406     assert props == ['disabled']
407
408
409 def test_requires_multi_disabled_inverse():
410     a = BoolOption('activate_service', '')
411     b = IntOption('num_service', '')
412     c = IPOption('ip_address_service', '',
413                  requires=[{'option': a, 'expected': True,
414                             'action': 'disabled', 'inverse': True},
415                            {'option': b, 'expected': 1,
416                             'action': 'disabled', 'inverse': True}])
417     od = OptionDescription('service', '', [a, b, c])
418     c = Config(od)
419     c.read_write()
420
421     props = []
422     try:
423         c.ip_address_service
424     except PropertiesOptionError as err:
425         props = err.proptype
426     assert props == ['disabled']
427
428     c.activate_service = True
429     props = []
430     try:
431         c.ip_address_service
432     except PropertiesOptionError as err:
433         props = err.proptype
434     assert props == ['disabled']
435
436     c.activate_service = False
437     props = []
438     try:
439         c.ip_address_service
440     except PropertiesOptionError as err:
441         props = err.proptype
442     assert props == ['disabled']
443
444     c.num_service = 1
445     props = []
446     try:
447         c.ip_address_service
448     except PropertiesOptionError as err:
449         props = err.proptype
450     assert props == ['disabled']
451
452     c.activate_service = True
453     c.ip_address_service
454
455
456 def test_requires_multi_disabled_2():
457     a = BoolOption('a', '')
458     b = BoolOption('b', '')
459     c = BoolOption('c', '')
460     d = BoolOption('d', '')
461     e = BoolOption('e', '')
462     f = BoolOption('f', '')
463     g = BoolOption('g', '')
464     h = BoolOption('h', '')
465     i = BoolOption('i', '')
466     j = BoolOption('j', '')
467     k = BoolOption('k', '')
468     l = BoolOption('l', '')
469     m = BoolOption('m', '')
470     list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m]
471     requires = []
472     for boo in list_bools:
473         requires.append({'option': boo, 'expected': True, 'action': 'disabled'})
474     z = IPOption('z', '', requires=requires)
475     y = copy(list_bools)
476     y.append(z)
477     od = OptionDescription('service', '', y)
478     cfg = Config(od)
479     cfg.read_write()
480
481     cfg.z
482     for boo in list_bools:
483         setattr(cfg, boo._name, True)
484         props = []
485         try:
486             cfg.z
487         except PropertiesOptionError as err:
488             props = err.proptype
489         assert props == ['disabled']
490     for boo in list_bools:
491         setattr(cfg, boo._name, False)
492         if boo == m:
493             cfg.z
494         else:
495             props = []
496             try:
497                 cfg.z
498             except PropertiesOptionError as err:
499                 props = err.proptype
500             assert props == ['disabled']
501
502
503 def test_requires_multi_disabled_inverse_2():
504     a = BoolOption('a', '')
505     b = BoolOption('b', '')
506     c = BoolOption('c', '')
507     d = BoolOption('d', '')
508     e = BoolOption('e', '')
509     f = BoolOption('f', '')
510     g = BoolOption('g', '')
511     h = BoolOption('h', '')
512     i = BoolOption('i', '')
513     j = BoolOption('j', '')
514     k = BoolOption('k', '')
515     l = BoolOption('l', '')
516     m = BoolOption('m', '')
517     list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m]
518     requires = []
519     for boo in list_bools:
520         requires.append({'option': boo, 'expected': True, 'action': 'disabled',
521                          'inverse': True})
522     z = IPOption('z', '', requires=requires)
523     y = copy(list_bools)
524     y.append(z)
525     od = OptionDescription('service', '', y)
526     cfg = Config(od)
527     cfg.read_write()
528
529     props = []
530     try:
531         cfg.z
532     except PropertiesOptionError as err:
533         props = err.proptype
534     assert props == ['disabled']
535     for boo in list_bools:
536         setattr(cfg, boo._name, True)
537         if boo == m:
538             cfg.z
539         else:
540             props = []
541             try:
542                 cfg.z
543             except PropertiesOptionError as err:
544                 props = err.proptype
545             assert props == ['disabled']
546     for boo in list_bools:
547         setattr(cfg, boo._name, False)
548         props = []
549         try:
550             cfg.z
551         except PropertiesOptionError as err:
552             props = err.proptype
553         assert props == ['disabled']
554
555
556 def test_requires_requirement_append():
557     a = BoolOption('activate_service', '', True)
558     b = IPOption('ip_address_service', '',
559                  requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
560     od = OptionDescription('service', '', [a, b])
561     c = Config(od)
562     c.read_write()
563     str(c.cfgimpl_get_settings())
564     str(c.cfgimpl_get_settings()[b])
565     raises(ValueError, 'c.cfgimpl_get_settings()[b].append("disabled")')
566     c.activate_service = False
567     # disabled is now set, test to remove disabled before store in storage
568     c.cfgimpl_get_settings()[b].append("test")
569
570
571 def test_requires_different_inverse():
572     a = BoolOption('activate_service', '', True)
573     a
574     raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}])")
575
576
577 def test_requires_recursive_path():
578     a = BoolOption('activate_service', '', True)
579     b = IPOption('ip_address_service', '',
580                  requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
581     od1 = OptionDescription('service', '', [a, b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
582     od = OptionDescription('base', '', [od1])
583     c = Config(od)
584     c.read_write()
585     raises(RequirementError, 'c.service.a')
586
587
588 def test_get_properties_with_None_path():
589     a = BoolOption('activate_service', '', True)
590     b = IPOption('ip_address_service', '',
591                  requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
592     od1 = OptionDescription('service', '', [a, b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
593     od = OptionDescription('base', '', [od1])
594     c = Config(od)
595     c.read_write()
596     raises(ValueError, "c.cfgimpl_get_settings()._getproperties(a)")
597
598
599 def test_set_item():
600     a = BoolOption('activate_service', '', True)
601     b = IPOption('ip_address_service', '')
602     od1 = OptionDescription('service', '', [a, b])
603     od = OptionDescription('base', '', [od1])
604     c = Config(od)
605     c.read_write()
606     raises(ValueError, 'c.cfgimpl_get_settings()[a] = ("test",)')
607
608
609 def test_optiondescription_requires():
610     a = BoolOption('activate_service', '', True)
611     b = BoolOption('ip_address_service', '', multi=True)
612     a, b
613     OptionDescription('service', '', [b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
614
615
616 def test_optiondescription_requires_multi():
617     a = BoolOption('activate_service', '', True)
618     b = IPOption('ip_address_service', '', multi=True)
619     a, b
620     raises(ValueError, "OptionDescription('service', '', [a], requires=[{'option': b, 'expected': False, 'action': 'disabled'}])")
621
622
623 def test_properties_conflict():
624     a = BoolOption('activate_service', '', True)
625     a
626     raises(ValueError, "IPOption('ip_address_service', '', properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])")
627     raises(ValueError, "od1 = OptionDescription('service', '', [a], properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])")
628
629
630 def test_master_slave_requires():
631     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
632     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True,
633                                    requires=[{'option': ip_admin_eth0, 'expected': '192.168.1.1', 'action': 'disabled'}])
634     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
635     interface1.impl_set_group_type(groups.master)
636     maconfig = OptionDescription('toto', '', [interface1])
637     cfg = Config(maconfig)
638     cfg.read_write()
639     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
640     assert cfg.ip_admin_eth0.ip_admin_eth0 == []
641     cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.1.2')
642     assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
643     assert cfg.ip_admin_eth0.ip_admin_eth0 == ['192.168.1.2']
644     cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.1.1')
645     assert cfg.ip_admin_eth0.netmask_admin_eth0[0] is None
646     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[1]")
647     cfg.ip_admin_eth0.ip_admin_eth0[1] = '192.168.1.2'
648     assert cfg.ip_admin_eth0.netmask_admin_eth0[1] is None
649     cfg.ip_admin_eth0.netmask_admin_eth0[1] = '255.255.255.255'
650     assert cfg.ip_admin_eth0.netmask_admin_eth0[1] == '255.255.255.255'
651     cfg.ip_admin_eth0.ip_admin_eth0[1] = '192.168.1.1'
652     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[1]")
653
654
655 def test_master_slave_requires_no_master():
656     activate = BoolOption('activate', "Activer l'accès au réseau", True)
657     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
658     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True,
659                                    requires=[{'option': activate, 'expected': False, 'action': 'disabled'}])
660     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
661     interface1.impl_set_group_type(groups.master)
662     maconfig = OptionDescription('toto', '', [activate, interface1])
663     cfg = Config(maconfig)
664     cfg.read_write()
665     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
666     assert cfg.ip_admin_eth0.ip_admin_eth0 == []
667     cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.1.2')
668     assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
669     assert cfg.ip_admin_eth0.netmask_admin_eth0[0] is None
670     assert cfg.ip_admin_eth0.ip_admin_eth0 == ['192.168.1.2']
671     cfg.activate = False
672     cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.1.1')
673     assert cfg.ip_admin_eth0.ip_admin_eth0 == ['192.168.1.2', '192.168.1.1']
674     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0")
675     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[0]")
676     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[1]")
677     cfg.activate = True
678     assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None, None]
679     cfg.ip_admin_eth0.netmask_admin_eth0 = [None, '255.255.255.255']
680     assert cfg.ip_admin_eth0.netmask_admin_eth0[1] == '255.255.255.255'
681     cfg.activate = False
682     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0")
683     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[0]")
684     raises(PropertiesOptionError, "cfg.ip_admin_eth0.netmask_admin_eth0[1]")