server/test/unittest_msplanner.py
branchtls-sprint
changeset 1785 01245e2a777d
parent 1398 5fe84a5f7035
child 1786 eccd1885d42e
equal deleted inserted replaced
1784:f0fb914e57db 1785:01245e2a777d
    22     support_entities = {'CWUser': False}
    22     support_entities = {'CWUser': False}
    23     support_relations = {}
    23     support_relations = {}
    24     def syntax_tree_search(self, *args, **kwargs):
    24     def syntax_tree_search(self, *args, **kwargs):
    25         return []
    25         return []
    26 
    26 
    27         
    27 
    28 class FakeCardSource(AbstractSource):
    28 class FakeCardSource(AbstractSource):
    29     uri = 'ccc'
    29     uri = 'ccc'
    30     support_entities = {'Card': True, 'Note': True, 'State': True}
    30     support_entities = {'Card': True, 'Note': True, 'State': True}
    31     support_relations = {'in_state': True, 'multisource_rel': True, 'multisource_inlined_rel': True,
    31     support_relations = {'in_state': True, 'multisource_rel': True, 'multisource_inlined_rel': True,
    32                          'multisource_crossed_rel': True}
    32                          'multisource_crossed_rel': True}
    33     dont_cross_relations = set(('fiche',))
    33     dont_cross_relations = set(('fiche', 'in_state'))
    34     cross_relations = set(('multisource_crossed_rel',))
    34     cross_relations = set(('multisource_crossed_rel',))
    35     
    35 
    36     def syntax_tree_search(self, *args, **kwargs):
    36     def syntax_tree_search(self, *args, **kwargs):
    37         return []
    37         return []
    38 
    38 
    39 X_ALL_SOLS = sorted([{'X': 'Affaire'}, {'X': 'Basket'}, {'X': 'Bookmark'},
    39 X_ALL_SOLS = sorted([{'X': 'Affaire'}, {'X': 'Basket'}, {'X': 'Bookmark'},
    40                      {'X': 'Card'}, {'X': 'Comment'}, {'X': 'Division'},
    40                      {'X': 'Card'}, {'X': 'Comment'}, {'X': 'Division'},
    51 def clear_ms_caches(repo):
    51 def clear_ms_caches(repo):
    52     clear_cache(repo, 'rel_type_sources')
    52     clear_cache(repo, 'rel_type_sources')
    53     clear_cache(repo, 'can_cross_relation')
    53     clear_cache(repo, 'can_cross_relation')
    54     clear_cache(repo, 'is_multi_sources_relation')
    54     clear_cache(repo, 'is_multi_sources_relation')
    55     # XXX source_defs
    55     # XXX source_defs
    56     
    56 
    57 # 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
    58 repo, cnx = init_test_database('sqlite')
    58 repo, cnx = init_test_database('sqlite')
    59 
    59 
    60 class BaseMSPlannerTC(BasePlannerTC):
    60 class BaseMSPlannerTC(BasePlannerTC):
    61     """test planner related feature on a 3-sources repository:
    61     """test planner related feature on a 3-sources repository:
    62     
    62 
    63     * system source supporting everything
    63     * system source supporting everything
    64     * ldap source supporting CWUser
    64     * ldap source supporting CWUser
    65     * rql source supporting Card
    65     * rql source supporting Card
    66     """
    66     """
    67     repo = repo
    67     repo = repo
    68     
    68 
    69     def setUp(self):
    69     def setUp(self):
    70         #_QuerierTC.setUp(self)
    70         #_QuerierTC.setUp(self)
    71         clear_cache(repo, 'rel_type_sources')
    71         clear_cache(repo, 'rel_type_sources')
    72         self.o = repo.querier
    72         self.o = repo.querier
    73         self.session = repo._sessions.values()[0]
    73         self.session = repo._sessions.values()[0]
    82         # hijack CWUser security
    82         # hijack CWUser security
    83         userreadperms = list(self.schema['CWUser']._groups['read'])
    83         userreadperms = list(self.schema['CWUser']._groups['read'])
    84         self.prevrqlexpr_user = userreadperms[-1]
    84         self.prevrqlexpr_user = userreadperms[-1]
    85         userreadperms[-1] = ERQLExpression('X owned_by U')
    85         userreadperms[-1] = ERQLExpression('X owned_by U')
    86         self.schema['CWUser']._groups['read'] = tuple(userreadperms)
    86         self.schema['CWUser']._groups['read'] = tuple(userreadperms)
    87         
    87 
    88         self.sources = self.o._repo.sources
    88         self.sources = self.o._repo.sources
    89         self.system = self.sources[-1]
    89         self.system = self.sources[-1]
    90         self.sources.append(FakeUserROSource(self.o._repo, self.o.schema,
    90         self.sources.append(FakeUserROSource(self.o._repo, self.o.schema,
    91                                              {'uri': 'ldapuser'}))
    91                                              {'uri': 'ldapuser'}))
    92         repo.sources_by_uri['ldapuser'] = self.sources[-1]
    92         repo.sources_by_uri['ldapuser'] = self.sources[-1]
    95                                            {'uri': 'cards'}))
    95                                            {'uri': 'cards'}))
    96         repo.sources_by_uri['cards'] = self.sources[-1]
    96         repo.sources_by_uri['cards'] = self.sources[-1]
    97         self.rql = self.sources[-1]
    97         self.rql = self.sources[-1]
    98         do_monkey_patch()
    98         do_monkey_patch()
    99         clear_ms_caches(repo)
    99         clear_ms_caches(repo)
   100         
   100 
   101     def tearDown(self):
   101     def tearDown(self):
   102         undo_monkey_patch()
   102         undo_monkey_patch()
   103         del self.sources[-1]
   103         del self.sources[-1]
   104         del self.sources[-1]
   104         del self.sources[-1]
   105         del repo.sources_by_uri['ldapuser']
   105         del repo.sources_by_uri['ldapuser']
   106         del repo.sources_by_uri['cards']
   106         del repo.sources_by_uri['cards']
   107         # restore hijacked security
   107         # restore hijacked security
   108         self.restore_orig_affaire_security()
   108         self.restore_orig_affaire_security()
   109         self.restore_orig_euser_security()
   109         self.restore_orig_euser_security()
   110         
   110 
   111     def restore_orig_affaire_security(self):
   111     def restore_orig_affaire_security(self):
   112         affreadperms = list(self.schema['Affaire']._groups['read'])
   112         affreadperms = list(self.schema['Affaire']._groups['read'])
   113         affreadperms[-1] = self.prevrqlexpr_affaire
   113         affreadperms[-1] = self.prevrqlexpr_affaire
   114         self.schema['Affaire']._groups['read'] = tuple(affreadperms)
   114         self.schema['Affaire']._groups['read'] = tuple(affreadperms)
   115         clear_cache(self.schema['Affaire'], 'ERSchema_get_rqlexprs')
   115         clear_cache(self.schema['Affaire'], 'ERSchema_get_rqlexprs')
   116         
   116 
   117     def restore_orig_euser_security(self):
   117     def restore_orig_euser_security(self):
   118         userreadperms = list(self.schema['CWUser']._groups['read'])
   118         userreadperms = list(self.schema['CWUser']._groups['read'])
   119         userreadperms[-1] = self.prevrqlexpr_user
   119         userreadperms[-1] = self.prevrqlexpr_user
   120         self.schema['CWUser']._groups['read'] = tuple(userreadperms)
   120         self.schema['CWUser']._groups['read'] = tuple(userreadperms)
   121         clear_cache(self.schema['CWUser'], 'ERSchema_get_rqlexprs')
   121         clear_cache(self.schema['CWUser'], 'ERSchema_get_rqlexprs')
   122 
   122 
   123                   
   123 
   124 class PartPlanInformationTC(BaseMSPlannerTC):
   124 class PartPlanInformationTC(BaseMSPlannerTC):
   125 
   125 
   126     def _test(self, rql, *args):
   126     def _test(self, rql, *args):
   127         if len(args) == 3:
   127         if len(args) == 3:
   128             kwargs, sourcesterms, needsplit = args
   128             kwargs, sourcesterms, needsplit = args
   138                 solindices = sourcevars.pop(var)
   138                 solindices = sourcevars.pop(var)
   139                 sourcevars[var._ms_table_key()] = solindices
   139                 sourcevars[var._ms_table_key()] = solindices
   140         self.assertEquals(ppi._sourcesterms, sourcesterms)
   140         self.assertEquals(ppi._sourcesterms, sourcesterms)
   141         self.assertEquals(ppi.needsplit, needsplit)
   141         self.assertEquals(ppi.needsplit, needsplit)
   142 
   142 
   143         
   143 
   144     def test_simple_system_only(self):
   144     def test_simple_system_only(self):
   145         """retrieve entities only supported by the system source"""
   145         """retrieve entities only supported by the system source"""
   146         self._test('CWGroup X',
   146         self._test('CWGroup X',
   147                    {self.system: {'X': s[0]}}, False)
   147                    {self.system: {'X': s[0]}}, False)
   148         
   148 
   149     def test_simple_system_ldap(self):
   149     def test_simple_system_ldap(self):
   150         """retrieve CWUser X from both sources and return concatenation of results
   150         """retrieve CWUser X from both sources and return concatenation of results
   151         """
   151         """
   152         self._test('CWUser X',
   152         self._test('CWUser X',
   153                    {self.system: {'X': s[0]}, self.ldap: {'X': s[0]}}, False)
   153                    {self.system: {'X': s[0]}, self.ldap: {'X': s[0]}}, False)
   154         
   154 
   155     def test_simple_system_rql(self):
   155     def test_simple_system_rql(self):
   156         """retrieve Card X from both sources and return concatenation of results
   156         """retrieve Card X from both sources and return concatenation of results
   157         """
   157         """
   158         self._test('Any X, XT WHERE X is Card, X title XT',
   158         self._test('Any X, XT WHERE X is Card, X title XT',
   159                    {self.system: {'X': s[0]}, self.rql: {'X': s[0]}}, False)
   159                    {self.system: {'X': s[0]}, self.rql: {'X': s[0]}}, False)
   160         
   160 
   161     def test_simple_eid_specified(self):
   161     def test_simple_eid_specified(self):
   162         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   162         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   163         """
   163         """
   164         ueid = self.session.user.eid
   164         ueid = self.session.user.eid
   165         self._test('Any X,L WHERE X eid %(x)s, X login L', {'x': ueid},
   165         self._test('Any X,L WHERE X eid %(x)s, X login L', {'x': ueid},
   166                    {self.system: {'X': s[0]}}, False)
   166                    {self.system: {'X': s[0]}}, False)
   167         
   167 
   168     def test_simple_eid_invariant(self):
   168     def test_simple_eid_invariant(self):
   169         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   169         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   170         """
   170         """
   171         ueid = self.session.user.eid
   171         ueid = self.session.user.eid
   172         self._test('Any X WHERE X eid %(x)s', {'x': ueid},
   172         self._test('Any X WHERE X eid %(x)s', {'x': ueid},
   173                    {self.system: {'x': s[0]}}, False)
   173                    {self.system: {'x': s[0]}}, False)
   174         
   174 
   175     def test_simple_invariant(self):
   175     def test_simple_invariant(self):
   176         """retrieve CWUser X from system source only (X is invariant and in_group not supported by ldap source)
   176         """retrieve CWUser X from system source only (X is invariant and in_group not supported by ldap source)
   177         """
   177         """
   178         self._test('Any X WHERE X is CWUser, X in_group G, G name "users"',
   178         self._test('Any X WHERE X is CWUser, X in_group G, G name "users"',
   179                    {self.system: {'X': s[0], 'G': s[0], 'in_group': s[0]}}, False)
   179                    {self.system: {'X': s[0], 'G': s[0], 'in_group': s[0]}}, False)
   180         
   180 
   181     def test_security_has_text(self):
   181     def test_security_has_text(self):
   182         """retrieve CWUser X from system source only (has_text not supported by ldap source)
   182         """retrieve CWUser X from system source only (has_text not supported by ldap source)
   183         """
   183         """
   184         # specify CWUser instead of any since the way this test is written we aren't well dealing
   184         # specify CWUser instead of any since the way this test is written we aren't well dealing
   185         # with ambigous query (eg only considering the first solution)
   185         # with ambigous query (eg only considering the first solution)
   186         self._test('CWUser X WHERE X has_text "bla"',
   186         self._test('CWUser X WHERE X has_text "bla"',
   187                    {self.system: {'X': s[0]}}, False)
   187                    {self.system: {'X': s[0]}}, False)
   188         
   188 
   189     def test_complex_base(self):
   189     def test_complex_base(self):
   190         """
   190         """
   191         1. retrieve Any X, L WHERE X is CWUser, X login L from system and ldap sources, store
   191         1. retrieve Any X, L WHERE X is CWUser, X login L from system and ldap sources, store
   192            concatenation of results into a temporary table
   192            concatenation of results into a temporary table
   193         2. return the result of Any X, L WHERE X is TMP, X login L, X in_group G,
   193         2. return the result of Any X, L WHERE X is TMP, X login L, X in_group G,
   200     def test_complex_invariant_ordered(self):
   200     def test_complex_invariant_ordered(self):
   201         """
   201         """
   202         1. retrieve Any X,AA WHERE X modification_date AA from system and ldap sources, store
   202         1. retrieve Any X,AA WHERE X modification_date AA from system and ldap sources, store
   203            concatenation of results into a temporary table
   203            concatenation of results into a temporary table
   204         2. return the result of Any X,AA ORDERBY AA WHERE %s owned_by X, X modification_date AA
   204         2. return the result of Any X,AA ORDERBY AA WHERE %s owned_by X, X modification_date AA
   205            on the system source   
   205            on the system source
   206         """
   206         """
   207         ueid = self.session.user.eid
   207         ueid = self.session.user.eid
   208         self._test('Any X,AA ORDERBY AA WHERE E eid %(x)s, E owned_by X, X modification_date AA', {'x': ueid},
   208         self._test('Any X,AA ORDERBY AA WHERE E eid %(x)s, E owned_by X, X modification_date AA', {'x': ueid},
   209                    {self.system: {'x': s[0], 'X': s[0], 'owned_by': s[0]},
   209                    {self.system: {'x': s[0], 'X': s[0], 'owned_by': s[0]},
   210                     self.ldap : {'X': s[0]}}, True)
   210                     self.ldap : {'X': s[0]}}, True)
   212     def test_complex_invariant(self):
   212     def test_complex_invariant(self):
   213         """
   213         """
   214         1. retrieve Any X,L,AA WHERE X login L, X modification_date AA from system and ldap sources, store
   214         1. retrieve Any X,L,AA WHERE X login L, X modification_date AA from system and ldap sources, store
   215            concatenation of results into a temporary table
   215            concatenation of results into a temporary table
   216         2. return the result of Any X,L,AA WHERE %s owned_by X, X login L, X modification_date AA
   216         2. return the result of Any X,L,AA WHERE %s owned_by X, X login L, X modification_date AA
   217            on the system source   
   217            on the system source
   218         """
   218         """
   219         ueid = self.session.user.eid
   219         ueid = self.session.user.eid
   220         self._test('Any X,L,AA WHERE E eid %(x)s, E owned_by X, X login L, X modification_date AA', {'x': ueid},
   220         self._test('Any X,L,AA WHERE E eid %(x)s, E owned_by X, X login L, X modification_date AA', {'x': ueid},
   221                    {self.system: {'x': s[0], 'X': s[0], 'owned_by': s[0]},
   221                    {self.system: {'x': s[0], 'X': s[0], 'owned_by': s[0]},
   222                     self.ldap : {'X': s[0]}}, True)
   222                     self.ldap : {'X': s[0]}}, True)
   231     def test_complex_multiple(self):
   231     def test_complex_multiple(self):
   232         """
   232         """
   233         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   233         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   234            cartesian product of results into a temporary table
   234            cartesian product of results into a temporary table
   235         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   235         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   236            on the system source   
   236            on the system source
   237         """
   237         """
   238         ueid = self.session.user.eid
   238         ueid = self.session.user.eid
   239         self._test('Any X,Y WHERE X login "syt", Y login "adim"', {'x': ueid},
   239         self._test('Any X,Y WHERE X login "syt", Y login "adim"', {'x': ueid},
   240                    {self.system: {'Y': s[0], 'X': s[0]},
   240                    {self.system: {'Y': s[0], 'X': s[0]},
   241                     self.ldap: {'Y': s[0], 'X': s[0]}}, True)
   241                     self.ldap: {'Y': s[0], 'X': s[0]}}, True)
   242         
   242 
   243     def test_complex_aggregat(self):
   243     def test_complex_aggregat(self):
   244         solindexes = set(range(len([e for e in self.schema.entities() if not e.is_final()])))
   244         solindexes = set(range(len([e for e in self.schema.entities() if not e.is_final()])))
   245         self._test('Any MAX(X)',
   245         self._test('Any MAX(X)',
   246                    {self.system: {'X': solindexes}}, False)
   246                    {self.system: {'X': solindexes}}, False)
   247                    
   247 
   248     def test_complex_optional(self):
   248     def test_complex_optional(self):
   249         ueid = self.session.user.eid
   249         ueid = self.session.user.eid
   250         self._test('Any U WHERE WF wf_info_for X, X eid %(x)s, WF owned_by U?, WF from_state FS', {'x': ueid},
   250         self._test('Any U WHERE WF wf_info_for X, X eid %(x)s, WF owned_by U?, WF from_state FS', {'x': ueid},
   251                    {self.system: {'WF': s[0], 'FS': s[0], 'U': s[0],
   251                    {self.system: {'WF': s[0], 'FS': s[0], 'U': s[0],
   252                                   'from_state': s[0], 'owned_by': s[0], 'wf_info_for': s[0],
   252                                   'from_state': s[0], 'owned_by': s[0], 'wf_info_for': s[0],
   253                                   'x': s[0]}},
   253                                   'x': s[0]}},
   254                    False)
   254                    False)
   255         
   255 
   256     def test_exists4(self):
   256     def test_exists4(self):
   257         """
   257         """
   258         State S could come from both rql source and system source,
   258         State S could come from both rql source and system source,
   259         but since X cannot come from the rql source, the solution
   259         but since X cannot come from the rql source, the solution
   260         {self.rql : 'S'} must be removed
   260         {self.rql : 'S'} must be removed
   261         """
   261         """
   262         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", '
   263                    '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 '
   264                    '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")',
   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]}, 
   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]},
   266                     self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}},
   266                     self.ldap: {'X': s[0], 'T2': s[0], 'T': s[0]}},
   267                    True)
   267                    True)
   268 
   268 
   269     def test_relation_need_split(self):
   269     def test_relation_need_split(self):
   270         self._test('Any X, S WHERE X in_state S',
   270         self._test('Any X, S WHERE X in_state S',
   271                    {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]},
   272                     self.rql: {'X': s[2], 'S': s[2]}},
   272                     self.rql: {'X': s[2], 'S': s[2]}},
   273                    True)
   273                    True)
   274         
   274 
   275     def test_not_relation_need_split(self):
   275     def test_not_relation_need_split(self):
   276         self._test('Any SN WHERE NOT X in_state S, S name SN',
   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]},
   277                    {self.rql: {'X': s[2], 'S': s[0, 1, 2]},
   278                     self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]}},
   278                     self.system: {'X': s[0, 1, 2], 'S': s[0, 1, 2]}},
   279                    True)
   279                    True)
   280         
   280 
   281     def test_not_relation_no_split_external(self):
   281     def test_not_relation_no_split_external(self):
   282         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   282         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   283         # similar to the above test but with an eid coming from the external source.
   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
   284         # the same plan may be used, since we won't find any record in the system source
   285         # linking 9999999 to a state 
   285         # linking 9999999 to a state
   286         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
   286         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
   287                    {'x': 999999},
   287                    {'x': 999999},
   288                    {self.rql: {'x': s[0], 'S': s[0]},
   288                    {self.rql: {'x': s[0], 'S': s[0]},
   289                     self.system: {'x': s[0], 'S': s[0]}},
   289                     self.system: {'x': s[0], 'S': s[0]}},
   290                    False)
   290                    False)
   301                    {'x': 999999, 'u': self.session.user.eid},
   301                    {'x': 999999, 'u': self.session.user.eid},
   302                    {self.system: {'P': s[0], 'G': s[0], 'X': s[0],
   302                    {self.system: {'P': s[0], 'G': s[0], 'X': s[0],
   303                                   'require_permission': s[0], 'in_group': s[0], 'P': s[0], 'require_group': s[0],
   303                                   'require_permission': s[0], 'in_group': s[0], 'P': s[0], 'require_group': s[0],
   304                                   'u': s[0]}},
   304                                   'u': s[0]}},
   305                    False)
   305                    False)
   306         
   306 
   307     def test_delete_relation1(self):
   307     def test_delete_relation1(self):
   308         ueid = self.session.user.eid
   308         ueid = self.session.user.eid
   309         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',
   310                    {'x': ueid, 'y': ueid},
   310                    {'x': ueid, 'y': ueid},
   311                    {self.system: {'Y': s[0], 'created_by': s[0], 'x': s[0]}},
   311                    {self.system: {'Y': s[0], 'created_by': s[0], 'x': s[0]}},
   316         ueid = self.session.user.eid
   316         ueid = self.session.user.eid
   317         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',
   318                    {'x': 999999,},
   318                    {'x': 999999,},
   319                    {self.rql: {'Y': s[0]}, self.system: {'Y': s[0], 'x': s[0]}},
   319                    {self.rql: {'Y': s[0]}, self.system: {'Y': s[0], 'x': s[0]}},
   320                    True)
   320                    True)
   321         
   321 
   322     def test_crossed_relation_eid_1_invariant(self):
   322     def test_crossed_relation_eid_1_invariant(self):
   323         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   323         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   324         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',
   325                    {'x': 999999},
   325                    {'x': 999999},
   326                    {self.system: {'Y': s[0], 'x': s[0]}},
   326                    {self.system: {'Y': s[0], 'x': s[0]}},
   339         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',
   340                    {'x': 999999},
   340                    {'x': 999999},
   341                    {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]},
   342                     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]}},
   343                    True)
   343                    True)
   344         
   344 
   345     def test_version_crossed_depends_on_2(self):
   345     def test_version_crossed_depends_on_2(self):
   346         repo._type_source_cache[999999] = ('Note', 'system', 999999)
   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',
   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},
   348                    {'x': 999999},
   349                    {self.rql: {'X': s[0], 'AD': s[0]},
   349                    {self.rql: {'X': s[0], 'AD': s[0]},
   354         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   354         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
   355         repo._type_source_cache[999998] = ('State', 'cards', 999998)
   355         repo._type_source_cache[999998] = ('State', 'cards', 999998)
   356         self._test('Any S,T WHERE S eid %(s)s, N eid %(n)s, N type T, N is Note, S is State',
   356         self._test('Any S,T WHERE S eid %(s)s, N eid %(n)s, N type T, N is Note, S is State',
   357                    {'n': 999999, 's': 999998},
   357                    {'n': 999999, 's': 999998},
   358                    {self.rql: {'s': s[0], 'N': s[0]}}, False)
   358                    {self.rql: {'s': s[0], 'N': s[0]}}, False)
   359                    
   359 
   360 
   360 
   361         
   361 
   362 class MSPlannerTC(BaseMSPlannerTC):
   362 class MSPlannerTC(BaseMSPlannerTC):
   363     
   363 
   364     def setUp(self):
   364     def setUp(self):
   365         BaseMSPlannerTC.setUp(self)
   365         BaseMSPlannerTC.setUp(self)
   366         self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
   366         self.planner = MSPlanner(self.o.schema, self.o._rqlhelper)
   367 
   367 
   368     _test = test_plan
   368     _test = test_plan
   385         """retrieve entities only supported by the system source
   385         """retrieve entities only supported by the system source
   386         """
   386         """
   387         self._test('CWGroup X LIMIT 10 OFFSET 10',
   387         self._test('CWGroup X LIMIT 10 OFFSET 10',
   388                    [('OneFetchStep', [('Any X LIMIT 10 OFFSET 10 WHERE X is CWGroup', [{'X': 'CWGroup'}])],
   388                    [('OneFetchStep', [('Any X LIMIT 10 OFFSET 10 WHERE X is CWGroup', [{'X': 'CWGroup'}])],
   389                      10, 10, [self.system], {}, [])])
   389                      10, 10, [self.system], {}, [])])
   390         
   390 
   391     def test_simple_system_ldap(self):
   391     def test_simple_system_ldap(self):
   392         """retrieve CWUser X from both sources and return concatenation of results
   392         """retrieve CWUser X from both sources and return concatenation of results
   393         """
   393         """
   394         self._test('CWUser X',
   394         self._test('CWUser X',
   395                    [('OneFetchStep', [('Any X WHERE X is CWUser', [{'X': 'CWUser'}])],
   395                    [('OneFetchStep', [('Any X WHERE X is CWUser', [{'X': 'CWUser'}])],
   396                      None, None, [self.ldap, self.system], {}, [])])
   396                      None, None, [self.ldap, self.system], {}, [])])
   397         
   397 
   398     def test_simple_system_ldap_limit(self):
   398     def test_simple_system_ldap_limit(self):
   399         """retrieve CWUser X from both sources and return concatenation of results
   399         """retrieve CWUser X from both sources and return concatenation of results
   400         """
   400         """
   401         self._test('CWUser X LIMIT 10',
   401         self._test('CWUser X LIMIT 10',
   402                    [('OneFetchStep', [('Any X LIMIT 10 WHERE X is CWUser', [{'X': 'CWUser'}])],
   402                    [('OneFetchStep', [('Any X LIMIT 10 WHERE X is CWUser', [{'X': 'CWUser'}])],
   426                    [('AggrStep', 'Any COUNT(X)', None, None, 'table0', None, [
   426                    [('AggrStep', 'Any COUNT(X)', None, None, 'table0', None, [
   427                        ('FetchStep', [('Any COUNT(X) WHERE X is CWUser', [{'X': 'CWUser'}])],
   427                        ('FetchStep', [('Any COUNT(X) WHERE X is CWUser', [{'X': 'CWUser'}])],
   428                         [self.ldap, self.system], {}, {'COUNT(X)': 'table0.C0'}, []),
   428                         [self.ldap, self.system], {}, {'COUNT(X)': 'table0.C0'}, []),
   429                        ]),
   429                        ]),
   430                    ])
   430                    ])
   431         
   431 
   432     def test_simple_system_rql(self):
   432     def test_simple_system_rql(self):
   433         """retrieve Card X from both sources and return concatenation of results
   433         """retrieve Card X from both sources and return concatenation of results
   434         """
   434         """
   435         self._test('Any X, XT WHERE X is Card, X title XT',
   435         self._test('Any X, XT WHERE X is Card, X title XT',
   436                    [('OneFetchStep', [('Any X,XT WHERE X is Card, X title XT', [{'X': 'Card', 'XT': 'String'}])],
   436                    [('OneFetchStep', [('Any X,XT WHERE X is Card, X title XT', [{'X': 'Card', 'XT': 'String'}])],
   437                      None, None, [self.rql, self.system], {}, [])])
   437                      None, None, [self.rql, self.system], {}, [])])
   438         
   438 
   439     def test_simple_eid_specified(self):
   439     def test_simple_eid_specified(self):
   440         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   440         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   441         """
   441         """
   442         ueid = self.session.user.eid
   442         ueid = self.session.user.eid
   443         self._test('Any X,L WHERE X eid %(x)s, X login L',
   443         self._test('Any X,L WHERE X eid %(x)s, X login L',
   444                    [('OneFetchStep', [('Any X,L WHERE X eid %s, X login L'%ueid, [{'X': 'CWUser', 'L': 'String'}])],
   444                    [('OneFetchStep', [('Any X,L WHERE X eid %s, X login L'%ueid, [{'X': 'CWUser', 'L': 'String'}])],
   445                      None, None, [self.system], {}, [])],
   445                      None, None, [self.system], {}, [])],
   446                    {'x': ueid})
   446                    {'x': ueid})
   447         
   447 
   448     def test_simple_eid_invariant(self):
   448     def test_simple_eid_invariant(self):
   449         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   449         """retrieve CWUser X from system source (eid is specified, can locate the entity)
   450         """
   450         """
   451         ueid = self.session.user.eid
   451         ueid = self.session.user.eid
   452         self._test('Any X WHERE X eid %(x)s',
   452         self._test('Any X WHERE X eid %(x)s',
   453                    [('OneFetchStep', [('Any %s'%ueid, [{}])],
   453                    [('OneFetchStep', [('Any %s'%ueid, [{}])],
   454                      None, None, [self.system], {}, [])],
   454                      None, None, [self.system], {}, [])],
   455                    {'x': ueid})
   455                    {'x': ueid})
   456         
   456 
   457     def test_simple_invariant(self):
   457     def test_simple_invariant(self):
   458         """retrieve CWUser X from system source only (X is invariant and in_group not supported by ldap source)
   458         """retrieve CWUser X from system source only (X is invariant and in_group not supported by ldap source)
   459         """
   459         """
   460         self._test('Any X WHERE X is CWUser, X in_group G, G name "users"',
   460         self._test('Any X WHERE X is CWUser, X in_group G, G name "users"',
   461                    [('OneFetchStep', [('Any X WHERE X is CWUser, X in_group G, G name "users"',
   461                    [('OneFetchStep', [('Any X WHERE X is CWUser, X in_group G, G name "users"',
   462                                        [{'X': 'CWUser', 'G': 'CWGroup'}])],
   462                                        [{'X': 'CWUser', 'G': 'CWGroup'}])],
   463                      None, None, [self.system], {}, [])])
   463                      None, None, [self.system], {}, [])])
   464         
   464 
   465     def test_complex_base(self):
   465     def test_complex_base(self):
   466         """
   466         """
   467         1. retrieve Any X, L WHERE X is CWUser, X login L from system and ldap sources, store
   467         1. retrieve Any X, L WHERE X is CWUser, X login L from system and ldap sources, store
   468            concatenation of results into a temporary table
   468            concatenation of results into a temporary table
   469         2. return the result of Any X, L WHERE X is TMP, X login LX in_group G,
   469         2. return the result of Any X, L WHERE X is TMP, X login LX in_group G,
   496                      [self.system], {'X': 'table0.C0', 'X.login': 'table0.C1', 'L': 'table0.C1'}, [])
   496                      [self.system], {'X': 'table0.C0', 'X.login': 'table0.C1', 'L': 'table0.C1'}, [])
   497                     ])
   497                     ])
   498 
   498 
   499     def test_complex_ordered(self):
   499     def test_complex_ordered(self):
   500         self._test('Any L ORDERBY L WHERE X login L',
   500         self._test('Any L ORDERBY L WHERE X login L',
   501                    [('AggrStep', 'Any L ORDERBY L', None, None, 'table0', None, 
   501                    [('AggrStep', 'Any L ORDERBY L', None, None, 'table0', None,
   502                      [('FetchStep', [('Any L WHERE X login L, X is CWUser',
   502                      [('FetchStep', [('Any L WHERE X login L, X is CWUser',
   503                                       [{'X': 'CWUser', 'L': 'String'}])],
   503                                       [{'X': 'CWUser', 'L': 'String'}])],
   504                        [self.ldap, self.system], {}, {'X.login': 'table0.C0', 'L': 'table0.C0'}, []),
   504                        [self.ldap, self.system], {}, {'X.login': 'table0.C0', 'L': 'table0.C0'}, []),
   505                       ])
   505                       ])
   506                     ])
   506                     ])
   507 
   507 
   508     def test_complex_ordered_limit_offset(self):
   508     def test_complex_ordered_limit_offset(self):
   509         self._test('Any L ORDERBY L LIMIT 10 OFFSET 10 WHERE X login L',
   509         self._test('Any L ORDERBY L LIMIT 10 OFFSET 10 WHERE X login L',
   510                    [('AggrStep', 'Any L ORDERBY L', 10, 10, 'table0', None, 
   510                    [('AggrStep', 'Any L ORDERBY L', 10, 10, 'table0', None,
   511                      [('FetchStep', [('Any L WHERE X login L, X is CWUser',
   511                      [('FetchStep', [('Any L WHERE X login L, X is CWUser',
   512                                       [{'X': 'CWUser', 'L': 'String'}])],
   512                                       [{'X': 'CWUser', 'L': 'String'}])],
   513                        [self.ldap, self.system], {}, {'X.login': 'table0.C0', 'L': 'table0.C0'}, []),
   513                        [self.ldap, self.system], {}, {'X.login': 'table0.C0', 'L': 'table0.C0'}, []),
   514                       ])
   514                       ])
   515                     ])
   515                     ])
   516         
   516 
   517     def test_complex_invariant_ordered(self):
   517     def test_complex_invariant_ordered(self):
   518         """
   518         """
   519         1. retrieve Any X,AA WHERE X modification_date AA from system and ldap sources, store
   519         1. retrieve Any X,AA WHERE X modification_date AA from system and ldap sources, store
   520            concatenation of results into a temporary table
   520            concatenation of results into a temporary table
   521         2. return the result of Any X,AA ORDERBY AA WHERE %s owned_by X, X modification_date AA
   521         2. return the result of Any X,AA ORDERBY AA WHERE %s owned_by X, X modification_date AA
   541     def test_complex_invariant(self):
   541     def test_complex_invariant(self):
   542         """
   542         """
   543         1. retrieve Any X,L,AA WHERE X login L, X modification_date AA from system and ldap sources, store
   543         1. retrieve Any X,L,AA WHERE X login L, X modification_date AA from system and ldap sources, store
   544            concatenation of results into a temporary table
   544            concatenation of results into a temporary table
   545         2. return the result of Any X,L,AA WHERE %s owned_by X, X login L, X modification_date AA
   545         2. return the result of Any X,L,AA WHERE %s owned_by X, X login L, X modification_date AA
   546            on the system source   
   546            on the system source
   547         """
   547         """
   548         ueid = self.session.user.eid
   548         ueid = self.session.user.eid
   549         self._test('Any X,L,AA WHERE E eid %(x)s, E owned_by X, X login L, X modification_date AA',
   549         self._test('Any X,L,AA WHERE E eid %(x)s, E owned_by X, X login L, X modification_date AA',
   550                    [('FetchStep', [('Any X,L,AA WHERE X login L, X modification_date AA, X is CWUser',
   550                    [('FetchStep', [('Any X,L,AA WHERE X login L, X modification_date AA, X is CWUser',
   551                                     [{'AA': 'Datetime', 'X': 'CWUser', 'L': 'String'}])],
   551                                     [{'AA': 'Datetime', 'X': 'CWUser', 'L': 'String'}])],
   591         1. retrieve CWUser X from system and ldap sources, Person X from system source only, store
   591         1. retrieve CWUser X from system and ldap sources, Person X from system source only, store
   592            each result in the same temp table
   592            each result in the same temp table
   593         2. return content of the table sorted
   593         2. return content of the table sorted
   594         """
   594         """
   595         self._test('Any X,F ORDERBY F WHERE X firstname F',
   595         self._test('Any X,F ORDERBY F WHERE X firstname F',
   596                    [('AggrStep', 'Any X,F ORDERBY F', None, None, 'table0', None, 
   596                    [('AggrStep', 'Any X,F ORDERBY F', None, None, 'table0', None,
   597                      [('FetchStep', [('Any X,F WHERE X firstname F, X is CWUser',
   597                      [('FetchStep', [('Any X,F WHERE X firstname F, X is CWUser',
   598                                       [{'X': 'CWUser', 'F': 'String'}])],
   598                                       [{'X': 'CWUser', 'F': 'String'}])],
   599                        [self.ldap, self.system], {},
   599                        [self.ldap, self.system], {},
   600                        {'X': 'table0.C0', 'X.firstname': 'table0.C1', 'F': 'table0.C1'}, []),
   600                        {'X': 'table0.C0', 'X.firstname': 'table0.C1', 'F': 'table0.C1'}, []),
   601                       ('FetchStep', [('Any X,F WHERE X firstname F, X is Personne',
   601                       ('FetchStep', [('Any X,F WHERE X firstname F, X is Personne',
   602                                       [{'X': 'Personne', 'F': 'String'}])],
   602                                       [{'X': 'Personne', 'F': 'String'}])],
   603                        [self.system], {},
   603                        [self.system], {},
   604                        {'X': 'table0.C0', 'X.firstname': 'table0.C1', 'F': 'table0.C1'}, []),
   604                        {'X': 'table0.C0', 'X.firstname': 'table0.C1', 'F': 'table0.C1'}, []),
   605                       ]),
   605                       ]),
   606                     ])
   606                     ])
   607         
   607 
   608     def test_complex_multiple(self):
   608     def test_complex_multiple(self):
   609         """
   609         """
   610         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   610         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   611            cartesian product of results into a temporary table
   611            cartesian product of results into a temporary table
   612         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   612         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   613            on the system source   
   613            on the system source
   614         """
   614         """
   615         ueid = self.session.user.eid
   615         ueid = self.session.user.eid
   616         self._test('Any X,Y WHERE X login "syt", Y login "adim"',
   616         self._test('Any X,Y WHERE X login "syt", Y login "adim"',
   617                    [('FetchStep',
   617                    [('FetchStep',
   618                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
   618                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
   625                     ('OneFetchStep',
   625                     ('OneFetchStep',
   626                      [('Any X,Y WHERE X is CWUser, Y is CWUser', [{'X': 'CWUser', 'Y': 'CWUser'}])],
   626                      [('Any X,Y WHERE X is CWUser, Y is CWUser', [{'X': 'CWUser', 'Y': 'CWUser'}])],
   627                      None, None, [self.system],
   627                      None, None, [self.system],
   628                      {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
   628                      {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
   629                     ], {'x': ueid})
   629                     ], {'x': ueid})
   630         
   630 
   631     def test_complex_multiple_limit_offset(self):
   631     def test_complex_multiple_limit_offset(self):
   632         """
   632         """
   633         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   633         1. retrieve Any X,A,Y,B WHERE X login A, Y login B from system and ldap sources, store
   634            cartesian product of results into a temporary table
   634            cartesian product of results into a temporary table
   635         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   635         2. return the result of Any X,Y WHERE X login 'syt', Y login 'adim'
   636            on the system source   
   636            on the system source
   637         """
   637         """
   638         ueid = self.session.user.eid
   638         ueid = self.session.user.eid
   639         self._test('Any X,Y LIMIT 10 OFFSET 10 WHERE X login "syt", Y login "adim"',
   639         self._test('Any X,Y LIMIT 10 OFFSET 10 WHERE X login "syt", Y login "adim"',
   640                    [('FetchStep',
   640                    [('FetchStep',
   641                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
   641                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
   646                     ('OneFetchStep',
   646                     ('OneFetchStep',
   647                      [('Any X,Y LIMIT 10 OFFSET 10 WHERE X is CWUser, Y is CWUser', [{'X': 'CWUser', 'Y': 'CWUser'}])],
   647                      [('Any X,Y LIMIT 10 OFFSET 10 WHERE X is CWUser, Y is CWUser', [{'X': 'CWUser', 'Y': 'CWUser'}])],
   648                      10, 10, [self.system],
   648                      10, 10, [self.system],
   649                      {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
   649                      {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
   650                     ], {'x': ueid})
   650                     ], {'x': ueid})
   651         
   651 
   652     def test_complex_aggregat(self):
   652     def test_complex_aggregat(self):
   653         self._test('Any MAX(X)',
   653         self._test('Any MAX(X)',
   654                    [('OneFetchStep',
   654                    [('OneFetchStep',
   655                      [('Any MAX(X)', X_ALL_SOLS)],
   655                      [('Any MAX(X)', X_ALL_SOLS)],
   656                      None, None, [self.system], {}, [])
   656                      None, None, [self.system], {}, [])
   657                     ])
   657                     ])
   658         
   658 
   659     def test_complex_typed_aggregat(self):
   659     def test_complex_typed_aggregat(self):
   660         self._test('Any MAX(X) WHERE X is Card',
   660         self._test('Any MAX(X) WHERE X is Card',
   661                    [('AggrStep', 'Any MAX(X)', None, None, 'table0',  None,
   661                    [('AggrStep', 'Any MAX(X)', None, None, 'table0',  None,
   662                      [('FetchStep',
   662                      [('FetchStep',
   663                        [('Any MAX(X) WHERE X is Card', [{'X': 'Card'}])],
   663                        [('Any MAX(X) WHERE X is Card', [{'X': 'Card'}])],
   664                        [self.rql, self.system], {}, {'MAX(X)': 'table0.C0'}, [])
   664                        [self.rql, self.system], {}, {'MAX(X)': 'table0.C0'}, [])
   665                       ])
   665                       ])
   666                     ])
   666                     ])
   667         
   667 
   668     def test_complex_greater_eid(self):
   668     def test_complex_greater_eid(self):
   669         self._test('Any X WHERE X eid > 12',
   669         self._test('Any X WHERE X eid > 12',
   670                    [('OneFetchStep',
   670                    [('OneFetchStep',
   671                      [('Any X WHERE X eid > 12', X_ALL_SOLS)],
   671                      [('Any X WHERE X eid > 12', X_ALL_SOLS)],
   672                      None, None, [self.system], {}, [])
   672                      None, None, [self.system], {}, [])
   673                     ])
   673                     ])
   674         
   674 
   675     def test_complex_greater_typed_eid(self):
   675     def test_complex_greater_typed_eid(self):
   676         self._test('Any X WHERE X eid > 12, X is Card',
   676         self._test('Any X WHERE X eid > 12, X is Card',
   677                    [('OneFetchStep',
   677                    [('OneFetchStep',
   678                      [('Any X WHERE X eid > 12, X is Card', [{'X': 'Card'}])],
   678                      [('Any X WHERE X eid > 12, X is Card', [{'X': 'Card'}])],
   679                      None, None, [self.system], {}, [])
   679                      None, None, [self.system], {}, [])
   680                     ])
   680                     ])
   681         
   681 
   682     def test_complex_optional(self):
   682     def test_complex_optional(self):
   683         ueid = self.session.user.eid
   683         ueid = self.session.user.eid
   684         self._test('Any U WHERE WF wf_info_for X, X eid %(x)s, WF owned_by U?, WF from_state FS',
   684         self._test('Any U WHERE WF wf_info_for X, X eid %(x)s, WF owned_by U?, WF from_state FS',
   685                    [('OneFetchStep', [('Any U WHERE WF wf_info_for 5, WF owned_by U?, WF from_state FS',
   685                    [('OneFetchStep', [('Any U WHERE WF wf_info_for 5, WF owned_by U?, WF from_state FS',
   686                                        [{'WF': 'TrInfo', 'FS': 'State', 'U': 'CWUser'}])],
   686                                        [{'WF': 'TrInfo', 'FS': 'State', 'U': 'CWUser'}])],
   693                    [('OneFetchStep', [('Any U WHERE WF wf_info_for 5, WF owned_by U?, WF from_state FS',
   693                    [('OneFetchStep', [('Any U WHERE WF wf_info_for 5, WF owned_by U?, WF from_state FS',
   694                                        [{'WF': 'TrInfo', 'FS': 'State', 'U': 'CWUser'}])],
   694                                        [{'WF': 'TrInfo', 'FS': 'State', 'U': 'CWUser'}])],
   695                      None, None, [self.system], {}, [])],
   695                      None, None, [self.system], {}, [])],
   696                    {'x': ueid})
   696                    {'x': ueid})
   697 
   697 
   698     
   698 
   699     def test_3sources_ambigous(self):
   699     def test_3sources_ambigous(self):
   700         self._test('Any X,T WHERE X owned_by U, U login "syt", X title T',
   700         self._test('Any X,T WHERE X owned_by U, U login "syt", X title T',
   701                    [('FetchStep', [('Any X,T WHERE X title T, X is Card', [{'X': 'Card', 'T': 'String'}])],
   701                    [('FetchStep', [('Any X,T WHERE X title T, X is Card', [{'X': 'Card', 'T': 'String'}])],
   702                      [self.rql, self.system], None,
   702                      [self.rql, self.system], None,
   703                      {'T': 'table0.C1', 'X': 'table0.C0', 'X.title': 'table0.C1'}, []),
   703                      {'T': 'table0.C1', 'X': 'table0.C0', 'X.title': 'table0.C1'}, []),
   734                      None, None, [self.system],
   734                      None, None, [self.system],
   735                      {'VR': 'table1.C1', 'V': 'table1.C0', 'V.creation_date': 'table1.C1', 'X.creation_date': 'table0.C0'}, [])
   735                      {'VR': 'table1.C1', 'V': 'table1.C0', 'V.creation_date': 'table1.C1', 'X.creation_date': 'table0.C0'}, [])
   736                     ])
   736                     ])
   737 
   737 
   738     def test_outer_supported_rel1(self):
   738     def test_outer_supported_rel1(self):
   739         # both system and rql support all variables, can be 
   739         # both system and rql support all variables, can be
   740         self._test('Any X, R WHERE X is Note, X in_state S, X type R, '
   740         self._test('Any X, R WHERE X is Note, X in_state S, X type R, '
   741                    'NOT EXISTS(Y is Note, Y in_state S, Y type R, X identity Y)',
   741                    'NOT EXISTS(Y is Note, Y in_state S, Y type R, X identity Y)',
   742                    [('OneFetchStep', [('Any X,R WHERE X is Note, X in_state S, X type R, NOT EXISTS(Y is Note, Y in_state S, Y type R, X identity Y), S is State',
   742                    [('OneFetchStep', [('Any X,R WHERE X is Note, X in_state S, X type R, NOT EXISTS(Y is Note, Y in_state S, Y type R, X identity Y), S is State',
   743                                        [{'Y': 'Note', 'X': 'Note', 'S': 'State', 'R': 'String'}])],
   743                                        [{'Y': 'Note', 'X': 'Note', 'S': 'State', 'R': 'String'}])],
   744                      None, None,
   744                      None, None,
   745                      [self.rql, self.system], {}, [])
   745                      [self.rql, self.system], {}, [])
   746                     ])
   746                     ])
   747 
   747 
   748     def test_not_identity(self):
   748     def test_not_identity(self):
   749         # both system and rql support all variables, can be 
   749         # both system and rql support all variables, can be
   750         self._test('Any X WHERE NOT X identity U, U eid %s' % self.session.user.eid,
   750         self._test('Any X WHERE NOT X identity U, U eid %s' % self.session.user.eid,
   751                    [('OneFetchStep',
   751                    [('OneFetchStep',
   752                      [('Any X WHERE NOT X identity 5, X is CWUser', [{'X': 'CWUser'}])],
   752                      [('Any X WHERE NOT X identity 5, X is CWUser', [{'X': 'CWUser'}])],
   753                      None, None,
   753                      None, None,
   754                      [self.ldap, self.system], {}, [])
   754                      [self.ldap, self.system], {}, [])
   767                     ('OneFetchStep', [('Any X,MAX(R) GROUPBY X WHERE X in_state S, X login R, NOT EXISTS(Y type R, S identity A, A is State, Y is Note), S is State, X is CWUser',
   767                     ('OneFetchStep', [('Any X,MAX(R) GROUPBY X WHERE X in_state S, X login R, NOT EXISTS(Y type R, S identity A, A is State, Y is Note), S is State, X is CWUser',
   768                                        [{'Y': 'Note', 'X': 'CWUser', 'S': 'State', 'R': 'String', 'A': 'State'}])],
   768                                        [{'Y': 'Note', 'X': 'CWUser', 'S': 'State', 'R': 'String', 'A': 'State'}])],
   769                      None, None, [self.system],
   769                      None, None, [self.system],
   770                      {'A': 'table0.C0', 'X': 'table1.C0', 'X.login': 'table1.C1', 'R': 'table1.C1', 'Y.type': 'table0.C1'}, [])
   770                      {'A': 'table0.C0', 'X': 'table1.C0', 'X.login': 'table1.C1', 'R': 'table1.C1', 'Y.type': 'table0.C1'}, [])
   771                     ])
   771                     ])
   772             
   772 
   773     def test_security_has_text(self):
   773     def test_security_has_text(self):
   774         # use a guest user
   774         # use a guest user
   775         self.session = self._user_session()[1]
   775         self.session = self._user_session()[1]
   776         self._test('Any X WHERE X has_text "bla"',
   776         self._test('Any X WHERE X has_text "bla"',
   777                    [('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   777                    [('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   793                           {'X': 'Personne'}, {'X': 'Societe'}, {'X': 'State'},
   793                           {'X': 'Personne'}, {'X': 'Societe'}, {'X': 'State'},
   794                           {'X': 'SubDivision'}, {'X': 'Tag'}, {'X': 'Transition'}]),],
   794                           {'X': 'SubDivision'}, {'X': 'Tag'}, {'X': 'Transition'}]),],
   795                        None, None, [self.system], {}, []),
   795                        None, None, [self.system], {}, []),
   796                       ])
   796                       ])
   797                      ])
   797                      ])
   798         
   798 
   799     def test_security_has_text_limit_offset(self):
   799     def test_security_has_text_limit_offset(self):
   800         # use a guest user
   800         # use a guest user
   801         self.session = self._user_session()[1]
   801         self.session = self._user_session()[1]
   802         # note: same as the above query but because of the subquery usage, the display differs (not printing solutions for each union)
   802         # note: same as the above query but because of the subquery usage, the display differs (not printing solutions for each union)
   803         self._test('Any X LIMIT 10 OFFSET 10 WHERE X has_text "bla"',
   803         self._test('Any X LIMIT 10 OFFSET 10 WHERE X has_text "bla"',
   826                         {'X': 'Comment'}, {'X': 'Division'}, {'X': 'CWUser'},
   826                         {'X': 'Comment'}, {'X': 'Division'}, {'X': 'CWUser'},
   827                         {'X': 'Email'}, {'X': 'EmailThread'}, {'X': 'File'},
   827                         {'X': 'Email'}, {'X': 'EmailThread'}, {'X': 'File'},
   828                         {'X': 'Folder'}, {'X': 'Image'}, {'X': 'Note'},
   828                         {'X': 'Folder'}, {'X': 'Image'}, {'X': 'Note'},
   829                         {'X': 'Personne'}, {'X': 'Societe'}, {'X': 'State'},
   829                         {'X': 'Personne'}, {'X': 'Societe'}, {'X': 'State'},
   830                         {'X': 'SubDivision'}, {'X': 'Tag'}, {'X': 'Transition'}])],
   830                         {'X': 'SubDivision'}, {'X': 'Tag'}, {'X': 'Transition'}])],
   831                      10, 10, [self.system], {'X': 'table0.C0'}, [])                    
   831                      10, 10, [self.system], {'X': 'table0.C0'}, [])
   832                      ])
   832                      ])
   833         
   833 
   834     def test_security_user(self):
   834     def test_security_user(self):
   835         """a guest user trying to see another user: EXISTS(X owned_by U) is automatically inserted"""
   835         """a guest user trying to see another user: EXISTS(X owned_by U) is automatically inserted"""
   836         # use a guest user
   836         # use a guest user
   837         self.session = self._user_session()[1]
   837         self.session = self._user_session()[1]
   838         self._test('Any X WHERE X login "bla"',
   838         self._test('Any X WHERE X login "bla"',
   840                      [('Any X WHERE X login "bla", X is CWUser', [{'X': 'CWUser'}])],
   840                      [('Any X WHERE X login "bla", X is CWUser', [{'X': 'CWUser'}])],
   841                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
   841                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
   842                     ('OneFetchStep',
   842                     ('OneFetchStep',
   843                      [('Any X WHERE EXISTS(X owned_by 5), X is CWUser', [{'X': 'CWUser'}])],
   843                      [('Any X WHERE EXISTS(X owned_by 5), X is CWUser', [{'X': 'CWUser'}])],
   844                      None, None, [self.system], {'X': 'table0.C0'}, [])])
   844                      None, None, [self.system], {'X': 'table0.C0'}, [])])
   845                 
   845 
   846     def test_security_complex_has_text(self):
   846     def test_security_complex_has_text(self):
   847         # use a guest user
   847         # use a guest user
   848         self.session = self._user_session()[1]
   848         self.session = self._user_session()[1]
   849         self._test('Any X WHERE X has_text "bla", X firstname "bla"',
   849         self._test('Any X WHERE X has_text "bla", X firstname "bla"',
   850                    [('FetchStep', [('Any X WHERE X firstname "bla", X is CWUser', [{'X': 'CWUser'}])],
   850                    [('FetchStep', [('Any X WHERE X firstname "bla", X is CWUser', [{'X': 'CWUser'}])],
   877     def test_security_complex_aggregat(self):
   877     def test_security_complex_aggregat(self):
   878         # use a guest user
   878         # use a guest user
   879         self.session = self._user_session()[1]
   879         self.session = self._user_session()[1]
   880         self._test('Any MAX(X)',
   880         self._test('Any MAX(X)',
   881                    [('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   881                    [('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   882                      [self.rql, self.system],  None, {'E': 'table1.C0'}, []), 
   882                      [self.rql, self.system],  None, {'E': 'table1.C0'}, []),
   883                     ('FetchStep', [('Any X WHERE X is CWUser', [{'X': 'CWUser'}])],
   883                     ('FetchStep', [('Any X WHERE X is CWUser', [{'X': 'CWUser'}])],
   884                      [self.ldap, self.system], None, {'X': 'table2.C0'}, []),
   884                      [self.ldap, self.system], None, {'X': 'table2.C0'}, []),
   885                     ('UnionFetchStep', [
   885                     ('UnionFetchStep', [
   886                         ('FetchStep', [('Any X WHERE EXISTS(X owned_by 5), X is Basket', [{'X': 'Basket'}])],
   886                         ('FetchStep', [('Any X WHERE EXISTS(X owned_by 5), X is Basket', [{'X': 'Basket'}])],
   887                           [self.system], {}, {'X': 'table0.C0'}, []),                        
   887                           [self.system], {}, {'X': 'table0.C0'}, []),
   888                         ('UnionFetchStep',
   888                         ('UnionFetchStep',
   889                          [('FetchStep', [('Any X WHERE X is IN(Card, Note, State)',
   889                          [('FetchStep', [('Any X WHERE X is IN(Card, Note, State)',
   890                                           [{'X': 'Card'}, {'X': 'Note'}, {'X': 'State'}])],
   890                                           [{'X': 'Card'}, {'X': 'Note'}, {'X': 'State'}])],
   891                            [self.rql, self.system], {}, {'X': 'table0.C0'}, []),
   891                            [self.rql, self.system], {}, {'X': 'table0.C0'}, []),
   892                           ('FetchStep',
   892                           ('FetchStep',
   893                            [('Any X WHERE X is IN(Bookmark, Comment, Division, CWCache, CWConstraint, CWConstraintType, CWEType, CWAttribute, CWGroup, CWRelation, CWPermission, CWProperty, CWRType, Email, EmailAddress, EmailPart, EmailThread, File, Folder, Image, Personne, RQLExpression, Societe, SubDivision, Tag, TrInfo, Transition)',
   893                            [('Any X WHERE X is IN(Bookmark, CWAttribute, CWCache, CWConstraint, CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, CWRelation, Comment, Division, Email, EmailAddress, EmailPart, EmailThread, File, Folder, Image, Personne, RQLExpression, Societe, SubDivision, Tag, TrInfo, Transition)',
   894                              sorted([{'X': 'Bookmark'}, {'X': 'Comment'}, {'X': 'Division'},
   894                              sorted([{'X': 'Bookmark'}, {'X': 'Comment'}, {'X': 'Division'},
   895                                       {'X': 'CWCache'}, {'X': 'CWConstraint'}, {'X': 'CWConstraintType'},
   895                                       {'X': 'CWCache'}, {'X': 'CWConstraint'}, {'X': 'CWConstraintType'},
   896                                       {'X': 'CWEType'}, {'X': 'CWAttribute'}, {'X': 'CWGroup'},
   896                                       {'X': 'CWEType'}, {'X': 'CWAttribute'}, {'X': 'CWGroup'},
   897                                       {'X': 'CWRelation'}, {'X': 'CWPermission'}, {'X': 'CWProperty'},
   897                                       {'X': 'CWRelation'}, {'X': 'CWPermission'}, {'X': 'CWProperty'},
   898                                       {'X': 'CWRType'}, {'X': 'Email'}, {'X': 'EmailAddress'},
   898                                       {'X': 'CWRType'}, {'X': 'Email'}, {'X': 'EmailAddress'},
   904                           ]),
   904                           ]),
   905                         ('FetchStep', [('Any X WHERE EXISTS(X owned_by 5), X is CWUser', [{'X': 'CWUser'}])],
   905                         ('FetchStep', [('Any X WHERE EXISTS(X owned_by 5), X is CWUser', [{'X': 'CWUser'}])],
   906                          [self.system], {'X': 'table2.C0'}, {'X': 'table0.C0'}, []),
   906                          [self.system], {'X': 'table2.C0'}, {'X': 'table0.C0'}, []),
   907                         ('FetchStep', [('Any X WHERE (EXISTS(X owned_by 5)) OR ((((EXISTS(D concerne C?, C owned_by 5, C type "X", X identity D, C is Division, D is Affaire)) OR (EXISTS(H concerne G?, G owned_by 5, G type "X", X identity H, G is SubDivision, H is Affaire))) OR (EXISTS(I concerne F?, F owned_by 5, F type "X", X identity I, F is Societe, I is Affaire))) OR (EXISTS(J concerne E?, E owned_by 5, X identity J, E is Note, J is Affaire))), X is Affaire',
   907                         ('FetchStep', [('Any X WHERE (EXISTS(X owned_by 5)) OR ((((EXISTS(D concerne C?, C owned_by 5, C type "X", X identity D, C is Division, D is Affaire)) OR (EXISTS(H concerne G?, G owned_by 5, G type "X", X identity H, G is SubDivision, H is Affaire))) OR (EXISTS(I concerne F?, F owned_by 5, F type "X", X identity I, F is Societe, I is Affaire))) OR (EXISTS(J concerne E?, E owned_by 5, X identity J, E is Note, J is Affaire))), X is Affaire',
   908                                         [{'C': 'Division', 'E': 'Note', 'D': 'Affaire', 'G': 'SubDivision', 'F': 'Societe', 'I': 'Affaire', 'H': 'Affaire', 'J': 'Affaire', 'X': 'Affaire'}])],
   908                                         [{'C': 'Division', 'E': 'Note', 'D': 'Affaire', 'G': 'SubDivision', 'F': 'Societe', 'I': 'Affaire', 'H': 'Affaire', 'J': 'Affaire', 'X': 'Affaire'}])],
   909                          [self.system], {'E': 'table1.C0'}, {'X': 'table0.C0'}, []),                        
   909                          [self.system], {'E': 'table1.C0'}, {'X': 'table0.C0'}, []),
   910                         ]),
   910                         ]),
   911                     ('OneFetchStep', [('Any MAX(X)', X_ALL_SOLS)],
   911                     ('OneFetchStep', [('Any MAX(X)', X_ALL_SOLS)],
   912                      None, None, [self.system], {'X': 'table0.C0'}, [])
   912                      None, None, [self.system], {'X': 'table0.C0'}, [])
   913                     ])
   913                     ])
   914             
   914 
   915     def test_security_complex_aggregat2(self):
   915     def test_security_complex_aggregat2(self):
   916         # use a guest user
   916         # use a guest user
   917         self.session = self._user_session()[1]
   917         self.session = self._user_session()[1]
   918         self._test('Any ET, COUNT(X) GROUPBY ET ORDERBY ET WHERE X is ET',                   
   918         self._test('Any ET, COUNT(X) GROUPBY ET ORDERBY ET WHERE X is ET',
   919                    [('FetchStep', [('Any X WHERE X is IN(Card, Note, State)',
   919                    [('FetchStep', [('Any X WHERE X is IN(Card, Note, State)',
   920                                     [{'X': 'Card'}, {'X': 'Note'}, {'X': 'State'}])],
   920                                     [{'X': 'Card'}, {'X': 'Note'}, {'X': 'State'}])],
   921                      [self.rql, self.system], None, {'X': 'table1.C0'}, []),
   921                      [self.rql, self.system], None, {'X': 'table1.C0'}, []),
   922                     ('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   922                     ('FetchStep', [('Any E WHERE E type "X", E is Note', [{'E': 'Note'}])],
   923                      [self.rql, self.system],  None, {'E': 'table2.C0'}, []),
   923                      [self.rql, self.system],  None, {'E': 'table2.C0'}, []),
   937                       ('FetchStep', [('Any ET,X WHERE X is ET, EXISTS(X owned_by 5), ET is CWEType, X is CWUser',
   937                       ('FetchStep', [('Any ET,X WHERE X is ET, EXISTS(X owned_by 5), ET is CWEType, X is CWUser',
   938                                       [{'ET': 'CWEType', 'X': 'CWUser'}])],
   938                                       [{'ET': 'CWEType', 'X': 'CWUser'}])],
   939                        [self.system], {'X': 'table3.C0'}, {'ET': 'table0.C0', 'X': 'table0.C1'}, []),
   939                        [self.system], {'X': 'table3.C0'}, {'ET': 'table0.C0', 'X': 'table0.C1'}, []),
   940                       # extra UnionFetchStep could be avoided but has no cost, so don't care
   940                       # extra UnionFetchStep could be avoided but has no cost, so don't care
   941                       ('UnionFetchStep',
   941                       ('UnionFetchStep',
   942                        [('FetchStep', [('Any ET,X WHERE X is ET, ET is CWEType, X is IN(Bookmark, Comment, Division, CWCache, CWConstraint, CWConstraintType, CWEType, CWAttribute, CWGroup, CWRelation, CWPermission, CWProperty, CWRType, Email, EmailAddress, EmailPart, EmailThread, File, Folder, Image, Personne, RQLExpression, Societe, SubDivision, Tag, TrInfo, Transition)',
   942                        [('FetchStep', [('Any ET,X WHERE X is ET, ET is CWEType, X is IN(Bookmark, CWAttribute, CWCache, CWConstraint, CWConstraintType, CWEType, CWGroup, CWPermission, CWProperty, CWRType, CWRelation, Comment, Division, Email, EmailAddress, EmailPart, EmailThread, File, Folder, Image, Personne, RQLExpression, Societe, SubDivision, Tag, TrInfo, Transition)',
   943                                         [{'X': 'Bookmark', 'ET': 'CWEType'}, {'X': 'Comment', 'ET': 'CWEType'},
   943                                         [{'X': 'Bookmark', 'ET': 'CWEType'}, {'X': 'Comment', 'ET': 'CWEType'},
   944                                          {'X': 'Division', 'ET': 'CWEType'}, {'X': 'CWCache', 'ET': 'CWEType'},
   944                                          {'X': 'Division', 'ET': 'CWEType'}, {'X': 'CWCache', 'ET': 'CWEType'},
   945                                          {'X': 'CWConstraint', 'ET': 'CWEType'}, {'X': 'CWConstraintType', 'ET': 'CWEType'},
   945                                          {'X': 'CWConstraint', 'ET': 'CWEType'}, {'X': 'CWConstraintType', 'ET': 'CWEType'},
   946                                          {'X': 'CWEType', 'ET': 'CWEType'}, {'X': 'CWAttribute', 'ET': 'CWEType'},
   946                                          {'X': 'CWEType', 'ET': 'CWEType'}, {'X': 'CWAttribute', 'ET': 'CWEType'},
   947                                          {'X': 'CWGroup', 'ET': 'CWEType'}, {'X': 'CWRelation', 'ET': 'CWEType'},
   947                                          {'X': 'CWGroup', 'ET': 'CWEType'}, {'X': 'CWRelation', 'ET': 'CWEType'},
  1052                      [('Any X,XT LIMIT 10 OFFSET 10 WHERE X owned_by U, X title XT, EXISTS(U owned_by 5), U is CWUser, X is Card',
  1052                      [('Any X,XT LIMIT 10 OFFSET 10 WHERE X owned_by U, X title XT, EXISTS(U owned_by 5), U is CWUser, X is Card',
  1053                        [{'X': 'Card', 'U': 'CWUser', 'XT': 'String'}])],
  1053                        [{'X': 'Card', 'U': 'CWUser', 'XT': 'String'}])],
  1054                      10, 10, [self.system],
  1054                      10, 10, [self.system],
  1055                      {'X': 'table0.C0', 'X.title': 'table0.C1', 'XT': 'table0.C1', 'U': 'table1.C0'}, [])
  1055                      {'X': 'table0.C0', 'X.title': 'table0.C1', 'XT': 'table0.C1', 'U': 'table1.C0'}, [])
  1056                     ])
  1056                     ])
  1057     
  1057 
  1058     def test_exists_base(self):
  1058     def test_exists_base(self):
  1059         self._test('Any X,L,S WHERE X in_state S, X login L, EXISTS(X in_group G, G name "bougloup")',
  1059         self._test('Any X,L,S WHERE X in_state S, X login L, EXISTS(X in_group G, G name "bougloup")',
  1060                    [('FetchStep', [('Any X,L WHERE X login L, X is CWUser', [{'X': 'CWUser', 'L': 'String'}])],
  1060                    [('FetchStep', [('Any X,L WHERE X login L, X is CWUser', [{'X': 'CWUser', 'L': 'String'}])],
  1061                      [self.ldap, self.system], None, {'X': 'table0.C0', 'X.login': 'table0.C1', 'L': 'table0.C1'}, []),
  1061                      [self.ldap, self.system], None, {'X': 'table0.C0', 'X.login': 'table0.C1', 'L': 'table0.C1'}, []),
  1062                     ('OneFetchStep', [("Any X,L,S WHERE X in_state S, X login L, "
  1062                     ('OneFetchStep', [("Any X,L,S WHERE X in_state S, X login L, "
  1126                     ('OneFetchStep', [('Any GN,L WHERE X in_group G, X login L, G name GN, EXISTS(X copain T, T is CWUser), NOT EXISTS(X copain T2, T2 is CWUser), G is CWGroup, X is CWUser',
  1126                     ('OneFetchStep', [('Any GN,L WHERE X in_group G, X login L, G name GN, EXISTS(X copain T, T is CWUser), NOT EXISTS(X copain T2, T2 is CWUser), G is CWGroup, X is CWUser',
  1127                        [{'G': 'CWGroup', 'GN': 'String', 'L': 'String', 'T': 'CWUser', 'T2': 'CWUser', 'X': 'CWUser'}])],
  1127                        [{'G': 'CWGroup', 'GN': 'String', 'L': 'String', 'T': 'CWUser', 'T2': 'CWUser', 'X': 'CWUser'}])],
  1128                      None, None, [self.system],
  1128                      None, None, [self.system],
  1129                      {'T': 'table0.C0', 'T2': 'table1.C0',
  1129                      {'T': 'table0.C0', 'T2': 'table1.C0',
  1130                       'X': 'table2.C1', 'X.login': 'table2.C0', 'L': 'table2.C0'}, [])])
  1130                       'X': 'table2.C1', 'X.login': 'table2.C0', 'L': 'table2.C0'}, [])])
  1131             
  1131 
  1132     def test_exists_security_no_invariant(self):
  1132     def test_exists_security_no_invariant(self):
  1133         ueid = self.session.user.eid
  1133         ueid = self.session.user.eid
  1134         self._test('Any X,AA,AB,AC,AD ORDERBY AA WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, A eid %(B)s, \
  1134         self._test('Any X,AA,AB,AC,AD ORDERBY AA WHERE X is CWUser, X login AA, X firstname AB, X surname AC, X modification_date AD, A eid %(B)s, \
  1135     EXISTS(((X identity A) OR \
  1135     EXISTS(((X identity A) OR \
  1136             (EXISTS(X in_group C, C name IN("managers", "staff"), C is CWGroup))) OR \
  1136             (EXISTS(X in_group C, C name IN("managers", "staff"), C is CWGroup))) OR \
  1157 
  1157 
  1158     def test_relation_need_split(self):
  1158     def test_relation_need_split(self):
  1159         self._test('Any X, S WHERE X in_state S',
  1159         self._test('Any X, S WHERE X in_state S',
  1160                    [('UnionStep', None, None, [
  1160                    [('UnionStep', None, None, [
  1161                        ('OneFetchStep', [('Any X,S WHERE X in_state S, S is State, X is IN(Affaire, CWUser)',
  1161                        ('OneFetchStep', [('Any X,S WHERE X in_state S, S is State, X is IN(Affaire, CWUser)',
  1162                                           [{'X': 'Affaire', 'S': 'State'}, {'X': 'CWUser', 'S': 'State'}])], 
  1162                                           [{'X': 'Affaire', 'S': 'State'}, {'X': 'CWUser', 'S': 'State'}])],
  1163                         None, None, [self.system], {}, []),
  1163                         None, None, [self.system], {}, []),
  1164                        ('OneFetchStep', [('Any X,S WHERE X in_state S, S is State, X is Note',
  1164                        ('OneFetchStep', [('Any X,S WHERE X in_state S, S is State, X is Note',
  1165                                           [{'X': 'Note', 'S': 'State'}])], 
  1165                                           [{'X': 'Note', 'S': 'State'}])],
  1166                         None, None, [self.rql, self.system], {}, []),
  1166                         None, None, [self.rql, self.system], {}, []),
  1167                     ])])
  1167                     ])])
  1168 
  1168 
  1169     def test_relation_selection_need_split(self):
  1169     def test_relation_selection_need_split(self):
  1170         self._test('Any X,S,U WHERE X in_state S, X todo_by U',
  1170         self._test('Any X,S,U WHERE X in_state S, X todo_by U',
  1221         # given eid. The "NOT X in_state S, X eid %(x)s" expression is necessarily true
  1221         # given eid. The "NOT X in_state S, X eid %(x)s" expression is necessarily true
  1222         # in the source where %(x)s is not coming from and will be removed during rql
  1222         # in the source where %(x)s is not coming from and will be removed during rql
  1223         # generation for the external source
  1223         # generation for the external source
  1224         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
  1224         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
  1225                    [('OneFetchStep', [('Any SN WHERE NOT 5 in_state S, S name SN, S is State',
  1225                    [('OneFetchStep', [('Any SN WHERE NOT 5 in_state S, S name SN, S is State',
  1226                                        [{'S': 'State', 'SN': 'String'}])], 
  1226                                        [{'S': 'State', 'SN': 'String'}])],
  1227                      None, None, [self.rql, self.system], {}, [])],
  1227                      None, None, [self.rql, self.system], {}, [])],
  1228                    {'x': ueid})
  1228                    {'x': ueid})
  1229 
  1229 
  1230     def test_not_relation_no_split_external(self):
  1230     def test_not_relation_no_split_external(self):
  1231         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1231         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1232         # similar to the above test but with an eid coming from the external source.
  1232         # similar to the above test but with an eid coming from the external source.
  1233         # the same plan may be used, since we won't find any record in the system source
  1233         # the same plan may be used, since we won't find any record in the system source
  1234         # linking 9999999 to a state 
  1234         # linking 9999999 to a state
  1235         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
  1235         self._test('Any SN WHERE NOT X in_state S, X eid %(x)s, S name SN',
  1236                    [('OneFetchStep', [('Any SN WHERE NOT 999999 in_state S, S name SN, S is State',
  1236                    [('OneFetchStep', [('Any SN WHERE NOT 999999 in_state S, S name SN, S is State',
  1237                                        [{'S': 'State', 'SN': 'String'}])], 
  1237                                        [{'S': 'State', 'SN': 'String'}])],
  1238                      None, None, [self.rql, self.system], {}, [])],
  1238                      None, None, [self.rql, self.system], {}, [])],
  1239                    {'x': 999999})
  1239                    {'x': 999999})
  1240 
  1240 
  1241     def test_not_relation_need_split(self):
  1241     def test_not_relation_need_split(self):
  1242         self._test('Any SN WHERE NOT X in_state S, S name SN',
  1242         self._test('Any SN WHERE NOT X in_state S, S name SN',
  1255                          [{'S': 'State', 'SN': 'String', 'X': 'Affaire'},
  1255                          [{'S': 'State', 'SN': 'String', 'X': 'Affaire'},
  1256                           {'S': 'State', 'SN': 'String', 'X': 'CWUser'}])],
  1256                           {'S': 'State', 'SN': 'String', 'X': 'CWUser'}])],
  1257                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1257                        None, None, [self.system], {'S': 'table0.C1', 'S.name': 'table0.C0', 'SN': 'table0.C0'},
  1258                        []),]
  1258                        []),]
  1259                      )])
  1259                      )])
  1260             
  1260 
  1261     def test_external_attributes_and_relation(self):
  1261     def test_external_attributes_and_relation(self):
  1262         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1262         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1263         self._test('Any A,B,C,D WHERE A eid %(x)s,A creation_date B,A modification_date C, A todo_by D?',
  1263         self._test('Any A,B,C,D WHERE A eid %(x)s,A creation_date B,A modification_date C, A todo_by D?',
  1264                    [('FetchStep', [('Any A,B,C WHERE A eid 999999, A creation_date B, A modification_date C, A is Note',
  1264                    [('FetchStep', [('Any A,B,C WHERE A eid 999999, A creation_date B, A modification_date C, A is Note',
  1265                                     [{'A': 'Note', 'C': 'Datetime', 'B': 'Datetime'}])],
  1265                                     [{'A': 'Note', 'C': 'Datetime', 'B': 'Datetime'}])],
  1285     def test_has_text(self):
  1285     def test_has_text(self):
  1286         self._test('Card X WHERE X has_text "toto"',
  1286         self._test('Card X WHERE X has_text "toto"',
  1287                    [('OneFetchStep', [('Any X WHERE X has_text "toto", X is Card',
  1287                    [('OneFetchStep', [('Any X WHERE X has_text "toto", X is Card',
  1288                                        [{'X': 'Card'}])],
  1288                                        [{'X': 'Card'}])],
  1289                      None, None, [self.system], {}, [])])
  1289                      None, None, [self.system], {}, [])])
  1290         
  1290 
  1291     def test_has_text_3(self):
  1291     def test_has_text_3(self):
  1292         self._test('Any X WHERE X has_text "toto", X title "zoubidou"',
  1292         self._test('Any X WHERE X has_text "toto", X title "zoubidou"',
  1293                    [('FetchStep', [(u'Any X WHERE X title "zoubidou", X is Card',
  1293                    [('FetchStep', [(u'Any X WHERE X title "zoubidou", X is Card',
  1294                                     [{'X': 'Card'}])],
  1294                                     [{'X': 'Card'}])],
  1295                      [self.rql, self.system], None, {'X': 'table0.C0'}, []),
  1295                      [self.rql, self.system], None, {'X': 'table0.C0'}, []),
  1300                         ('OneFetchStep', [(u'Any X WHERE X has_text "toto", X title "zoubidou", X is EmailThread',
  1300                         ('OneFetchStep', [(u'Any X WHERE X has_text "toto", X title "zoubidou", X is EmailThread',
  1301                                            [{'X': 'EmailThread'}])],
  1301                                            [{'X': 'EmailThread'}])],
  1302                          None, None, [self.system], {}, []),
  1302                          None, None, [self.system], {}, []),
  1303                         ]),
  1303                         ]),
  1304                     ])
  1304                     ])
  1305         
  1305 
  1306     def test_sort_func(self):
  1306     def test_sort_func(self):
  1307         self._test('Note X ORDERBY DUMB_SORT(RF) WHERE X type RF',
  1307         self._test('Note X ORDERBY DUMB_SORT(RF) WHERE X type RF',
  1308                    [('AggrStep', 'Any X ORDERBY DUMB_SORT(RF)', None, None, 'table0', None, [
  1308                    [('AggrStep', 'Any X ORDERBY DUMB_SORT(RF)', None, None, 'table0', None, [
  1309                        ('FetchStep', [('Any X,RF WHERE X type RF, X is Note',
  1309                        ('FetchStep', [('Any X,RF WHERE X type RF, X is Note',
  1310                                        [{'X': 'Note', 'RF': 'String'}])],
  1310                                        [{'X': 'Note', 'RF': 'String'}])],
  1360                       'Y': 'table1.C0', 'Y.title': 'table1.C1'}, [])
  1360                       'Y': 'table1.C0', 'Y.title': 'table1.C1'}, [])
  1361                     ])
  1361                     ])
  1362 
  1362 
  1363     def test_attr_unification_neq_1(self):
  1363     def test_attr_unification_neq_1(self):
  1364         self._test('Any X,Y WHERE X is Bookmark, Y is Card, X creation_date D, Y creation_date > D',
  1364         self._test('Any X,Y WHERE X is Bookmark, Y is Card, X creation_date D, Y creation_date > D',
  1365                    [('FetchStep', 
  1365                    [('FetchStep',
  1366                      [('Any Y,D WHERE Y creation_date > D, Y is Card',
  1366                      [('Any Y,D WHERE Y creation_date > D, Y is Card',
  1367                        [{'D': 'Datetime', 'Y': 'Card'}])],
  1367                        [{'D': 'Datetime', 'Y': 'Card'}])],
  1368                      [self.rql,self.system], None,
  1368                      [self.rql,self.system], None,
  1369                      {'D': 'table0.C1', 'Y': 'table0.C0', 'Y.creation_date': 'table0.C1'}, []),
  1369                      {'D': 'table0.C1', 'Y': 'table0.C0', 'Y.creation_date': 'table0.C1'}, []),
  1370                     ('OneFetchStep',
  1370                     ('OneFetchStep',
  1437                      None, None, [self.system], {}, [])],
  1437                      None, None, [self.system], {}, [])],
  1438                    {'x': 999999})
  1438                    {'x': 999999})
  1439 
  1439 
  1440 
  1440 
  1441     # external source w/ .cross_relations == ['multisource_crossed_rel'] ######
  1441     # external source w/ .cross_relations == ['multisource_crossed_rel'] ######
  1442     
  1442 
  1443     def test_crossed_relation_eid_1_invariant(self):
  1443     def test_crossed_relation_eid_1_invariant(self):
  1444         repo._type_source_cache[999999] = ('Note', 'system', 999999)
  1444         repo._type_source_cache[999999] = ('Note', 'system', 999999)
  1445         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
  1445         self._test('Any Y WHERE X eid %(x)s, X multisource_crossed_rel Y',
  1446                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y', [{u'Y': 'Note'}])],
  1446                    [('OneFetchStep', [('Any Y WHERE 999999 multisource_crossed_rel Y', [{u'Y': 'Note'}])],
  1447                       None, None, [self.system], {}, [])
  1447                       None, None, [self.system], {}, [])
  1469                     ],
  1469                     ],
  1470                    {'x': 999999,})
  1470                    {'x': 999999,})
  1471 
  1471 
  1472     def test_crossed_relation_eid_2_needattr(self):
  1472     def test_crossed_relation_eid_2_needattr(self):
  1473         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1473         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1474         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',                   
  1474         self._test('Any Y,T WHERE X eid %(x)s, X multisource_crossed_rel Y, Y type T',
  1475                    [('FetchStep', [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
  1475                    [('FetchStep', [('Any Y,T WHERE Y type T, Y is Note', [{'T': 'String', 'Y': 'Note'}])],
  1476                      [self.rql, self.system], None,
  1476                      [self.rql, self.system], None,
  1477                      {'T': 'table0.C1', 'Y': 'table0.C0', 'Y.type': 'table0.C1'}, []),
  1477                      {'T': 'table0.C1', 'Y': 'table0.C0', 'Y.type': 'table0.C1'}, []),
  1478                     ('UnionStep', None, None,
  1478                     ('UnionStep', None, None,
  1479                      [('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
  1479                      [('OneFetchStep', [('Any Y,T WHERE 999999 multisource_crossed_rel Y, Y type T, Y is Note',
  1525                        {'T': 'table1.C1', 'X': 'table0.C0', 'X.type': 'table0.C1',
  1525                        {'T': 'table1.C1', 'X': 'table0.C0', 'X.type': 'table0.C1',
  1526                         'Y': 'table1.C0', 'Y.type': 'table1.C1'},
  1526                         'Y': 'table1.C0', 'Y.type': 'table1.C1'},
  1527                        [])]
  1527                        [])]
  1528                      )],
  1528                      )],
  1529                     {'x': 999999,})
  1529                     {'x': 999999,})
  1530         
  1530 
  1531     # edition queries tests ###################################################
  1531     # edition queries tests ###################################################
  1532 
  1532 
  1533     def test_insert_simplified_var_1(self):
  1533     def test_insert_simplified_var_1(self):
  1534         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1534         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1535         repo._type_source_cache[999998] = ('State', 'system', None)
  1535         repo._type_source_cache[999998] = ('State', 'system', None)
  1600                                            [{'A': 'Affaire'}])],
  1600                                            [{'A': 'Affaire'}])],
  1601                          None, None, [self.system], {}, [])]
  1601                          None, None, [self.system], {}, [])]
  1602                        )]
  1602                        )]
  1603                      )],
  1603                      )],
  1604                    {'n': 999999, 's': 999998})
  1604                    {'n': 999999, 's': 999998})
  1605     
  1605 
  1606     def test_delete_relation1(self):
  1606     def test_delete_relation1(self):
  1607         ueid = self.session.user.eid
  1607         ueid = self.session.user.eid
  1608         self._test('DELETE X created_by Y WHERE X eid %(x)s, NOT Y eid %(y)s',
  1608         self._test('DELETE X created_by Y WHERE X eid %(x)s, NOT Y eid %(y)s',
  1609                    [('DeleteRelationsStep', [
  1609                    [('DeleteRelationsStep', [
  1610                        ('OneFetchStep', [('Any 5,Y WHERE %s created_by Y, NOT Y eid %s, Y is CWUser'%(ueid, ueid),
  1610                        ('OneFetchStep', [('Any 5,Y WHERE %s created_by Y, NOT Y eid %s, Y is CWUser'%(ueid, ueid),
  1611                                           [{'Y': 'CWUser'}])],
  1611                                           [{'Y': 'CWUser'}])],
  1612                         None, None, [self.system], {}, []),
  1612                         None, None, [self.system], {}, []),
  1613                        ]),
  1613                        ]),
  1614                     ],
  1614                     ],
  1615                    {'x': ueid, 'y': ueid})
  1615                    {'x': ueid, 'y': ueid})
  1616         
  1616 
  1617     def test_delete_relation2(self):
  1617     def test_delete_relation2(self):
  1618         ueid = self.session.user.eid
  1618         ueid = self.session.user.eid
  1619         self._test('DELETE X created_by Y WHERE X eid %(x)s, NOT Y login "syt"',
  1619         self._test('DELETE X created_by Y WHERE X eid %(x)s, NOT Y login "syt"',
  1620                    [('FetchStep', [('Any Y WHERE NOT Y login "syt", Y is CWUser', [{'Y': 'CWUser'}])],
  1620                    [('FetchStep', [('Any Y WHERE NOT Y login "syt", Y is CWUser', [{'Y': 'CWUser'}])],
  1621                      [self.ldap, self.system], None, {'Y': 'table0.C0'}, []),
  1621                      [self.ldap, self.system], None, {'Y': 'table0.C0'}, []),
  1634                                          [{'Y': 'Card'}, {'Y': 'Note'}])],
  1634                                          [{'Y': 'Card'}, {'Y': 'Note'}])],
  1635                        None, None, [self.system], {}, [])
  1635                        None, None, [self.system], {}, [])
  1636                       ])
  1636                       ])
  1637                     ],
  1637                     ],
  1638                    {'x': 999999})
  1638                    {'x': 999999})
  1639         
  1639 
  1640     def test_delete_entity2(self):
  1640     def test_delete_entity2(self):
  1641         repo._type_source_cache[999999] = ('Note', 'system', 999999)
  1641         repo._type_source_cache[999999] = ('Note', 'system', 999999)
  1642         self._test('DELETE Note X WHERE X eid %(x)s, NOT X multisource_inlined_rel Y',
  1642         self._test('DELETE Note X WHERE X eid %(x)s, NOT X multisource_inlined_rel Y',
  1643                    [('DeleteEntitiesStep',
  1643                    [('DeleteEntitiesStep',
  1644                      [('OneFetchStep', [('Any X WHERE X eid 999999, NOT X multisource_inlined_rel Y, X is Note, Y is IN(Affaire, Note)',
  1644                      [('OneFetchStep', [('Any X WHERE X eid 999999, NOT X multisource_inlined_rel Y, X is Note, Y is IN(Affaire, Note)',
  1645                                          [{'X': 'Note', 'Y': 'Affaire'}, {'X': 'Note', 'Y': 'Note'}])],
  1645                                          [{'X': 'Note', 'Y': 'Affaire'}, {'X': 'Note', 'Y': 'Note'}])],
  1646                        None, None, [self.system], {}, [])
  1646                        None, None, [self.system], {}, [])
  1647                       ])
  1647                       ])
  1648                     ],
  1648                     ],
  1649                    {'x': 999999})
  1649                    {'x': 999999})
  1650                    
  1650 
  1651     def test_update(self):
  1651     def test_update(self):
  1652         self._test('SET X copain Y WHERE X login "comme", Y login "cochon"',
  1652         self._test('SET X copain Y WHERE X login "comme", Y login "cochon"',
  1653                    [('FetchStep',
  1653                    [('FetchStep',
  1654                      [('Any X WHERE X login "comme", X is CWUser', [{'X': 'CWUser'}])],
  1654                      [('Any X WHERE X login "comme", X is CWUser', [{'X': 'CWUser'}])],
  1655                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
  1655                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
  1699 #                        ('OneFetchStep', [('DISTINCT Any X,%s WHERE X is CWUser' % activatedeid,
  1699 #                        ('OneFetchStep', [('DISTINCT Any X,%s WHERE X is CWUser' % activatedeid,
  1700 #                                           [{'X': 'CWUser'}])],
  1700 #                                           [{'X': 'CWUser'}])],
  1701 #                         None, None, [self.system], {}, []),
  1701 #                         None, None, [self.system], {}, []),
  1702 #                        ]),
  1702 #                        ]),
  1703 #                     ])
  1703 #                     ])
  1704         
  1704 
  1705     # non regression tests ####################################################
  1705     # non regression tests ####################################################
  1706     
  1706 
  1707     def test_nonregr1(self):
  1707     def test_nonregr1(self):
  1708         self._test('Any X, Y WHERE X copain Y, X login "syt", Y login "cochon"',
  1708         self._test('Any X, Y WHERE X copain Y, X login "syt", Y login "cochon"',
  1709                    [('FetchStep',
  1709                    [('FetchStep',
  1710                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
  1710                      [('Any X WHERE X login "syt", X is CWUser', [{'X': 'CWUser'}])],
  1711                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
  1711                      [self.ldap, self.system], None, {'X': 'table0.C0'}, []),
  1715                     ('OneFetchStep',
  1715                     ('OneFetchStep',
  1716                      [('Any X,Y WHERE X copain Y, X is CWUser, Y is CWUser',
  1716                      [('Any X,Y WHERE X copain Y, X is CWUser, Y is CWUser',
  1717                        [{'X': 'CWUser', 'Y': 'CWUser'}])],
  1717                        [{'X': 'CWUser', 'Y': 'CWUser'}])],
  1718                      None, None, [self.system], {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
  1718                      None, None, [self.system], {'X': 'table0.C0', 'Y': 'table1.C0'}, [])
  1719                     ])
  1719                     ])
  1720     
  1720 
  1721     def test_nonregr2(self):
  1721     def test_nonregr2(self):
  1722         treid = self.session.user.latest_trinfo().eid
  1722         treid = self.session.user.latest_trinfo().eid
  1723         self._test('Any X ORDERBY D DESC WHERE E eid %(x)s, E wf_info_for X, X modification_date D',
  1723         self._test('Any X ORDERBY D DESC WHERE E eid %(x)s, E wf_info_for X, X modification_date D',
  1724                    [('FetchStep', [('Any X,D WHERE X modification_date D, X is Note',
  1724                    [('FetchStep', [('Any X,D WHERE X modification_date D, X is Note',
  1725                                     [{'X': 'Note', 'D': 'Datetime'}])],
  1725                                     [{'X': 'Note', 'D': 'Datetime'}])],
  1744                          {'X': 'table0.C0', 'X.modification_date': 'table0.C1', 'D': 'table0.C1'},
  1744                          {'X': 'table0.C0', 'X.modification_date': 'table0.C1', 'D': 'table0.C1'},
  1745                          {'X': 'table2.C0', 'X.modification_date': 'table2.C1', 'D': 'table2.C1', 'E.wf_info_for': 'table2.C0'}, []),
  1745                          {'X': 'table2.C0', 'X.modification_date': 'table2.C1', 'D': 'table2.C1', 'E.wf_info_for': 'table2.C0'}, []),
  1746                         ]),
  1746                         ]),
  1747                     ],
  1747                     ],
  1748                    {'x': treid})
  1748                    {'x': treid})
  1749         
  1749 
  1750     def test_nonregr3(self):
  1750     def test_nonregr3(self):
  1751         # original jpl query:
  1751         # original jpl query:
  1752         # Any X, NOW - CD, P WHERE P is Project, U interested_in P, U is CWUser, U login "sthenault", X concerns P, X creation_date CD ORDERBY CD DESC LIMIT 5
  1752         # Any X, NOW - CD, P WHERE P is Project, U interested_in P, U is CWUser, U login "sthenault", X concerns P, X creation_date CD ORDERBY CD DESC LIMIT 5
  1753         self._test('Any X, NOW - CD, P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, U login "admin", P is X, X creation_date CD',
  1753         self._test('Any X, NOW - CD, P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, U login "admin", P is X, X creation_date CD',
  1754                    [('FetchStep', [('Any U WHERE U login "admin", U is CWUser', [{'U': 'CWUser'}])],
  1754                    [('FetchStep', [('Any U WHERE U login "admin", U is CWUser', [{'U': 'CWUser'}])],
  1755                      [self.ldap, self.system], None, {'U': 'table0.C0'}, []),
  1755                      [self.ldap, self.system], None, {'U': 'table0.C0'}, []),
  1756                     ('OneFetchStep', [('Any X,(NOW - CD),P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, P is X, X creation_date CD, P is Bookmark, U is CWUser, X is CWEType',
  1756                     ('OneFetchStep', [('Any X,(NOW - CD),P ORDERBY CD DESC LIMIT 5 WHERE P bookmarked_by U, P is X, X creation_date CD, P is Bookmark, U is CWUser, X is CWEType',
  1757                                        [{'P': 'Bookmark', 'U': 'CWUser', 'X': 'CWEType', 'CD': 'Datetime'}])],
  1757                                        [{'P': 'Bookmark', 'U': 'CWUser', 'X': 'CWEType', 'CD': 'Datetime'}])],
  1758                      5, None,  [self.system], {'U': 'table0.C0'}, [])]
  1758                      5, None,  [self.system], {'U': 'table0.C0'}, [])]
  1759                    )
  1759                    )
  1760         
  1760 
  1761     def test_nonregr4(self):
  1761     def test_nonregr4(self):
  1762         self._test('Any U ORDERBY D DESC WHERE WF wf_info_for X, WF creation_date D, WF from_state FS, '
  1762         self._test('Any U ORDERBY D DESC WHERE WF wf_info_for X, WF creation_date D, WF from_state FS, '
  1763                    'WF owned_by U?, X eid %(x)s',
  1763                    'WF owned_by U?, X eid %(x)s',
  1764                    [#('FetchStep', [('Any U WHERE U is CWUser', [{'U': 'CWUser'}])],
  1764                    [#('FetchStep', [('Any U WHERE U is CWUser', [{'U': 'CWUser'}])],
  1765                     # [self.ldap, self.system], None, {'U': 'table0.C0'}, []),
  1765                     # [self.ldap, self.system], None, {'U': 'table0.C0'}, []),
  1769                      [self.system], {}, [])],
  1769                      [self.system], {}, [])],
  1770                    {'x': self.session.user.eid})
  1770                    {'x': self.session.user.eid})
  1771 
  1771 
  1772     def test_nonregr5(self):
  1772     def test_nonregr5(self):
  1773         # original jpl query:
  1773         # original jpl query:
  1774         # DISTINCT Version V WHERE MB done_in MV, MV eid %(x)s, 
  1774         # DISTINCT Version V WHERE MB done_in MV, MV eid %(x)s,
  1775         # MB depends_on B, B done_in V, V version_of P, NOT P eid %(p)s'
  1775         # MB depends_on B, B done_in V, V version_of P, NOT P eid %(p)s'
  1776         cardeid = self.execute('INSERT Card X: X title "hop"')[0][0]
  1776         cardeid = self.execute('INSERT Card X: X title "hop"')[0][0]
  1777         noteeid = self.execute('INSERT Note X')[0][0]
  1777         noteeid = self.execute('INSERT Note X')[0][0]
  1778         self._test('DISTINCT Card V WHERE MB documented_by MV, MV eid %(x)s, '
  1778         self._test('DISTINCT Card V WHERE MB documented_by MV, MV eid %(x)s, '
  1779                    'MB depends_on B, B documented_by V, V multisource_rel P, NOT P eid %(p)s',
  1779                    'MB depends_on B, B documented_by V, V multisource_rel P, NOT P eid %(p)s',
  1820                      [self.rql], None, {}, []),
  1820                      [self.rql], None, {}, []),
  1821                     ('OneFetchStep', [('Any 999999,Z WHERE Z concerne 999999, Z is Affaire',
  1821                     ('OneFetchStep', [('Any 999999,Z WHERE Z concerne 999999, Z is Affaire',
  1822                                        [{'Z': 'Affaire'}])],
  1822                                        [{'Z': 'Affaire'}])],
  1823                      None, None, [self.system], {}, [])],
  1823                      None, None, [self.system], {}, [])],
  1824                    {'x': 999999})
  1824                    {'x': 999999})
  1825         
  1825 
  1826     def test_nonregr9(self):
  1826     def test_nonregr9(self):
  1827         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1827         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1828         repo._type_source_cache[999998] = ('Note', 'cards', 999998)
  1828         repo._type_source_cache[999998] = ('Note', 'cards', 999998)
  1829         self._test('SET X migrated_from Y WHERE X eid %(x)s, Y multisource_rel Z, Z eid %(z)s, Y migrated_from Z',
  1829         self._test('SET X migrated_from Y WHERE X eid %(x)s, Y multisource_rel Z, Z eid %(z)s, Y migrated_from Z',
  1830                    [('FetchStep', [('Any Y WHERE Y multisource_rel 999998, Y is Note', [{'Y': 'Note'}])],
  1830                    [('FetchStep', [('Any Y WHERE Y multisource_rel 999998, Y is Note', [{'Y': 'Note'}])],
  1851                      None, None, [self.system], {'AA': 'table0.C1', 'AB': 'table0.C2',
  1851                      None, None, [self.system], {'AA': 'table0.C1', 'AB': 'table0.C2',
  1852                                                  'X': 'table0.C0', 'X.login': 'table0.C1', 'X.modification_date': 'table0.C2'},
  1852                                                  'X': 'table0.C0', 'X.login': 'table0.C1', 'X.modification_date': 'table0.C2'},
  1853                      [])
  1853                      [])
  1854                     ],
  1854                     ],
  1855                    {'x': 999999})
  1855                    {'x': 999999})
  1856         
  1856 
  1857     def test_nonregr11(self):
  1857     def test_nonregr11(self):
  1858         repo._type_source_cache[999999] = ('Bookmark', 'system', 999999)
  1858         repo._type_source_cache[999999] = ('Bookmark', 'system', 999999)
  1859         self._test('SET X bookmarked_by Y WHERE X eid %(x)s, Y login "hop"',
  1859         self._test('SET X bookmarked_by Y WHERE X eid %(x)s, Y login "hop"',
  1860                    [('FetchStep',
  1860                    [('FetchStep',
  1861                      [('Any Y WHERE Y login "hop", Y is CWUser', [{'Y': 'CWUser'}])],
  1861                      [('Any Y WHERE Y login "hop", Y is CWUser', [{'Y': 'CWUser'}])],
  1865                      [('OneFetchStep', [('DISTINCT Any 999999,Y WHERE Y is CWUser', [{'Y': 'CWUser'}])],
  1865                      [('OneFetchStep', [('DISTINCT Any 999999,Y WHERE Y is CWUser', [{'Y': 'CWUser'}])],
  1866                        None, None, [self.system], {'Y': 'table0.C0'},
  1866                        None, None, [self.system], {'Y': 'table0.C0'},
  1867                        [])]
  1867                        [])]
  1868                      )],
  1868                      )],
  1869                    {'x': 999999})
  1869                    {'x': 999999})
  1870         
  1870 
  1871     def test_nonregr12(self):
  1871     def test_nonregr12(self):
  1872         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1872         repo._type_source_cache[999999] = ('Note', 'cards', 999999)
  1873         self._test('Any X ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E see_also X',
  1873         self._test('Any X ORDERBY Z DESC WHERE X modification_date Z, E eid %(x)s, E see_also X',
  1874                    [('FetchStep', [('Any X,Z WHERE X modification_date Z, X is Note',
  1874                    [('FetchStep', [('Any X,Z WHERE X modification_date Z, X is Note',
  1875                                     [{'X': 'Note', 'Z': 'Datetime'}])],
  1875                                     [{'X': 'Note', 'Z': 'Datetime'}])],
  1914                                        [{'B': 'File', 'U': 'CWUser', 'UL': 'String'}])],
  1914                                        [{'B': 'File', 'U': 'CWUser', 'UL': 'String'}])],
  1915                      None, None, [self.system],
  1915                      None, None, [self.system],
  1916                      {'U': 'table1.C0', 'UL': 'table1.C1'},
  1916                      {'U': 'table1.C0', 'UL': 'table1.C1'},
  1917                      [])],
  1917                      [])],
  1918                    {'x': self.session.user.eid})
  1918                    {'x': self.session.user.eid})
  1919         
  1919 
  1920     def test_nonregr13_2(self):
  1920     def test_nonregr13_2(self):
  1921         # identity *not* wrapped into exists.
  1921         # identity *not* wrapped into exists.
  1922         #
  1922         #
  1923         # XXX this test fail since in this case, in "U identity 5" U and 5 are
  1923         # XXX this test fail since in this case, in "U identity 5" U and 5 are
  1924         # from the same scope so constraints are applied (telling the U should
  1924         # from the same scope so constraints are applied (telling the U should
  1952                    {'x': self.session.user.eid})
  1952                    {'x': self.session.user.eid})
  1953 
  1953 
  1954 
  1954 
  1955 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
  1955 class MSPlannerTwoSameExternalSourcesTC(BasePlannerTC):
  1956     """test planner related feature on a 3-sources repository:
  1956     """test planner related feature on a 3-sources repository:
  1957     
  1957 
  1958     * 2 rql sources supporting Card
  1958     * 2 rql sources supporting Card
  1959     """
  1959     """
  1960     repo = repo
  1960     repo = repo
  1961     
  1961 
  1962     def setUp(self):
  1962     def setUp(self):
  1963         self.o = repo.querier
  1963         self.o = repo.querier
  1964         self.session = repo._sessions.values()[0]
  1964         self.session = repo._sessions.values()[0]
  1965         self.pool = self.session.set_pool()
  1965         self.pool = self.session.set_pool()
  1966         self.schema = self.o.schema
  1966         self.schema = self.o.schema
  1980         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
  1980         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards2'].cross_relations
  1981         assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
  1981         assert repo.sources_by_uri['cards'].support_relation('multisource_crossed_rel')
  1982         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards'].cross_relations
  1982         assert 'multisource_crossed_rel' in repo.sources_by_uri['cards'].cross_relations
  1983         clear_ms_caches(repo)
  1983         clear_ms_caches(repo)
  1984     _test = test_plan
  1984     _test = test_plan
  1985         
  1985 
  1986     def tearDown(self):
  1986     def tearDown(self):
  1987         undo_monkey_patch()
  1987         undo_monkey_patch()
  1988         del self.sources[-1]
  1988         del self.sources[-1]
  1989         del self.sources[-1]
  1989         del self.sources[-1]
  1990         del repo.sources_by_uri['cards']
  1990         del repo.sources_by_uri['cards']
  2088                         'X': 'table0.C0'},
  2088                         'X': 'table0.C0'},
  2089                        [])]
  2089                        [])]
  2090                      )]
  2090                      )]
  2091                    )
  2091                    )
  2092 
  2092 
       
  2093     def test_nonregr_dont_cross_rel_source_filtering(self):
       
  2094         self.repo._type_source_cache[999999] = ('Note', 'cards', 999999)
       
  2095         self._test('Any X,AA,AB WHERE E eid %(x)s, E in_state X, X name AA, X modification_date AB',
       
  2096                    [('OneFetchStep', [('Any X,AA,AB WHERE 999999 in_state X, X name AA, X modification_date AB, X is State',
       
  2097                                        [{'AA': 'String', 'AB': 'Datetime', 'X': 'State'}])],
       
  2098                      None, None,
       
  2099                      [self.rql], {}, []
       
  2100                      )],
       
  2101                    {'x': 999999})
       
  2102 
  2093 
  2103 
  2094 if __name__ == '__main__':
  2104 if __name__ == '__main__':
  2095     from logilab.common.testlib import unittest_main
  2105     from logilab.common.testlib import unittest_main
  2096     unittest_main()
  2106     unittest_main()