From cfb4db2559f02c0dbd881df0fc5d6a5200ab8356 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 29 Dec 2017 11:38:41 +0100 Subject: [PATCH] add requires test --- test/new_api/test_requires.py | 880 ++++++++++++++++++++++++++++++++++ tiramisu/api.py | 13 +- tiramisu/option/baseoption.py | 19 +- tiramisu/setting.py | 32 +- 4 files changed, 916 insertions(+), 28 deletions(-) create mode 100644 test/new_api/test_requires.py diff --git a/test/new_api/test_requires.py b/test/new_api/test_requires.py new file mode 100644 index 0000000..a16227b --- /dev/null +++ b/test/new_api/test_requires.py @@ -0,0 +1,880 @@ +# coding: utf-8 +from .autopath import do_autopath +do_autopath() + +from copy import copy +from tiramisu.setting import groups +from tiramisu import setting +setting.expires_time = 1 +from tiramisu import IPOption, OptionDescription, BoolOption, IntOption, StrOption, \ + MasterSlaves, Config, getapi +from tiramisu.error import PropertiesOptionError, RequirementError +from py.test import raises + + +def test_requires(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + api.option('ip_address_service').value.get() + api.option('activate_service').value.set(False) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + api.option('activate_service').value.set(True) + api.option('ip_address_service').value.get() + + +def test_requires_with_requires(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + api.option('ip_address_service').property.add('test') + api.option('ip_address_service').value.get() + api.option('activate_service').value.set(False) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + api.option('activate_service').value.set(True) + api.option('ip_address_service').value.get() + + +def test_requires_invalid(): + a = BoolOption('activate_service', '', True) + a + raises(ValueError, "IPOption('ip_address_service', '', requires='string')") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'unknown': True}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'action': 'disabled'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'expected': False, 'action': 'disabled'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'inverse': 'string'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'transitive': 'string'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'same_action': 'string'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': 'string', 'expected': False, 'action': 'disabled'}])") + raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': 'string', 'action': 'disabled'}])") + + +def test_requires_same_action(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'new'}]) + + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, + 'action': 'disabled', 'inverse': False, + 'transitive': True, 'same_action': False}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.property.add('new') + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['new']) + # + props = [] + try: + api.option('ip_address_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_multiple_requires(): + a = StrOption('activate_service', '') + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'}, + {'option': a, 'expected': 'ok', 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + api.option('ip_address_service').value.get() + api.option('activate_service').value.set('yes') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set('ok') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set('no') + api.option('ip_address_service').value.get() + + +def test_multiple_requires_cumulative(): + a = StrOption('activate_service', '') + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': 'yes', 'action': 'disabled'}, + {'option': a, 'expected': 'yes', 'action': 'hidden'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + api.option('ip_address_service').value.get() + api.option('activate_service').value.set('yes') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert set(props) == set(['hidden', 'disabled']) + + api.option('activate_service').value.set('ok') + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set('no') + api.option('ip_address_service').value.get() + + +def test_multiple_requires_cumulative_inverse(): + a = StrOption('activate_service', '') + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True}, + {'option': a, 'expected': 'yes', 'action': 'hidden', 'inverse': True}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert set(props) == set(['hidden', 'disabled']) + api.option('activate_service').value.set('yes') + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set('ok') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert set(props) == set(['hidden', 'disabled']) + + api.option('activate_service').value.set('no') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert set(props) == set(['hidden', 'disabled']) + + +def test_multiple_requires_inverse(): + a = StrOption('activate_service', '') + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': 'yes', 'action': 'disabled', 'inverse': True}, + {'option': a, 'expected': 'ok', 'action': 'disabled', 'inverse': True}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set('yes') + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set('ok') + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set('no') + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_transitive(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + # + props = [] + try: + api.option('ip_address_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_transitive_owner(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + #no more default value + api.option('ip_address_service_web').value.set('1.1.1.1') + api.option('activate_service').value.set(False) + props = [] + try: + api.option('ip_address_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_transitive_bis(): + a = BoolOption('activate_service', '', True) + abis = BoolOption('activate_service_bis', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}]) + + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': True, 'action': 'disabled', 'inverse': True}]) + od = OptionDescription('service', '', [a, abis, b, d]) + api = getapi(Config(od)) + api.property.read_write() + # + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + # + props = [] + try: + api.option('ip_address_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_transitive_hidden_disabled(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'hidden'}]) + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['hidden']) + raises(RequirementError, "api.option('ip_address_service_web').value.get()") + + +def test_requires_transitive_hidden_disabled_multiple(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'hidden'}, + {'option': a, 'expected': False, 'action': 'disabled'}]) + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, 'action': 'mandatory'}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert set(props) == {'disabled', 'hidden'} + raises(RequirementError, "api.option('ip_address_service_web').value.get()") + + +def test_requires_not_transitive(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, + 'action': 'disabled', 'transitive': False}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + # + api.option('ip_address_service_web').value.get() + + +def test_requires_not_transitive_not_same_action(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, + 'action': 'hidden', 'transitive': False}]) + od = OptionDescription('service', '', [a, b, d]) + api = getapi(Config(od)) + api.property.read_write() + api.option('activate_service').value.get() + api.option('activate_service_web').value.get() + api.option('ip_address_service_web').value.get() + api.option('activate_service').value.set(False) + # + props = [] + try: + api.option('activate_service_web').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + # + raises(RequirementError, "api.option('ip_address_service_web').value.get()") + + +def test_requires_None(): + a = BoolOption('activate_service', '') + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': None, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + api.option('activate_service').value.set(False) + api.option('ip_address_service').value.get() + + +def test_requires_multi_disabled(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + c = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': True, 'action': 'disabled'}, + {'option': b, 'expected': 1, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, c]) + api = getapi(Config(od)) + api.property.read_write() + + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(False) + api.option('ip_address_service').value.get() + + api.option('num_service').value.set(1) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_multi_disabled_new_format(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + c = IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value': True}, {'option': b, 'value': 1}], 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, c]) + api = getapi(Config(od)) + api.property.read_write() + + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(False) + api.option('ip_address_service').value.get() + + api.option('num_service').value.set(1) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_unknown_operator(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + raises(ValueError, """IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value': True}, {'option': b, 'value': 1}], + 'action': 'disabled', 'operator': 'unknown'}])""") + + +def test_requires_keys(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + raises(ValueError, """IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value2': True}, {'option': b, 'value': 1}], + 'action': 'disabled', 'operator': 'and'}])""") + + +def test_requires_unvalid(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + raises(ValueError, """IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value': 'unvalid'}, {'option': b, 'value': 1}], + 'action': 'disabled', 'operator': 'and'}])""") + + +def test_requires_multi_disabled_new_format_and(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + c = IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value': True}, {'option': b, 'value': 1}], 'action': 'disabled', 'operator': 'and'}]) + od = OptionDescription('service', '', [a, b, c]) + api = getapi(Config(od)) + api.property.read_write() + + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == [] + + api.option('activate_service').value.set(False) + api.option('ip_address_service').value.get() + + api.option('num_service').value.set(1) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == [] + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_multi_disabled_new_format_and_2(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + c = IPOption('ip_address_service', '', + requires=[{'expected': [{'option': a, 'value': True}, {'option': b, 'value': 1}], 'action': 'disabled', 'operator': 'and'}, + {'expected': [{'option': a, 'value': False}, {'option': b, 'value': 1}], 'action': 'expert'}]) + od = OptionDescription('service', '', [a, b, c]) + api = getapi(Config(od)) + api.property.add('expert') + api.property.read_write() + api.option('ip_address_service').value.get() + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == [] + + api.option('activate_service').value.set(False) + api.option('num_service').value.set(1) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['expert']) + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled', 'expert']) + + +def test_requires_multi_disabled_inverse(): + a = BoolOption('activate_service', '') + b = IntOption('num_service', '') + c = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': True, + 'action': 'disabled', 'inverse': True}, + {'option': b, 'expected': 1, + 'action': 'disabled', 'inverse': True}]) + od = OptionDescription('service', '', [a, b, c]) + api = getapi(Config(od)) + api.property.read_write() + + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(True) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(False) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('num_service').value.set(1) + props = [] + try: + api.option('ip_address_service').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + api.option('activate_service').value.set(True) + api.option('ip_address_service').value.get() + + +def test_requires_multi_disabled_2(): + a = BoolOption('a', '') + b = BoolOption('b', '') + c = BoolOption('c', '') + d = BoolOption('d', '') + e = BoolOption('e', '') + f = BoolOption('f', '') + g = BoolOption('g', '') + h = BoolOption('h', '') + i = BoolOption('i', '') + j = BoolOption('j', '') + k = BoolOption('k', '') + l = BoolOption('l', '') + m = BoolOption('m', '') + list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m] + requires = [] + for boo in list_bools: + requires.append({'option': boo, 'expected': True, 'action': 'disabled'}) + z = IPOption('z', '', requires=requires) + y = copy(list_bools) + y.append(z) + od = OptionDescription('service', '', y) + api = getapi(Config(od)) + api.property.read_write() + + api.option('z').value.get() + for boo in list_bools: + api.option(boo.impl_getname()).value.set(True) + props = [] + try: + api.option('z').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + for boo in list_bools: + api.option(boo.impl_getname()).value.set(False) + if boo == m: + api.option('z').value.get() + else: + props = [] + try: + api.option('z').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_multi_disabled_inverse_2(): + a = BoolOption('a', '') + b = BoolOption('b', '') + c = BoolOption('c', '') + d = BoolOption('d', '') + e = BoolOption('e', '') + f = BoolOption('f', '') + g = BoolOption('g', '') + h = BoolOption('h', '') + i = BoolOption('i', '') + j = BoolOption('j', '') + k = BoolOption('k', '') + l = BoolOption('l', '') + m = BoolOption('m', '') + list_bools = [a, b, c, d, e, f, g, h, i, j, k, l, m] + requires = [] + for boo in list_bools: + requires.append({'option': boo, 'expected': True, 'action': 'disabled', + 'inverse': True}) + z = IPOption('z', '', requires=requires) + y = copy(list_bools) + y.append(z) + od = OptionDescription('service', '', y) + api = getapi(Config(od)) + api.property.read_write() + + props = [] + try: + api.option('z').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + for boo in list_bools: + api.option(boo.impl_getname()).value.set(True) + if boo == m: + api.option('z').value.get() + else: + props = [] + try: + api.option('z').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + for boo in list_bools: + api.option(boo.impl_getname()).value.set(False) + props = [] + try: + api.option('z').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + + +def test_requires_requirement_append(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + api.property.get() + api.option('ip_address_service').property.get() + raises(ValueError, "api.option('ip_address_service').property.add('disabled')") + api.option('activate_service').value.set(False) + # disabled is now set, test to remove disabled before store in storage + api.option('ip_address_service').property.add("test") + + +def test_requires_different_inverse(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', requires=[ + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}]) + od = OptionDescription('service', '', [a, b]) + api = getapi(Config(od)) + api.property.read_write() + raises(PropertiesOptionError, "api.option('ip_address_service').value.get()") + api.option('activate_service').value.set(False) + raises(PropertiesOptionError, "api.option('ip_address_service').value.get()") + + +def test_requires_different_inverse_unicode(): + a = BoolOption('activate_service', '', True) + d = StrOption('activate_other_service', '', 'val2') + b = IPOption('ip_address_service', '', requires=[ + {'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, + {'option': d, 'expected': 'val1', 'action': 'disabled', 'inverse': False}]) + od = OptionDescription('service', '', [a, d, b]) + api = getapi(Config(od)) + api.property.read_write() + assert api.option('ip_address_service').value.get() == None + api.option('activate_service').value.set(False) + raises(PropertiesOptionError, "api.option('ip_address_service').value.get()") + api.option('activate_service').value.set(True) + assert api.option('ip_address_service').value.get() == None + api.option('activate_other_service').value.set('val1') + raises(PropertiesOptionError, "api.option('ip_address_service').value.get()") + api.option('activate_service').value.set(False) + raises(PropertiesOptionError, "api.option('ip_address_service').value.get()") + + +def test_requires_recursive_path(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od1 = OptionDescription('service', '', [a, b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('base', '', [od1]) + api = getapi(Config(od)) + api.property.read_write() + raises(RequirementError, "api.option('service.a').value.get()") + + +def test_optiondescription_requires(): + a = BoolOption('activate_service', '', True) + b = BoolOption('ip_address_service', '', multi=True) + a, b + OptionDescription('service', '', [b], requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + + +def test_optiondescription_requires_multi(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', multi=True) + a, b + raises(ValueError, "OptionDescription('service', '', [a], requires=[{'option': b, 'expected': False, 'action': 'disabled'}])") + + +def test_properties_conflict(): + a = BoolOption('activate_service', '', True) + a + raises(ValueError, "IPOption('ip_address_service', '', properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])") + raises(ValueError, "od1 = OptionDescription('service', '', [a], properties=('disabled',), requires=[{'option': a, 'expected': False, 'action': 'disabled'}])") + + +def test_master_slave_requires(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, + requires=[{'option': ip_admin_eth0, 'expected': '192.168.1.1', 'action': 'disabled'}]) + interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + #interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('toto', '', [interface1]) + api = getapi(Config(maconfig)) + api.property.read_write() + assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == [] + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2']) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2'] + # + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1']) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()") + # + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.2']) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() is None + api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.255') + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == '255.255.255.255' + # + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1']) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()") + + +def test_master_slave_requires_no_master(): + activate = BoolOption('activate', "Activer l'accès au réseau", True) + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True, + requires=[{'option': activate, 'expected': False, 'action': 'disabled'}]) + interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + #interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('toto', '', [activate, interface1]) + api = getapi(Config(maconfig)) + api.property.read_write() + assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == [] + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2']) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2'] + api.option('activate').value.set(False) + api.option('ip_admin_eth0.ip_admin_eth0').value.set(['192.168.1.2', '192.168.1.1']) + assert api.option('ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.1.2', '192.168.1.1'] + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()") + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()") + api.option('activate').value.set(True) + assert api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get() is None + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() is None + api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.set('255.255.255.255') + assert api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get() == '255.255.255.255' + api.option('activate').value.set(False) + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 0).value.get()") + raises(PropertiesOptionError, "api.option('ip_admin_eth0.netmask_admin_eth0', 1).value.get()") diff --git a/tiramisu/api.py b/tiramisu/api.py index 6aec4ed..a47b965 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -288,15 +288,6 @@ class TiramisuOptionProperty(CommonTiramisuOption): properties = properties.get() return set(properties) - @count - def set(self, properties): - """set properties for a specified option""" - self.get_option() - properties = frozenset(properties) - self.settings.setproperties(path=self.path, - properties=properties, - config_bag=self.config_bag) - @count def add(self, prop): self.get_option() @@ -308,7 +299,9 @@ class TiramisuOptionProperty(CommonTiramisuOption): def pop(self, prop): props = self.get() props.remove(prop) - self.set(props) + self.settings.setproperties(path=self.path, + properties=frozenset(props), + config_bag=self.config_bag) @count def reset(self): diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 0f55823..342a747 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -149,19 +149,20 @@ class Base(object): calc_properties = frozenset() requires = undefined if properties is None: - properties = tuple() + properties = frozenset() + if isinstance(properties, tuple): + properties = frozenset(properties) if is_multi and 'empty' not in properties: - properties = tuple(list(properties) + ['empty']) - if not isinstance(properties, tuple): + properties = properties | {'empty'} + if not isinstance(properties, frozenset): raise TypeError(_('invalid properties type {0} for {1},' - ' must be a tuple').format(type(properties), + ' must be a frozenset').format(type(properties), name)) - if calc_properties != frozenset([]) and properties is not tuple(): - set_forbidden_properties = calc_properties & set(properties) + if calc_properties != frozenset([]) and properties: + set_forbidden_properties = calc_properties & properties if set_forbidden_properties != frozenset(): - raise ValueError('conflict: properties already set in ' - 'requirement {0}'.format( - list(set_forbidden_properties))) + raise ValueError(_('conflict: properties already set in ' + 'requirement {0}').format(list(set_forbidden_properties))) _setattr = object.__setattr__ _setattr(self, '_name', name) _setattr(self, '_informations', {'doc': doc}) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 6bb928e..da38f6f 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -474,20 +474,23 @@ class Settings(object): "imbrication detected for option:" " '{0}' with requirement on: " "'{1}'").format(path, reqpath)) - if option.impl_is_multi(): - if index is None: - # multi is allowed only for slaves - # so do not calculated requires if no index - continue + if not option.impl_is_multi(): + idx = None + is_indexed = False + elif option.impl_is_master_slaves('slave'): idx = index + is_indexed = False else: idx = None + is_indexed = True sconfig_bag = config_bag.copy('nooption') sconfig_bag.option = option try: value = context.getattr(reqpath, idx, sconfig_bag) + if is_indexed: + value = value[index] except PropertiesOptionError as err: if not transitive: if all_properties is None: @@ -508,7 +511,7 @@ class Settings(object): '').format(opt.impl_get_display_name(), option.impl_get_display_name(), prop_msg, - display_list(properties))) + display_list(list(properties)))) orig_value = err # transitive action, force expected value = expected[0] @@ -562,6 +565,19 @@ class Settings(object): """ if self._getcontext().cfgimpl_get_meta() is not None: raise ConfigError(_('cannot change property with metaconfig')) + if path is not None and config_bag.option.impl_getrequires() is not None: + not_allowed_props = properties & getattr(config_bag.option, '_calc_properties', static_set) + if not_allowed_props: + if len(not_allowed_props) == 1: + prop_msg = _('property') + calc_msg = _('this property is calculated') + else: + prop_msg = _('properties') + calc_msg = _('those properties are calculated') + raise ValueError(_('cannot set {} {} for option {} {}' + '').format(prop_msg, display_list(list(not_allowed_props), add_quote=True), + config_bag.option.impl_getname(), + calc_msg)) if config_bag is None: opt = None else: @@ -590,9 +606,7 @@ class Settings(object): raise ConfigError(_('cannot add this property: "{0}"').format( ' '.join(property_))) - props = self.getproperties(path, - None, - config_bag) + props = config_bag.option.impl_getproperties() self.setproperties(path, props | {property_}, config_bag,