server/test/unittest_msplanner.py
changeset 1230 232e16835fff
parent 1228 91ae10ffb611
child 1231 1457a545af03
equal deleted inserted replaced
1229:dd9bdcfc03b6 1230:232e16835fff
    46                      {'X': 'File'}, {'X': 'Folder'}, {'X': 'Image'},
    46                      {'X': 'File'}, {'X': 'Folder'}, {'X': 'Image'},
    47                      {'X': 'Note'}, {'X': 'Personne'}, {'X': 'RQLExpression'},
    47                      {'X': 'Note'}, {'X': 'Personne'}, {'X': 'RQLExpression'},
    48                      {'X': 'Societe'}, {'X': 'State'}, {'X': 'SubDivision'},
    48                      {'X': 'Societe'}, {'X': 'State'}, {'X': 'SubDivision'},
    49                      {'X': 'Tag'}, {'X': 'TrInfo'}, {'X': 'Transition'}])
    49                      {'X': 'Tag'}, {'X': 'TrInfo'}, {'X': 'Transition'}])
    50 
    50 
       
    51 def clear_ms_caches(repo):
       
    52     clear_cache(repo, 'rel_type_sources')
       
    53     clear_cache(repo, 'can_cross_relation')
       
    54     clear_cache(repo, 'is_multi_sources_relation')
       
    55     # XXX source_defs
       
    56     
    51 # keep cnx so it's not garbage collected and the associated session is closed
    57 # keep cnx so it's not garbage collected and the associated session is closed
    52 repo, cnx = init_test_database('sqlite')
    58 repo, cnx = init_test_database('sqlite')
    53 
    59 
    54 class BaseMSPlannerTC(BasePlannerTC):
    60 class BaseMSPlannerTC(BasePlannerTC):
    55     """test planner related feature on a 3-sources repository:
    61     """test planner related feature on a 3-sources repository:
    88         self.sources.append(FakeCardSource(self.o._repo, self.o.schema,
    94         self.sources.append(FakeCardSource(self.o._repo, self.o.schema,
    89                                            {'uri': 'cards'}))
    95                                            {'uri': 'cards'}))
    90         repo.sources_by_uri['cards'] = self.sources[-1]
    96         repo.sources_by_uri['cards'] = self.sources[-1]
    91         self.rql = self.sources[-1]
    97         self.rql = self.sources[-1]
    92         do_monkey_patch()
    98         do_monkey_patch()
       
    99         clear_ms_caches(repo)
    93         
   100         
    94     def tearDown(self):
   101     def tearDown(self):
    95         undo_monkey_patch()
   102         undo_monkey_patch()
    96         del self.sources[-1]
   103         del self.sources[-1]
    97         del self.sources[-1]
   104         del self.sources[-1]
   254         """
   261         """
   255         self._test('Any G,L WHERE X in_group G, X login L, G name "managers", '
   262         self._test('Any G,L WHERE X in_group G, X login L, G name "managers", '
   256                    'EXISTS(X copain T, T login L, T login in ("comme", "cochon")) OR '
   263                    'EXISTS(X copain T, T login L, T login in ("comme", "cochon")) OR '
   257                    'EXISTS(X in_state S, S name "pascontent", NOT X copain T2, T2 login "billy")',
   264                    'EXISTS(X in_state S, S name "pascontent", NOT X copain T2, T2 login "billy")',
   258                    {self.system: {'X': s[0], 'S': s[0], 'T2': s[0], 'T': s[0], 'G': s[0], 'copain': s[0], 'in_group': s[0]}, 
   265                    {self.system: {'X': s[0], 'S': s[0], 'T2': s[0], 'T': s[0], 'G': s[0], 'copain': s[0], 'in_group': s[0]}, 
   259                     self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}}, True)
   266                     self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}},
       
   267                    True)
   260 
   268 
   261     def test_relation_need_split(self):
   269     def test_relation_need_split(self):
   262         self._test('Any X, S WHERE X in_state S',
   270         self._test('Any X, S WHERE X in_state S',
   263                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]},
   271                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]},
   264                      self.rql: {'X': s[2], 'S': s[2]}}, True)
   272                     self.rql: {'X': s[2], 'S': s[2]}},
       
   273                    True)
       
   274         
       
   275     def test_not_relation_need_split(self):
       
   276         self._test('Any SN WHERE NOT X in_state S, S name SN',
       
   277                    {self.rql: {'X': s[2], 'S': s[0, 1, 2]},
       
   278                     self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]}},
       
   279                    True)
       
   280         
       
   281     def test_not_relation_no_split_external(self):
       
   282         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
       
   283         # similar to the above test but with an eid coming from the external source.
       
   284         # the same plan may be used, since we won't find any record in the system source
       
   285         # linking 9999999 to a state 
       
   286         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
       
   287                    {'x': 999999},
       
   288                    {self.rql: {'x': s[0], 'S': s[0]},
       
   289                     self.system: {'x': s[0], 'S': s[0]}},
       
   290                    False)
   265 
   291 
   266     def test_relation_restriction_ambigous_need_split(self):
   292     def test_relation_restriction_ambigous_need_split(self):
   267         self._test('Any X,T WHERE X in_state S, S name "pending", T tags X',
   293         self._test('Any X,T WHERE X in_state S, S name "pending", T tags X',
   268                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2], 'T': s[0, 1, 2], 'tags': s[0, 1, 2]},
   294                    {self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2], 'T': s[0, 1, 2], 'tags': s[0, 1, 2]},
   269                     self.rql: {'X': s[2], 'S': s[2]}}, True)
   295                     self.rql: {'X': s[2], 'S': s[2]}},
       
   296                    True)
   270 
   297 
   271     def test_simplified_var(self):
   298     def test_simplified_var(self):
   272         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   299         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   273         self._test('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',
   300         self._test('Any U WHERE U in_group G, (G name IN ("managers", "logilab") OR (X require_permission P?, P name "bla", P require_group G)), X eid %(x)s, U eid %(u)s',
   274                    {'x': 999999, 'u': self.session.user.eid},
   301                    {'x': 999999, 'u': self.session.user.eid},
   279         
   306         
   280     def test_delete_relation1(self):
   307     def test_delete_relation1(self):
   281         ueid = self.session.user.eid
   308         ueid = self.session.user.eid
   282         self._test('Any X, Y WHERE X created_by Y, X eid %(x)s, NOT Y eid %(y)s',
   309         self._test('Any X, Y WHERE X created_by Y, X eid %(x)s, NOT Y eid %(y)s',
   283                    {'x': ueid, 'y': ueid},
   310                    {'x': ueid, 'y': ueid},
   284                    {self.system: {'Y': s[0], 'created_by': s[0], 'x': s[0]}}, False)
   311                    {self.system: {'Y': s[0], 'created_by': s[0], 'x': s[0]}},
       
   312                    False)
   285 
   313 
   286     def test_crossed_relation_eid_1_needattr(self):
   314     def test_crossed_relation_eid_1_needattr(self):
   287         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   315         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   288         ueid = self.session.user.eid
   316         ueid = self.session.user.eid
   289         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
   317         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
   290                    {'x': 999999,},
   318                    {'x': 999999,},
   291                    {self.rql: {'Y': s[0]}, self.system: {'Y': s[0], 'x': s[0]}}, True)
   319                    {self.rql: {'Y': s[0]}, self.system: {'Y': s[0], 'x': s[0]}},
       
   320                    True)
   292         
   321         
   293     def test_crossed_relation_eid_1_invariant(self):
   322     def test_crossed_relation_eid_1_invariant(self):
   294         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   323         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   295         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
   324         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
   296                    {'x': 999999},
   325                    {'x': 999999},
   297                    {self.system: {'Y': s[0], 'x': s[0]}}, False)
   326                    {self.system: {'Y': s[0], 'x': s[0]}},
       
   327                    False)
   298 
   328 
   299     def test_crossed_relation_eid_2_invariant(self):
   329     def test_crossed_relation_eid_2_invariant(self):
   300         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   330         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   301         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
   331         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
   302                    {'x': 999999,},
   332                    {'x': 999999,},
   309         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
   339         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
   310                    {'x': 999999},
   340                    {'x': 999999},
   311                    {self.rql: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
   341                    {self.rql: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]},
   312                     self.system: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]}},
   342                     self.system: {'X': s[0], 'AD': s[0], 'multisource_crossed_rel': s[0], 'x': s[0]}},
   313                    True)
   343                    True)
       
   344         
       
   345     def test_version_crossed_depends_on_2(self):
       
   346         repo._type_source_cache[999999] = ('Note', 'system', 999999)
       
   347         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
       
   348                    {'x': 999999},
       
   349                    {self.rql: {'X': s[0], 'AD': s[0]},
       
   350                     self.system: {'X': s[0], 'AD': s[0], 'x': s[0]}},
       
   351                     True)
       
   352 
       
   353     def test_simplified_var_3(self):
       
   354         self.set_debug(True)
       
   355         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
       
   356         repo._type_source_cache[999998] = ('State', 'cards', 999998)
       
   357         self._test('Any S,T WHERE S eid %(s)s, N eid %(n)s, N type T, N is Note, S is State',
       
   358                    {'n': 999999, 's': 999998},
       
   359                    {self.rql: {'s': s[0], 'N': s[0]}}, False)
   314                    
   360                    
   315 
   361 
   316         
   362         
   317 class MSPlannerTC(BaseMSPlannerTC):
   363 class MSPlannerTC(BaseMSPlannerTC):
   318     
   364     
  1198         self._test('Any SN WHERE NOT X in_state S, S name SN',
  1244         self._test('Any SN WHERE NOT X in_state S, S name SN',
  1199                    [('FetchStep', [('Any SN,S WHERE S name SN, S is State',
  1245                    [('FetchStep', [('Any SN,S WHERE S name SN, S is State',
  1200                                     [{'S': 'State', 'SN': 'String'}])],
  1246                                     [{'S': 'State', 'SN': 'String'}])],
  1201                      [self.rql, self.system], None, {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1247                      [self.rql, self.system], None, {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1202                      []),
  1248                      []),
  1203                     ('FetchStep', [('Any X WHERE X is Note', [{'X': 'Note'}])],
       
  1204                      [self.rql, self.system], None, {'X': 'table1.C0'},
       
  1205                      []),
       
  1206                     ('IntersectStep', None, None,
  1249                     ('IntersectStep', None, None,
  1207                      [('OneFetchStep',
  1250                      [('OneFetchStep',
       
  1251                        [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is Note',
       
  1252                          [{'S': 'State', 'SN': 'String', 'X': 'Note'}])],
       
  1253                        None, None, [self.rql, self.system], {},
       
  1254                        []),
       
  1255                       ('OneFetchStep',
  1208                        [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is IN(Affaire, EUser)',
  1256                        [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is IN(Affaire, EUser)',
  1209                          [{'S': 'State', 'SN': 'String', 'X': 'Affaire'},
  1257                          [{'S': 'State', 'SN': 'String', 'X': 'Affaire'},
  1210                           {'S': 'State', 'SN': 'String', 'X': 'EUser'}])],
  1258                           {'S': 'State', 'SN': 'String', 'X': 'EUser'}])],
  1211                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1259                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1212                        []),
  1260                        []),]
  1213                       ('OneFetchStep',
       
  1214                        [('Any SN WHERE NOT X in_state S, S name SN, S is State, X is Note',
       
  1215                          [{'S': 'State', 'SN': 'String', 'X': 'Note'}])],
       
  1216                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0',
       
  1217                                                    'X': 'table1.C0'},
       
  1218                        [])]
       
  1219                      )])
  1261                      )])
  1220             
  1262             
  1221     def test_external_attributes_and_relation(self):
  1263     def test_external_attributes_and_relation(self):
  1222         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1264         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1223         self._test('Any A,B,C,D WHERE A eid %(x)s,A creation_date B,A modification_date C, A todo_by D?',
  1265         self._test('Any A,B,C,D WHERE A eid %(x)s,A creation_date B,A modification_date C, A todo_by D?',
  1927         self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
  1969         self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
  1928         assert repo.sources_by_uri['cards2'].support_relation('multisource_crossed_rel')
  1970         assert repo.sources_by_uri['cards2'].support_relation('multisource_crossed_rel')
  1929         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
  1971         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
  1930         assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
  1972         assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
  1931         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards'].cross_relations
  1973         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards'].cross_relations
       
  1974         clear_ms_caches(repo)
  1932     _test = test_plan
  1975     _test = test_plan
  1933         
  1976         
  1934     def tearDown(self):
  1977     def tearDown(self):
  1935         undo_monkey_patch()
  1978         undo_monkey_patch()
  1936         del self.sources[-1]
  1979         del self.sources[-1]
  1989                          {'A': 'table0.C0', 'AD': 'table0.C1', 'AD.name': 'table0.C2',
  2032                          {'A': 'table0.C0', 'AD': 'table0.C1', 'AD.name': 'table0.C2',
  1990                           'AE': 'table0.C2', 'X': 'table1.C0'},
  2033                           'AE': 'table0.C2', 'X': 'table1.C0'},
  1991                          [])],
  2034                          [])],
  1992                        {'x': 999999})
  2035                        {'x': 999999})
  1993 
  2036 
  1994     def test_version_crossed_depends_on_2_XXXFIXME(self):
  2037     def test_version_crossed_depends_on_2(self):
       
  2038         self.set_debug(True)
  1995         self.repo._type_source_cache[999999] = ('Note', 'system', 999999)
  2039         self.repo._type_source_cache[999999] = ('Note', 'system', 999999)
  1996         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
  2040         self._test('Any X,AD,AE WHERE E eid %(x)s, E multisource_crossed_rel X, X in_state AD, AD name AE',
  1997                    [],
  2041                    [('FetchStep', [('Any X,AD,AE WHERE X in_state AD, AD name AE, AD is State, X is Note',
       
  2042                                     [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
       
  2043                      [self.rql, self.rql2, self.system],
       
  2044                      None, {'AD': 'table0.C1', 'AD.name': 'table0.C2',
       
  2045                             'AE': 'table0.C2', 'X': 'table0.C0'},
       
  2046                      []),
       
  2047                     ('OneFetchStep', [('Any X,AD,AE WHERE 999999 multisource_crossed_rel X, AD name AE, AD is State, X is Note',
       
  2048                                        [{'AD': 'State', 'AE': 'String', 'X': 'Note'}])],
       
  2049                      None, None, [self.system],
       
  2050                      {'AD': 'table0.C1', 'AD.name': 'table0.C2', 'AE': 'table0.C2', 'X': 'table0.C0'},
       
  2051                      [])],
  1998                    {'x': 999999})
  2052                    {'x': 999999})
  1999 
  2053 
  2000     def test_version_crossed_depends_on_3_XXXFIXME(self):
  2054     def test_version_crossed_depends_on_3_XXXFIXME(self):
  2001         self._test('Any X,AD,AE WHERE E multisource_crossed_rel X, X in_state AD, AD name AE, E is Note',
  2055         self._test('Any X,AD,AE WHERE E multisource_crossed_rel X, X in_state AD, AD name AE, E is Note',
  2002                    [])
  2056                    [])