Merge branch 'master' into orm
[tiramisu.git] / test / test_parsing_group.py
1 # coding: utf-8
2 import autopath
3 from tiramisu.setting import groups, owners
4 from tiramisu.config import Config
5 from tiramisu.option import ChoiceOption, BoolOption, IntOption, \
6     StrOption, OptionDescription
7 from tiramisu.error import SlaveError
8
9 from py.test import raises
10
11
12 def make_description():
13     numero_etab = StrOption('numero_etab', "identifiant de l'établissement")
14     nom_machine = StrOption('nom_machine', "nom de la machine", default="eoleng")
15     nombre_interfaces = IntOption('nombre_interfaces', "nombre d'interfaces à activer",
16                                   default=1)
17     activer_proxy_client = BoolOption('activer_proxy_client', "utiliser un proxy",
18                                       default=False)
19     mode_conteneur_actif = BoolOption('mode_conteneur_actif', "le serveur est en mode conteneur",
20                                       default=False)
21     adresse_serveur_ntp = StrOption('serveur_ntp', "adresse serveur ntp", multi=True)
22     time_zone = ChoiceOption('time_zone', 'fuseau horaire du serveur',
23                              ('Paris', 'Londres'), 'Paris')
24
25     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé")
26     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
27
28     master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
29     interface1 = OptionDescription('interface1', '', [master])
30     interface1.impl_set_group_type(groups.family)
31
32     general = OptionDescription('general', '', [numero_etab, nom_machine,
33                                 nombre_interfaces, activer_proxy_client,
34                                 mode_conteneur_actif, adresse_serveur_ntp,
35                                 time_zone])
36     general.impl_set_group_type(groups.family)
37     creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
38     descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole])
39     return descr
40
41
42 def test_base_config():
43     descr = make_description()
44     config = Config(descr)
45     config.read_write()
46     assert config.creole.general.activer_proxy_client is False
47     assert config.creole.general.nom_machine == "eoleng"
48     assert config.find_first(byname='nom_machine', type_='value') == "eoleng"
49     result = {'general.numero_etab': None, 'general.nombre_interfaces': 1,
50               'general.serveur_ntp': [], 'interface1.ip_admin_eth0.ip_admin_eth0': None,
51               'general.mode_conteneur_actif': False, 'general.time_zone': 'Paris',
52               'interface1.ip_admin_eth0.netmask_admin_eth0': None, 'general.nom_machine':
53               'eoleng', 'general.activer_proxy_client': False}
54     assert config.creole.make_dict() == result
55     result = {'serveur_ntp': [], 'mode_conteneur_actif': False,
56               'ip_admin_eth0': None, 'time_zone': 'Paris', 'numero_etab': None,
57               'netmask_admin_eth0': None, 'nom_machine': 'eoleng', 'activer_proxy_client':
58               False, 'nombre_interfaces': 1}
59     assert config.creole.make_dict(flatten=True) == result
60
61
62 def test_make_dict_filter():
63     descr = make_description()
64     config = Config(descr)
65     config.read_write()
66     subresult = {'numero_etab': None, 'nombre_interfaces': 1,
67                  'serveur_ntp': [], 'mode_conteneur_actif': False,
68                  'time_zone': 'Paris', 'nom_machine': 'eoleng',
69                  'activer_proxy_client': False}
70     result = {}
71     for key, value in subresult.items():
72         result['general.' + key] = value
73     assert config.creole.make_dict(withoption='numero_etab') == result
74     raises(AttributeError, "config.creole.make_dict(withoption='numero_etab', withvalue='toto')")
75     assert config.creole.make_dict(withoption='numero_etab', withvalue=None) == result
76     assert config.creole.general.make_dict(withoption='numero_etab') == subresult
77
78
79 def test_get_group_type():
80     descr = make_description()
81     config = Config(descr)
82     config.read_write()
83     grp = config.unwrap_from_path('creole.general')
84     assert grp.impl_get_group_type() == groups.family
85     assert grp.impl_get_group_type() == 'family'
86     assert isinstance(grp.impl_get_group_type(), groups.GroupType)
87     raises(TypeError, 'grp.impl_set_group_type(groups.default)')
88
89
90 def test_iter_on_groups():
91     descr = make_description()
92     config = Config(descr)
93     config.read_write()
94     result = list(config.creole.iter_groups(group_type=groups.family))
95     group_names = [res[0] for res in result]
96     #FIXME pourquoi inversé ??
97     #assert group_names == ['general', 'interface1']
98     assert group_names == ['interface1', 'general']
99     for i in config.creole.iter_groups(group_type=groups.family):
100         #test StopIteration
101         break
102
103
104 def test_iter_on_groups_props():
105     descr = make_description()
106     config = Config(descr)
107     config.read_write()
108     config.cfgimpl_get_settings()[descr.creole.interface1].append('disabled')
109     result = list(config.creole.iter_groups(group_type=groups.family))
110     group_names = [res[0] for res in result]
111     assert group_names == ['general']
112
113
114 def test_iter_on_empty_group():
115     config = Config(OptionDescription("name", "descr", []))
116     config.read_write()
117     result = list(config.iter_groups())
118     assert result == []
119     for i in config.iter_groups():
120         pass
121     for i in config:
122         pass
123     assert [] == list(config)
124
125
126 def test_iter_not_group():
127     config = Config(OptionDescription("name", "descr", []))
128     config.read_write()
129     raises(TypeError, "list(config.iter_groups(group_type='family'))")
130
131
132 def test_groups_with_master():
133     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
134     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
135     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
136     interface1.impl_set_group_type(groups.master)
137     assert interface1.impl_get_group_type() == groups.master
138
139
140 def test_groups_with_master_in_config():
141     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
142     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
143     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
144     interface1.impl_set_group_type(groups.master)
145     Config(interface1)
146     assert interface1.impl_get_group_type() == groups.master
147
148
149 def test_allowed_groups():
150     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
151     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
152     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
153     raises(ValueError, "interface1.impl_set_group_type('toto')")
154
155
156 def test_master_not_valid_name():
157     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
158     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
159     invalid_group = OptionDescription('interface1', '', [ip_admin_eth0, netmask_admin_eth0])
160     raises(ValueError, "invalid_group.impl_set_group_type(groups.master)")
161
162
163 def test_sub_group_in_master_group():
164     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
165     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
166     subgroup = OptionDescription("subgroup", '', [])
167     invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
168     raises(ValueError, "invalid_group.impl_set_group_type(groups.master)")
169
170
171 def test_group_always_has_multis():
172     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
173     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
174     group = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
175     raises(ValueError, "group.impl_set_group_type(groups.master)")
176
177
178 #____________________________________________________________
179 def test_values_with_master_and_slaves():
180     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
181     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
182     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
183     interface1.impl_set_group_type(groups.master)
184     maconfig = OptionDescription('toto', '', [interface1])
185     cfg = Config(maconfig)
186     cfg.read_write()
187     owner = cfg.cfgimpl_get_settings().getowner()
188     assert interface1.impl_get_group_type() == groups.master
189     assert cfg.getowner(ip_admin_eth0) == owners.default
190     assert cfg.getowner(netmask_admin_eth0) == owners.default
191     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
192     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
193     assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
194     assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
195     assert cfg.getowner(ip_admin_eth0) == owner
196     assert cfg.getowner(netmask_admin_eth0) == owners.default
197     cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.147"]
198     raises(SlaveError, 'cfg.ip_admin_eth0.netmask_admin_eth0.append(None)')
199     raises(SlaveError, 'cfg.ip_admin_eth0.netmask_admin_eth0.pop(0)')
200
201
202 def test_reset_values_with_master_and_slaves():
203     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
204     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
205     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
206     interface1.impl_set_group_type(groups.master)
207     maconfig = OptionDescription('toto', '', [interface1])
208     cfg = Config(maconfig)
209     cfg.read_write()
210     owner = cfg.cfgimpl_get_settings().getowner()
211     assert interface1.impl_get_group_type() == groups.master
212     assert cfg.getowner(ip_admin_eth0) == owners.default
213     assert cfg.getowner(netmask_admin_eth0) == owners.default
214     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
215     assert cfg.getowner(ip_admin_eth0) == owner
216     assert cfg.getowner(netmask_admin_eth0) == owners.default
217     del(cfg.ip_admin_eth0.ip_admin_eth0)
218     assert cfg.getowner(ip_admin_eth0) == owners.default
219     assert cfg.getowner(netmask_admin_eth0) == owners.default
220     assert cfg.ip_admin_eth0.ip_admin_eth0 == []
221     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
222
223
224 def test_values_with_master_and_slaves_slave():
225     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
226     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
227     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
228     interface1.impl_set_group_type(groups.master)
229     maconfig = OptionDescription('toto', '', [interface1])
230     cfg = Config(maconfig)
231     cfg.read_write()
232     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
233     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']")
234     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
235     cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']
236     cfg.ip_admin_eth0.netmask_admin_eth0[0] = '255.255.255.0'
237     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']")
238     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = []")
239     del(cfg.ip_admin_eth0.netmask_admin_eth0)
240     cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']
241     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
242     assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0', None]
243     cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
244     raises(SlaveError, 'cfg.ip_admin_eth0.netmask_admin_eth0.pop(1)')
245
246
247 def test_values_with_master_and_slaves_master():
248     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
249     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
250     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
251     interface1.impl_set_group_type(groups.master)
252     maconfig = OptionDescription('toto', '', [interface1])
253     cfg = Config(maconfig)
254     cfg.read_write()
255     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
256     cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]
257     cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.145"]
258     cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
259     raises(SlaveError, 'cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145"]')
260     assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0', '255.255.255.0']
261     cfg.ip_admin_eth0.ip_admin_eth0.pop(1)
262     assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"]
263     assert cfg.ip_admin_eth0.netmask_admin_eth0 == ['255.255.255.0']
264     del(cfg.ip_admin_eth0.ip_admin_eth0)
265     assert cfg.ip_admin_eth0.ip_admin_eth0 == []
266     assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
267
268
269 def test_values_with_master_and_slaves_master_error():
270     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
271     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
272     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
273     interface1.impl_set_group_type(groups.master)
274     maconfig = OptionDescription('toto', '', [interface1])
275     cfg = Config(maconfig)
276     cfg.read_write()
277     cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.145"]
278     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']")
279     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0', '255.255.255.0']")
280     cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0']
281     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0']")
282     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0 = ['255.255.255.0', '255.255.255.0', '255.255.255.0']")
283
284
285 def test_values_with_master_owner():
286     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
287     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
288     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
289     interface1.impl_set_group_type(groups.master)
290     maconfig = OptionDescription('toto', '', [interface1])
291     cfg = Config(maconfig)
292     cfg.read_write()
293     owner = cfg.cfgimpl_get_settings().getowner()
294     assert cfg.getowner(ip_admin_eth0) == owners.default
295     assert cfg.getowner(netmask_admin_eth0) == owners.default
296     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
297     assert cfg.getowner(ip_admin_eth0) == owner
298     assert cfg.getowner(netmask_admin_eth0) == owners.default
299     cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
300     assert cfg.getowner(ip_admin_eth0) == owner
301     assert cfg.getowner(netmask_admin_eth0) == owners.default
302
303
304 def test_values_with_master_disabled():
305     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
306     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
307     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
308     interface1.impl_set_group_type(groups.master)
309     maconfig = OptionDescription('toto', '', [interface1])
310     cfg = Config(maconfig)
311     cfg.read_write()
312     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
313     cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
314     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
315     cfg.ip_admin_eth0.netmask_admin_eth0 = ["192.168.230.145"]
316     cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
317     del(cfg.ip_admin_eth0.netmask_admin_eth0)
318     cfg.cfgimpl_get_settings()[netmask_admin_eth0].append('disabled')
319     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
320     cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
321
322     #delete with value in disabled var
323     cfg.cfgimpl_get_settings()[netmask_admin_eth0].remove('disabled')
324     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
325     cfg.ip_admin_eth0.netmask_admin_eth0 = ["192.168.230.145"]
326     cfg.cfgimpl_get_settings()[netmask_admin_eth0].append('disabled')
327     cfg.ip_admin_eth0.ip_admin_eth0.pop(0)
328
329     #append with value in disabled var
330     cfg.cfgimpl_get_settings()[netmask_admin_eth0].remove('disabled')
331     cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
332     cfg.ip_admin_eth0.netmask_admin_eth0 = ["192.168.230.145"]
333     cfg.cfgimpl_get_settings()[netmask_admin_eth0].append('disabled')
334     cfg.ip_admin_eth0.ip_admin_eth0.append('192.168.230.43')
335
336
337 def test_multi_insert():
338     var = StrOption('var', '', ['ok'], multi=True)
339     od = OptionDescription('od', '', [var])
340     c = Config(od)
341     c.read_write()
342     assert c.var == ['ok']
343     assert c.getowner(var) == owners.default
344     c.var.insert(0, 'nok')
345     assert c.var == ['nok', 'ok']
346     assert c.getowner(var) != owners.default
347
348
349 def test_multi_insert_master():
350     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
351     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
352     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
353     interface1.impl_set_group_type(groups.master)
354     maconfig = OptionDescription('toto', '', [interface1])
355     cfg = Config(maconfig)
356     cfg.read_write()
357     raises(SlaveError, "cfg.ip_admin_eth0.ip_admin_eth0.insert(0, 'nok')")
358     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0.insert(0, 'nok')")
359
360
361 def test_multi_sort():
362     var = StrOption('var', '', ['ok', 'nok'], multi=True)
363     od = OptionDescription('od', '', [var])
364     c = Config(od)
365     c.read_write()
366     assert c.var == ['ok', 'nok']
367     assert c.getowner(var) == owners.default
368     c.var.sort()
369     assert c.var == ['nok', 'ok']
370     assert c.getowner(var) != owners.default
371
372
373 def test_multi_sort_master():
374     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
375     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
376     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
377     interface1.impl_set_group_type(groups.master)
378     maconfig = OptionDescription('toto', '', [interface1])
379     cfg = Config(maconfig)
380     cfg.read_write()
381     raises(SlaveError, "cfg.ip_admin_eth0.ip_admin_eth0.sort()")
382     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0.sort()")
383
384
385 def test_multi_reverse():
386     var = StrOption('var', '', ['ok', 'nok'], multi=True)
387     od = OptionDescription('od', '', [var])
388     c = Config(od)
389     c.read_write()
390     assert c.var == ['ok', 'nok']
391     assert c.getowner(var) == owners.default
392     c.var.reverse()
393     assert c.var == ['nok', 'ok']
394     assert c.getowner(var) != owners.default
395
396
397 def test_multi_reverse_master():
398     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
399     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
400     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
401     interface1.impl_set_group_type(groups.master)
402     maconfig = OptionDescription('toto', '', [interface1])
403     cfg = Config(maconfig)
404     cfg.read_write()
405     raises(SlaveError, "cfg.ip_admin_eth0.ip_admin_eth0.reverse()")
406     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0.reverse()")
407
408
409 def test_multi_extend():
410     var = StrOption('var', '', ['ok', 'nok'], multi=True)
411     od = OptionDescription('od', '', [var])
412     c = Config(od)
413     c.read_write()
414     assert c.var == ['ok', 'nok']
415     assert c.getowner(var) == owners.default
416     c.var.extend(['pok'])
417     assert c.var == ['ok', 'nok', 'pok']
418     assert c.getowner(var) != owners.default
419
420
421 def test_multi_extend_master():
422     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
423     netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
424     interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
425     interface1.impl_set_group_type(groups.master)
426     maconfig = OptionDescription('toto', '', [interface1])
427     cfg = Config(maconfig)
428     cfg.read_write()
429     raises(SlaveError, "cfg.ip_admin_eth0.ip_admin_eth0.extend(['ok'])")
430     raises(SlaveError, "cfg.ip_admin_eth0.netmask_admin_eth0.extend(['ok'])")
431
432
433 def test_multi_non_valid_value():
434     ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
435     maconfig = OptionDescription('toto', '', [ip_admin_eth0])
436     cfg = Config(maconfig)
437     cfg.read_write()
438     cfg.ip_admin_eth0 = ['a']
439     raises(ValueError, 'cfg.ip_admin_eth0[0] = 1')