configurationengine/source/cone/public/tests/unittest_rules_on_configuration.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 import operator as ops
       
    18 import unittest
       
    19 import sys, os
       
    20 import __init__
       
    21 import tokenize
       
    22 import StringIO
       
    23 
       
    24 from cone.public import api,exceptions, utils
       
    25 from cone.public.rules import ASTInterpreter, RelationContainerImpl
       
    26 from cone.public.rules import ParseException, DefaultContext, BaseRelation
       
    27 from cone.public import rules
       
    28 
       
    29 #### TEST RELATIONS ####
       
    30 
       
    31 AA_BA = 'a.a == "foo" requires b.b != 0'
       
    32 AB_BB = 'a.b configures b.b = a.b+":"+ "test"'
       
    33 BA_CA = 'b.a requires c.a and c.b and a.b'
       
    34 
       
    35 CB_DA = 'c.b requires d.a'
       
    36 DA_DB = 'd.a requires d.b'
       
    37 
       
    38 AC_AB_BA = 'a.c and a.a requires b.a'
       
    39 
       
    40 EA_FSTAR = 'e.a requires f.*'
       
    41 
       
    42 TEST_RELATIONS = {
       
    43     'a.a' : [AA_BA, 'a.a == "test" requires b.a'],
       
    44     'a.b' : [AB_BB],
       
    45     'a.c' : [AC_AB_BA],
       
    46     'b.a' : [BA_CA],
       
    47     'c.b' : [CB_DA],
       
    48     'd.a' : [DA_DB],
       
    49     'e.a' : [EA_FSTAR]
       
    50 }
       
    51 
       
    52 def get_test_configuration():
       
    53     config = api.Configuration()
       
    54     config.add_feature(api.Feature('a'))
       
    55     config.add_feature(api.Feature('a'),'a')
       
    56     config.add_feature(api.Feature('b'),'a')
       
    57     config.add_feature(api.Feature('c'),'a')
       
    58     config.add_feature(api.Feature('b'))
       
    59     config.add_feature(api.Feature('a'),'b')
       
    60     config.add_feature(api.Feature('b'),'b')
       
    61     config.add_feature(api.Feature('c'))
       
    62     config.add_feature(api.Feature('a'),'c')
       
    63     config.add_feature(api.Feature('b'),'c')
       
    64     config.add_feature(api.Feature('d'))
       
    65     config.add_feature(api.Feature('a'),'d')
       
    66     config.add_feature(api.Feature('b'),'d')
       
    67     config.add_feature(api.Feature('e'))
       
    68     config.add_feature(api.Feature('a'),'e')
       
    69     dview = config.get_default_view()
       
    70     dview.get_feature('a.a').set_value('test')
       
    71     dview.get_feature('a.b').set_value('hey')
       
    72     dview.get_feature('a.c').set_value(False)
       
    73     dview.get_feature('b.a').set_value(True)
       
    74     dview.get_feature('b.b').set_value(True)
       
    75     dview.get_feature('c.a').set_value(True)
       
    76     dview.get_feature('c.b').set_value(True)
       
    77     dview.get_feature('d.a').set_value(False)
       
    78     dview.get_feature('d.b').set_value(False)
       
    79     return config
       
    80 
       
    81 class TestFactory():
       
    82     def get_relations_for(self, configuration, ref):
       
    83         rels = TEST_RELATIONS.get(ref)
       
    84         if rels:
       
    85             relation_container = RelationContainerImpl()
       
    86             for rel in rels:
       
    87                 (left_expression,relation_name,right_expression) = parse_rule(rel)
       
    88                 relation = rules.RELATIONS.get(relation_name)(configuration, left_expression, right_expression)
       
    89                 relation_container.add_relation(relation)
       
    90                 propagated_relations = self.get_relations_for(configuration, right_expression)
       
    91                 if propagated_relations:
       
    92                     for relation in propagated_relations:
       
    93                         relation_container.add_relation(relation)
       
    94             return relation_container
       
    95         return None
       
    96 
       
    97 def parse_rule(rulestring):
       
    98     """
       
    99     Divide the given rule string into (left side, relation, right side) components. 
       
   100     @return: Triple (left side, relation, right side)
       
   101     """
       
   102     left_expression = ''
       
   103     relation_name = None
       
   104     right_expression = ''
       
   105     for token in rules.get_tokens(rulestring):
       
   106         if relation_name == None:
       
   107             if token in rules.RELATIONS.keys():
       
   108                 relation_name = token
       
   109             else:
       
   110                 left_expression += ' ' + token
       
   111         else:
       
   112             right_expression += ' ' + token
       
   113     
       
   114     if relation_name == None:
       
   115         raise exceptions.ParseError('invalid rule definition %s' % rulestring)
       
   116     
       
   117     return (left_expression,relation_name,right_expression)
       
   118 
       
   119 class ConfigurationContext(DefaultContext):
       
   120     def handle_terminal(self, expression):
       
   121         try:
       
   122             value = self.data.get_feature(expression).get_value()
       
   123             if value != None:
       
   124                 #print "handle_terminal %s = %s" % (expression,value)
       
   125                 return value
       
   126             else:
       
   127                 raise exceptions.NotBound('Feature %s has no value' % expression)
       
   128         except exceptions.NotFound,e:
       
   129             """ return the expression itself if it is not a fearef """
       
   130             #print "handle_terminal constant %s" % (expression)
       
   131             try:
       
   132                 return eval(expression)
       
   133             except (NameError,SyntaxError), e:
       
   134                 return expression
       
   135 
       
   136     def eval(self, ast, expression, value):
       
   137         #print "expression %s = %s" % (expression,value)
       
   138         pass
       
   139         
       
   140 class ConfigurationBaseRelation(BaseRelation):
       
   141     def __init__(self, data, left, right):
       
   142         self.context = ConfigurationContext(data)
       
   143         super(ConfigurationBaseRelation, self).__init__(data, left, right)
       
   144 
       
   145 class RequireRelation(ConfigurationBaseRelation):
       
   146     KEY = 'requires'
       
   147     def __init__(self, data, left, right):
       
   148         super(RequireRelation, self).__init__(data, left, right)
       
   149         self.context = ConfigurationContext(data)
       
   150 
       
   151 class ConfigureRelation(ConfigurationBaseRelation):
       
   152     KEY = 'configures'
       
   153     def __init__(self, data, left, right):
       
   154         super(ConfigureRelation, self).__init__(data, left, right)
       
   155         self.context = ConfigurationContext(data)
       
   156 
       
   157 def handle_configure(self, left, right):
       
   158     if left and right:
       
   159         return True
       
   160     elif not left:
       
   161         return True
       
   162     return False
       
   163 
       
   164 def handle_set(self, left, right):
       
   165     left.set_value(right)
       
   166 
       
   167 class ConfigureExpression(rules.TwoOperatorExpression):
       
   168     PRECEDENCE = rules.PRECEDENCES['RELATION_OPERATORS']
       
   169     KEY = 'configures'
       
   170     OP = handle_configure
       
   171 
       
   172     def eval(self, context):
       
   173         super(ConfigureExpression, self).eval(context)
       
   174         if not self.value:
       
   175             left_keys = []
       
   176             for ref in self.ast.extract_refs(str(self.left)):
       
   177                 for key in context.get_keys(ref):
       
   178                     left_keys.append(key)
       
   179 
       
   180             for key in left_keys:
       
   181                 self.ast.add_error(key, { 'error_string' : 'CONFIGURES right side value is "False"',
       
   182                                           'left_key' : key,
       
   183                                           'rule' : self.ast.expression
       
   184                                           })
       
   185         return self.value
       
   186 
       
   187 def handle_plus(self, a,b):
       
   188     #print "%s adding a: %s to b: %s" % (self, a,b)
       
   189     return a + b
       
   190 
       
   191 class ConcatExpression(rules.TwoOperatorExpression):
       
   192     PRECEDENCE = rules.PRECEDENCES['ADDSUB_OPERATORS']
       
   193     KEY= '+'
       
   194     OP = handle_plus
       
   195 
       
   196 
       
   197 class SetExpression(rules.TwoOperatorExpression):
       
   198     PRECEDENCE = rules.PRECEDENCES['SET_OPERATORS']
       
   199     KEY= '='
       
   200     OP = handle_set
       
   201 
       
   202     def eval(self, context):
       
   203         try:
       
   204             variable = context.data.get_feature(self.left.expression)
       
   205             variable.set_value(self.right.eval(context))
       
   206             return True
       
   207         except exceptions.NotFound:
       
   208             return False
       
   209 
       
   210 class TestRelations(unittest.TestCase):
       
   211 
       
   212     def setUp(self):
       
   213         self.configuration = get_test_configuration()
       
   214         
       
   215         self.RELATIONS_BACKUP = rules.RELATIONS
       
   216         self.OPERATORS_BACKUP = rules.OPERATORS
       
   217         rules.RELATIONS = rules.RELATIONS.copy()
       
   218         rules.OPERATORS = rules.OPERATORS.copy()
       
   219         self.assertTrue(self.RELATIONS_BACKUP is not rules.RELATIONS)
       
   220         self.assertTrue(self.OPERATORS_BACKUP is not rules.OPERATORS)
       
   221         
       
   222         rules.RELATIONS[RequireRelation.KEY] = RequireRelation
       
   223         rules.RELATIONS[ConfigureRelation.KEY] = ConfigureRelation
       
   224         rules.OPERATORS[ConfigureExpression.KEY] = ConfigureExpression
       
   225         rules.OPERATORS[ConcatExpression.KEY] = ConcatExpression
       
   226         rules.OPERATORS[SetExpression.KEY] = SetExpression
       
   227     
       
   228     def tearDown(self):
       
   229         rules.RELATIONS = self.RELATIONS_BACKUP
       
   230         rules.OPERATORS = self.OPERATORS_BACKUP
       
   231 
       
   232     def test_has_ref(self):
       
   233         """
       
   234         Tests the relation and relation container
       
   235         """
       
   236         factory = TestFactory()
       
   237         rels = factory.get_relations_for(self.configuration, 'a.a')
       
   238         ret= rels.execute()
       
   239         self.assertTrue(ret)
       
   240 
       
   241     def test_has_ref(self):
       
   242         """
       
   243         Tests the relation and relation container
       
   244         """
       
   245         factory = TestFactory()
       
   246         rels = factory.get_relations_for(self.configuration, 'a.a')
       
   247         ret= rels.execute()
       
   248         self.assertTrue(ret)
       
   249         
       
   250     def test_not_has_ref(self):
       
   251         factory = TestFactory()
       
   252         # depends on c.a which has no value in conf
       
   253         rels = factory.get_relations_for(self.configuration, 'b.a')
       
   254         ret = rels.execute()
       
   255         self.assertTrue(ret)
       
   256 
       
   257     def test_not_has_ref_in_container(self):
       
   258         factory = TestFactory()
       
   259         rels = factory.get_relations_for(self.configuration, 'c.b')
       
   260         ret = rels.execute()
       
   261         self.assertFalse(ret)
       
   262 
       
   263     def test_two_on_the_left(self):
       
   264         factory = TestFactory()
       
   265         rels = factory.get_relations_for(self.configuration, 'a.c')
       
   266         ret = rels.execute()
       
   267         self.assertTrue(ret)
       
   268 
       
   269     def test_configure_right_side(self):
       
   270         factory = TestFactory()
       
   271         rels = factory.get_relations_for(self.configuration, 'a.b')
       
   272         ret = rels.execute()
       
   273         self.assertTrue(ret)
       
   274         self.assertEquals(self.configuration.get_default_view().get_feature('b.b').get_value(),'hey:test')
       
   275 
       
   276 if __name__ == '__main__':
       
   277     unittest.main()