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