109 yield cnx, ServerMigrationHelper(self.repo.config, migrschema, |
108 yield cnx, ServerMigrationHelper(self.repo.config, migrschema, |
110 repo=self.repo, cnx=cnx, |
109 repo=self.repo, cnx=cnx, |
111 interactive=False) |
110 interactive=False) |
112 |
111 |
113 def table_sql(self, mh, tablename): |
112 def table_sql(self, mh, tablename): |
114 result = mh.sqlexec("SELECT table_name FROM information_schema.tables WHERE LOWER(table_name)=%(table)s", |
113 result = mh.sqlexec( |
115 {'table': tablename.lower()}) |
114 "SELECT table_name FROM information_schema.tables WHERE LOWER(table_name)=%(table)s", |
|
115 {'table': tablename.lower()}) |
116 if result: |
116 if result: |
117 return result[0][0] |
117 return result[0][0] |
118 return None # no such table |
118 return None # no such table |
119 |
119 |
120 def table_schema(self, mh, tablename): |
120 def table_schema(self, mh, tablename): |
121 result = mh.sqlexec("SELECT column_name, data_type, character_maximum_length FROM information_schema.columns " |
121 result = mh.sqlexec( |
122 "WHERE LOWER(table_name) = %(table)s", {'table': tablename.lower()}) |
122 "SELECT column_name, data_type, character_maximum_length " |
|
123 "FROM information_schema.columns " |
|
124 "WHERE LOWER(table_name) = %(table)s", {'table': tablename.lower()}) |
123 assert result, 'no table %s' % tablename |
125 assert result, 'no table %s' % tablename |
124 return dict((x[0], (x[1], x[2])) for x in result) |
126 return dict((x[0], (x[1], x[2])) for x in result) |
125 |
127 |
126 def table_constraints(self, mh, tablename): |
128 def table_constraints(self, mh, tablename): |
127 result = mh.sqlexec( |
129 result = mh.sqlexec( |
176 orderdict2 = dict(mh.rqlexec('Any RTN, O WHERE X name "Note", RDEF from_entity X, ' |
178 orderdict2 = dict(mh.rqlexec('Any RTN, O WHERE X name "Note", RDEF from_entity X, ' |
177 'RDEF relation_type RT, RDEF ordernum O, RT name RTN')) |
179 'RDEF relation_type RT, RDEF ordernum O, RT name RTN')) |
178 whateverorder = migrschema['whatever'].rdef('Note', 'Int').order |
180 whateverorder = migrschema['whatever'].rdef('Note', 'Int').order |
179 for k, v in orderdict.items(): |
181 for k, v in orderdict.items(): |
180 if v >= whateverorder: |
182 if v >= whateverorder: |
181 orderdict[k] = v+1 |
183 orderdict[k] = v + 1 |
182 orderdict['whatever'] = whateverorder |
184 orderdict['whatever'] = whateverorder |
183 self.assertDictEqual(orderdict, orderdict2) |
185 self.assertDictEqual(orderdict, orderdict2) |
184 #self.assertEqual([r.type for r in self.schema['Note'].ordered_relations()], |
|
185 # ['modification_date', 'creation_date', 'owned_by', |
|
186 # 'eid', 'ecrit_par', 'inline1', 'date', 'type', |
|
187 # 'whatever', 'date', 'in_basket']) |
|
188 # NB: commit instead of rollback make following test fail with py2.5 |
|
189 # this sounds like a pysqlite/2.5 bug (the same eid is affected to |
|
190 # two different entities) |
|
191 |
186 |
192 def test_add_attribute_varchar(self): |
187 def test_add_attribute_varchar(self): |
193 with self.mh() as (cnx, mh): |
188 with self.mh() as (cnx, mh): |
194 self.assertNotIn('whatever', self.schema) |
189 self.assertNotIn('whatever', self.schema) |
195 cnx.create_entity('Note') |
190 cnx.create_entity('Note') |
231 self.assertIn('newstyledefaultdate', self.schema) |
226 self.assertIn('newstyledefaultdate', self.schema) |
232 self.assertEqual(self.schema['mydate'].subjects(), ('Note', )) |
227 self.assertEqual(self.schema['mydate'].subjects(), ('Note', )) |
233 self.assertEqual(self.schema['mydate'].objects(), ('Date', )) |
228 self.assertEqual(self.schema['mydate'].objects(), ('Date', )) |
234 testdate = date(2005, 12, 13) |
229 testdate = date(2005, 12, 13) |
235 eid1 = mh.rqlexec('INSERT Note N')[0][0] |
230 eid1 = mh.rqlexec('INSERT Note N')[0][0] |
236 eid2 = mh.rqlexec('INSERT Note N: N mydate %(mydate)s', {'mydate' : testdate})[0][0] |
231 eid2 = mh.rqlexec('INSERT Note N: N mydate %(mydate)s', {'mydate': testdate})[0][0] |
237 d1 = mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid1})[0][0] |
232 d1 = mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid1})[0][0] |
238 d2 = mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid2})[0][0] |
233 d2 = mh.rqlexec('Any D WHERE X eid %(x)s, X mydate D', {'x': eid2})[0][0] |
239 d3 = mh.rqlexec('Any D WHERE X eid %(x)s, X oldstyledefaultdate D', {'x': eid1})[0][0] |
234 d3 = mh.rqlexec('Any D WHERE X eid %(x)s, X oldstyledefaultdate D', {'x': eid1})[0][0] |
240 d4 = mh.rqlexec('Any D WHERE X eid %(x)s, X newstyledefaultdate D', {'x': eid1})[0][0] |
235 d4 = mh.rqlexec('Any D WHERE X eid %(x)s, X newstyledefaultdate D', {'x': eid1})[0][0] |
241 self.assertEqual(d1, date.today()) |
236 self.assertEqual(d1, date.today()) |
283 c2 = mh.rqlexec('Any C WHERE X eid %s, X civility C' % eid2)[0][0] |
278 c2 = mh.rqlexec('Any C WHERE X eid %s, X civility C' % eid2)[0][0] |
284 self.assertEqual(c2, None) |
279 self.assertEqual(c2, None) |
285 |
280 |
286 def test_workflow_actions(self): |
281 def test_workflow_actions(self): |
287 with self.mh() as (cnx, mh): |
282 with self.mh() as (cnx, mh): |
288 wf = mh.cmd_add_workflow(u'foo', ('Personne', 'Email'), |
283 mh.cmd_add_workflow(u'foo', ('Personne', 'Email'), |
289 ensure_workflowable=False) |
284 ensure_workflowable=False) |
290 for etype in ('Personne', 'Email'): |
285 for etype in ('Personne', 'Email'): |
291 s1 = mh.rqlexec('Any N WHERE WF workflow_of ET, ET name "%s", WF name N' % |
286 s1 = mh.rqlexec('Any N WHERE WF workflow_of ET, ET name "%s", WF name N' % |
292 etype)[0][0] |
287 etype)[0][0] |
293 self.assertEqual(s1, "foo") |
288 self.assertEqual(s1, "foo") |
294 s1 = mh.rqlexec('Any N WHERE ET default_workflow WF, ET name "%s", WF name N' % |
289 s1 = mh.rqlexec('Any N WHERE ET default_workflow WF, ET name "%s", WF name N' % |
304 self.assertIn('Old', self.schema) |
299 self.assertIn('Old', self.schema) |
305 self.assertTrue(cnx.execute('CWEType X WHERE X name "Folder2"')) |
300 self.assertTrue(cnx.execute('CWEType X WHERE X name "Folder2"')) |
306 self.assertIn('filed_under2', self.schema) |
301 self.assertIn('filed_under2', self.schema) |
307 self.assertTrue(cnx.execute('CWRType X WHERE X name "filed_under2"')) |
302 self.assertTrue(cnx.execute('CWRType X WHERE X name "filed_under2"')) |
308 self.assertEqual(sorted(str(rs) for rs in self.schema['Folder2'].subject_relations()), |
303 self.assertEqual(sorted(str(rs) for rs in self.schema['Folder2'].subject_relations()), |
309 ['created_by', 'creation_date', 'cw_source', 'cwuri', |
304 ['created_by', 'creation_date', 'cw_source', 'cwuri', |
310 'description', 'description_format', |
305 'description', 'description_format', |
311 'eid', |
306 'eid', |
312 'filed_under2', 'has_text', |
307 'filed_under2', 'has_text', |
313 'identity', 'in_basket', 'inlined_rel', 'is', 'is_instance_of', |
308 'identity', 'in_basket', 'inlined_rel', 'is', 'is_instance_of', |
314 'modification_date', 'name', 'owned_by']) |
309 'modification_date', 'name', 'owned_by']) |
315 self.assertCountEqual([str(rs) for rs in self.schema['Folder2'].object_relations()], |
310 self.assertCountEqual([str(rs) for rs in self.schema['Folder2'].object_relations()], |
316 ['filed_under2', 'identity', 'inlined_rel']) |
311 ['filed_under2', 'identity', 'inlined_rel']) |
317 # Old will be missing as it has been renamed into 'New' in the migrated |
312 # Old will be missing as it has been renamed into 'New' in the migrated |
318 # schema while New hasn't been added here. |
313 # schema while New hasn't been added here. |
319 self.assertEqual(sorted(str(e) for e in self.schema['filed_under2'].subjects()), |
314 self.assertEqual(sorted(str(e) for e in self.schema['filed_under2'].subjects()), |
320 sorted(str(e) for e in self.schema.entities() if not e.final and e != 'Old')) |
315 sorted(str(e) for e in self.schema.entities() |
|
316 if not e.final and e != 'Old')) |
321 self.assertEqual(self.schema['filed_under2'].objects(), ('Folder2',)) |
317 self.assertEqual(self.schema['filed_under2'].objects(), ('Folder2',)) |
322 eschema = self.schema.eschema('Folder2') |
318 eschema = self.schema.eschema('Folder2') |
323 for cstr in eschema.rdef('name').constraints: |
319 for cstr in eschema.rdef('name').constraints: |
324 self.assertTrue(hasattr(cstr, 'eid')) |
320 self.assertTrue(hasattr(cstr, 'eid')) |
325 |
321 |
352 todo = wf.add_state(u'todo', initial=True) |
348 todo = wf.add_state(u'todo', initial=True) |
353 done = wf.add_state(u'done') |
349 done = wf.add_state(u'done') |
354 wf.add_transition(u'redoit', done, todo) |
350 wf.add_transition(u'redoit', done, todo) |
355 wf.add_transition(u'markasdone', todo, done) |
351 wf.add_transition(u'markasdone', todo, done) |
356 cnx.commit() |
352 cnx.commit() |
357 eschema = self.schema.eschema('Folder2') |
|
358 mh.cmd_drop_entity_type('Folder2') |
353 mh.cmd_drop_entity_type('Folder2') |
359 self.assertNotIn('Folder2', self.schema) |
354 self.assertNotIn('Folder2', self.schema) |
360 self.assertFalse(cnx.execute('CWEType X WHERE X name "Folder2"')) |
355 self.assertFalse(cnx.execute('CWEType X WHERE X name "Folder2"')) |
361 # test automatic workflow deletion |
356 # test automatic workflow deletion |
362 self.assertFalse(cnx.execute('Workflow X WHERE NOT X workflow_of ET')) |
357 self.assertFalse(cnx.execute('Workflow X WHERE NOT X workflow_of ET')) |
402 mh.cmd_add_relation_definition('Personne', 'concerne2', 'Affaire') |
397 mh.cmd_add_relation_definition('Personne', 'concerne2', 'Affaire') |
403 self.assertEqual(self.schema['concerne2'].subjects(), |
398 self.assertEqual(self.schema['concerne2'].subjects(), |
404 ('Personne',)) |
399 ('Personne',)) |
405 self.assertEqual(self.schema['concerne2'].objects(), |
400 self.assertEqual(self.schema['concerne2'].objects(), |
406 ('Affaire', )) |
401 ('Affaire', )) |
407 self.assertEqual(self.schema['concerne2'].rdef('Personne', 'Affaire').cardinality, |
402 self.assertEqual( |
408 '1*') |
403 self.schema['concerne2'].rdef('Personne', 'Affaire').cardinality, |
|
404 '1*') |
409 mh.cmd_add_relation_definition('Personne', 'concerne2', 'Note') |
405 mh.cmd_add_relation_definition('Personne', 'concerne2', 'Note') |
410 self.assertEqual(sorted(self.schema['concerne2'].objects()), ['Affaire', 'Note']) |
406 self.assertEqual(sorted(self.schema['concerne2'].objects()), ['Affaire', 'Note']) |
411 mh.create_entity('Personne', nom=u'tot') |
407 mh.create_entity('Personne', nom=u'tot') |
412 mh.create_entity('Affaire') |
408 mh.create_entity('Affaire') |
413 mh.rqlexec('SET X concerne2 Y WHERE X is Personne, Y is Affaire') |
409 mh.rqlexec('SET X concerne2 Y WHERE X is Personne, Y is Affaire') |
418 self.assertNotIn('concerne2', self.schema) |
414 self.assertNotIn('concerne2', self.schema) |
419 |
415 |
420 def test_drop_relation_definition_existant_rtype(self): |
416 def test_drop_relation_definition_existant_rtype(self): |
421 with self.mh() as (cnx, mh): |
417 with self.mh() as (cnx, mh): |
422 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
418 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
423 ['Affaire', 'Personne']) |
419 ['Affaire', 'Personne']) |
424 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
420 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
425 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
421 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
426 mh.cmd_drop_relation_definition('Personne', 'concerne', 'Affaire') |
422 mh.cmd_drop_relation_definition('Personne', 'concerne', 'Affaire') |
427 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
423 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
428 ['Affaire']) |
424 ['Affaire']) |
429 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
425 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
430 ['Division', 'Note', 'Societe', 'SubDivision']) |
426 ['Division', 'Note', 'Societe', 'SubDivision']) |
431 mh.cmd_add_relation_definition('Personne', 'concerne', 'Affaire') |
427 mh.cmd_add_relation_definition('Personne', 'concerne', 'Affaire') |
432 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
428 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
433 ['Affaire', 'Personne']) |
429 ['Affaire', 'Personne']) |
434 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
430 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
435 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
431 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
436 # trick: overwrite self.maxeid to avoid deletion of just reintroduced types |
432 # trick: overwrite self.maxeid to avoid deletion of just reintroduced types |
437 self.maxeid = cnx.execute('Any MAX(X)')[0][0] |
433 self.maxeid = cnx.execute('Any MAX(X)')[0][0] |
438 |
434 |
439 def test_drop_relation_definition_with_specialization(self): |
435 def test_drop_relation_definition_with_specialization(self): |
440 with self.mh() as (cnx, mh): |
436 with self.mh() as (cnx, mh): |
441 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
437 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
442 ['Affaire', 'Personne']) |
438 ['Affaire', 'Personne']) |
443 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
439 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
444 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
440 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
445 mh.cmd_drop_relation_definition('Affaire', 'concerne', 'Societe') |
441 mh.cmd_drop_relation_definition('Affaire', 'concerne', 'Societe') |
446 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
442 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
447 ['Affaire', 'Personne']) |
443 ['Affaire', 'Personne']) |
448 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
444 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
449 ['Affaire', 'Note']) |
445 ['Affaire', 'Note']) |
450 mh.cmd_add_relation_definition('Affaire', 'concerne', 'Societe') |
446 mh.cmd_add_relation_definition('Affaire', 'concerne', 'Societe') |
451 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
447 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].subjects()), |
452 ['Affaire', 'Personne']) |
448 ['Affaire', 'Personne']) |
453 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
449 self.assertEqual(sorted(str(e) for e in self.schema['concerne'].objects()), |
454 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
450 ['Affaire', 'Division', 'Note', 'Societe', 'SubDivision']) |
455 # trick: overwrite self.maxeid to avoid deletion of just reintroduced types |
451 # trick: overwrite self.maxeid to avoid deletion of just reintroduced types |
456 self.maxeid = cnx.execute('Any MAX(X)')[0][0] |
452 self.maxeid = cnx.execute('Any MAX(X)')[0][0] |
457 |
453 |
458 def test_rename_relation(self): |
454 def test_rename_relation(self): |
459 self.skipTest('implement me') |
455 self.skipTest('implement me') |
544 |
540 |
545 # test permissions synchronization #################################### |
541 # test permissions synchronization #################################### |
546 # new rql expr to add note entity |
542 # new rql expr to add note entity |
547 eexpr = self._erqlexpr_entity(cnx, 'add', 'Note') |
543 eexpr = self._erqlexpr_entity(cnx, 'add', 'Note') |
548 self.assertEqual(eexpr.expression, |
544 self.assertEqual(eexpr.expression, |
549 'X ecrit_part PE, U in_group G, ' |
545 'X ecrit_part PE, U in_group G, ' |
550 'PE require_permission P, P name "add_note", P require_group G') |
546 'PE require_permission P, P name "add_note", P require_group G') |
551 self.assertEqual([et.name for et in eexpr.reverse_add_permission], ['Note']) |
547 self.assertEqual([et.name for et in eexpr.reverse_add_permission], ['Note']) |
552 self.assertEqual(eexpr.reverse_read_permission, ()) |
548 self.assertEqual(eexpr.reverse_read_permission, ()) |
553 self.assertEqual(eexpr.reverse_delete_permission, ()) |
549 self.assertEqual(eexpr.reverse_delete_permission, ()) |
554 self.assertEqual(eexpr.reverse_update_permission, ()) |
550 self.assertEqual(eexpr.reverse_update_permission, ()) |
555 self.assertTrue(self._rrqlexpr_rset(cnx, 'add', 'para')) |
551 self.assertTrue(self._rrqlexpr_rset(cnx, 'add', 'para')) |
556 # no rqlexpr to delete para attribute |
552 # no rqlexpr to delete para attribute |
557 self.assertFalse(self._rrqlexpr_rset(cnx, 'delete', 'para')) |
553 self.assertFalse(self._rrqlexpr_rset(cnx, 'delete', 'para')) |
558 # new rql expr to add ecrit_par relation |
554 # new rql expr to add ecrit_par relation |
559 rexpr = self._rrqlexpr_entity(cnx, 'add', 'ecrit_par') |
555 rexpr = self._rrqlexpr_entity(cnx, 'add', 'ecrit_par') |
560 self.assertEqual(rexpr.expression, |
556 self.assertEqual(rexpr.expression, |
561 'O require_permission P, P name "add_note", ' |
557 'O require_permission P, P name "add_note", ' |
562 'U in_group G, P require_group G') |
558 'U in_group G, P require_group G') |
563 self.assertEqual([rdef.rtype.name for rdef in rexpr.reverse_add_permission], ['ecrit_par']) |
559 self.assertEqual([rdef.rtype.name for rdef in rexpr.reverse_add_permission], |
|
560 ['ecrit_par']) |
564 self.assertEqual(rexpr.reverse_read_permission, ()) |
561 self.assertEqual(rexpr.reverse_read_permission, ()) |
565 self.assertEqual(rexpr.reverse_delete_permission, ()) |
562 self.assertEqual(rexpr.reverse_delete_permission, ()) |
566 # no more rqlexpr to delete and add travaille relation |
563 # no more rqlexpr to delete and add travaille relation |
567 self.assertFalse(self._rrqlexpr_rset(cnx, 'add', 'travaille')) |
564 self.assertFalse(self._rrqlexpr_rset(cnx, 'add', 'travaille')) |
568 self.assertFalse(self._rrqlexpr_rset(cnx, 'delete', 'travaille')) |
565 self.assertFalse(self._rrqlexpr_rset(cnx, 'delete', 'travaille')) |
588 # * 1 update (Affaire update) |
585 # * 1 update (Affaire update) |
589 # * 2 new (Note add, ecrit_par add) |
586 # * 2 new (Note add, ecrit_par add) |
590 # * 2 implicit new for attributes (Note.para, Person.test) |
587 # * 2 implicit new for attributes (Note.para, Person.test) |
591 # remaining orphan rql expr which should be deleted at commit (composite relation) |
588 # remaining orphan rql expr which should be deleted at commit (composite relation) |
592 # unattached expressions -> pending deletion on commit |
589 # unattached expressions -> pending deletion on commit |
593 self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "ERQLExpression",' |
590 self.assertEqual( |
594 'NOT ET1 read_permission X, NOT ET2 add_permission X, ' |
591 cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "ERQLExpression",' |
595 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0], |
592 'NOT ET1 read_permission X, NOT ET2 add_permission X, ' |
596 7) |
593 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0], |
597 self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "RRQLExpression",' |
594 7) |
598 'NOT ET1 read_permission X, NOT ET2 add_permission X, ' |
595 self.assertEqual( |
599 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0], |
596 cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "RRQLExpression",' |
600 2) |
597 'NOT ET1 read_permission X, NOT ET2 add_permission X, ' |
|
598 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0], |
|
599 2) |
601 # finally |
600 # finally |
602 self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression')[0][0], |
601 self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression')[0][0], |
603 nbrqlexpr_start + 1 + 2 + 2 + 2) |
602 nbrqlexpr_start + 1 + 2 + 2 + 2) |
604 cnx.commit() |
603 cnx.commit() |
605 # unique_together test |
604 # unique_together test |
606 self.assertEqual(len(self.schema.eschema('Personne')._unique_together), 1) |
605 self.assertEqual(len(self.schema.eschema('Personne')._unique_together), 1) |
607 self.assertCountEqual(self.schema.eschema('Personne')._unique_together[0], |
606 self.assertCountEqual(self.schema.eschema('Personne')._unique_together[0], |
608 ('nom', 'prenom', 'datenaiss')) |
607 ('nom', 'prenom', 'datenaiss')) |
609 rset = cnx.execute('Any C WHERE C is CWUniqueTogetherConstraint, C constraint_of ET, ET name "Personne"') |
608 rset = cnx.execute('Any C WHERE C is CWUniqueTogetherConstraint, ' |
|
609 'C constraint_of ET, ET name "Personne"') |
610 self.assertEqual(len(rset), 1) |
610 self.assertEqual(len(rset), 1) |
611 relations = [r.name for r in rset.get_entity(0, 0).relations] |
611 relations = [r.name for r in rset.get_entity(0, 0).relations] |
612 self.assertCountEqual(relations, ('nom', 'prenom', 'datenaiss')) |
612 self.assertCountEqual(relations, ('nom', 'prenom', 'datenaiss')) |
613 |
613 |
614 # serialized constraint changed |
614 # serialized constraint changed |
626 rset = self._erqlexpr_rset(cnx, action, ertype) |
626 rset = self._erqlexpr_rset(cnx, action, ertype) |
627 self.assertEqual(len(rset), 1) |
627 self.assertEqual(len(rset), 1) |
628 return rset.get_entity(0, 0) |
628 return rset.get_entity(0, 0) |
629 |
629 |
630 def _rrqlexpr_rset(self, cnx, action, ertype): |
630 def _rrqlexpr_rset(self, cnx, action, ertype): |
631 rql = 'RQLExpression X WHERE RT is CWRType, RDEF %s_permission X, RT name %%(name)s, RDEF relation_type RT' % action |
631 return cnx.execute('RQLExpression X WHERE RT is CWRType, RDEF %s_permission X, ' |
632 return cnx.execute(rql, {'name': ertype}) |
632 'RT name %%(name)s, RDEF relation_type RT' % action, |
|
633 {'name': ertype}) |
633 |
634 |
634 def _rrqlexpr_entity(self, cnx, action, ertype): |
635 def _rrqlexpr_entity(self, cnx, action, ertype): |
635 rset = self._rrqlexpr_rset(cnx, action, ertype) |
636 rset = self._rrqlexpr_rset(cnx, action, ertype) |
636 self.assertEqual(len(rset), 1) |
637 self.assertEqual(len(rset), 1) |
637 return rset.get_entity(0, 0) |
638 return rset.get_entity(0, 0) |
665 self.assertNotIn(self.config.cube_dir('file'), self.config.cubes_path()) |
666 self.assertNotIn(self.config.cube_dir('file'), self.config.cubes_path()) |
666 for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', |
667 for ertype in ('Email', 'EmailThread', 'EmailPart', 'File', |
667 'sender', 'in_thread', 'reply_to', 'data_format'): |
668 'sender', 'in_thread', 'reply_to', 'data_format'): |
668 self.assertNotIn(ertype, schema) |
669 self.assertNotIn(ertype, schema) |
669 self.assertEqual(sorted(schema['see_also'].rdefs), |
670 self.assertEqual(sorted(schema['see_also'].rdefs), |
670 sorted([('Folder', 'Folder'), |
671 sorted([('Folder', 'Folder'), |
671 ('Bookmark', 'Bookmark'), |
672 ('Bookmark', 'Bookmark'), |
672 ('Bookmark', 'Note'), |
673 ('Bookmark', 'Note'), |
673 ('Note', 'Note'), |
674 ('Note', 'Note'), |
674 ('Note', 'Bookmark')])) |
675 ('Note', 'Bookmark')])) |
675 self.assertEqual(sorted(schema['see_also'].subjects()), ['Bookmark', 'Folder', 'Note']) |
676 self.assertEqual(sorted(schema['see_also'].subjects()), |
676 self.assertEqual(sorted(schema['see_also'].objects()), ['Bookmark', 'Folder', 'Note']) |
677 ['Bookmark', 'Folder', 'Note']) |
677 self.assertEqual(cnx.execute('Any X WHERE X pkey "system.version.fakeemail"').rowcount, 0) |
678 self.assertEqual(sorted(schema['see_also'].objects()), |
678 self.assertEqual(cnx.execute('Any X WHERE X pkey "system.version.file"').rowcount, 0) |
679 ['Bookmark', 'Folder', 'Note']) |
|
680 self.assertEqual( |
|
681 cnx.execute('Any X WHERE X pkey "system.version.fakeemail"').rowcount, |
|
682 0) |
|
683 self.assertEqual( |
|
684 cnx.execute('Any X WHERE X pkey "system.version.file"').rowcount, |
|
685 0) |
679 finally: |
686 finally: |
680 mh.cmd_add_cube('fakeemail') |
687 mh.cmd_add_cube('fakeemail') |
681 self.assertIn('fakeemail', self.config.cubes()) |
688 self.assertIn('fakeemail', self.config.cubes()) |
682 self.assertIn(self.config.cube_dir('fakeemail'), self.config.cubes_path()) |
689 self.assertIn(self.config.cube_dir('fakeemail'), self.config.cubes_path()) |
683 self.assertIn('file', self.config.cubes()) |
690 self.assertIn('file', self.config.cubes()) |
689 sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'), |
696 sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'), |
690 ('Bookmark', 'Bookmark'), |
697 ('Bookmark', 'Bookmark'), |
691 ('Bookmark', 'Note'), |
698 ('Bookmark', 'Note'), |
692 ('Note', 'Note'), |
699 ('Note', 'Note'), |
693 ('Note', 'Bookmark')])) |
700 ('Note', 'Bookmark')])) |
694 self.assertEqual(sorted(schema['see_also'].subjects()), ['Bookmark', 'EmailThread', 'Folder', 'Note']) |
701 self.assertEqual(sorted(schema['see_also'].subjects()), |
695 self.assertEqual(sorted(schema['see_also'].objects()), ['Bookmark', 'EmailThread', 'Folder', 'Note']) |
702 ['Bookmark', 'EmailThread', 'Folder', 'Note']) |
|
703 self.assertEqual(sorted(schema['see_also'].objects()), |
|
704 ['Bookmark', 'EmailThread', 'Folder', 'Note']) |
696 from cubes.fakeemail.__pkginfo__ import version as email_version |
705 from cubes.fakeemail.__pkginfo__ import version as email_version |
697 from cubes.file.__pkginfo__ import version as file_version |
706 from cubes.file.__pkginfo__ import version as file_version |
698 self.assertEqual(cnx.execute('Any V WHERE X value V, X pkey "system.version.fakeemail"')[0][0], |
707 self.assertEqual( |
699 email_version) |
708 cnx.execute('Any V WHERE X value V, X pkey "system.version.fakeemail"')[0][0], |
700 self.assertEqual(cnx.execute('Any V WHERE X value V, X pkey "system.version.file"')[0][0], |
709 email_version) |
701 file_version) |
710 self.assertEqual( |
702 # trick: overwrite self.maxeid to avoid deletion of just reintroduced |
711 cnx.execute('Any V WHERE X value V, X pkey "system.version.file"')[0][0], |
703 # types (and their associated tables!) |
712 file_version) |
704 self.maxeid = cnx.execute('Any MAX(X)')[0][0] |
|
705 # why this commit is necessary is unclear to me (though without it |
713 # why this commit is necessary is unclear to me (though without it |
706 # next test may fail complaining of missing tables |
714 # next test may fail complaining of missing tables |
707 cnx.commit() |
715 cnx.commit() |
708 |
716 |
709 def test_add_drop_cube_no_deps(self): |
717 def test_add_drop_cube_no_deps(self): |
737 self.assertEqual(sorted(et.type for et in self.schema['Para'].specialized_by()), |
745 self.assertEqual(sorted(et.type for et in self.schema['Para'].specialized_by()), |
738 ['Note']) |
746 ['Note']) |
739 self.assertEqual(self.schema['Note'].specializes().type, 'Para') |
747 self.assertEqual(self.schema['Note'].specializes().type, 'Para') |
740 mh.cmd_add_entity_type('Text') |
748 mh.cmd_add_entity_type('Text') |
741 self.assertEqual(sorted(et.type for et in self.schema['Para'].specialized_by()), |
749 self.assertEqual(sorted(et.type for et in self.schema['Para'].specialized_by()), |
742 ['Note', 'Text']) |
750 ['Note', 'Text']) |
743 self.assertEqual(self.schema['Text'].specializes().type, 'Para') |
751 self.assertEqual(self.schema['Text'].specializes().type, 'Para') |
744 # test columns have been actually added |
752 # test columns have been actually added |
745 text = cnx.execute('INSERT Text X: X para "hip", X summary "hop", X newattr "momo"').get_entity(0, 0) |
753 text = cnx.create_entity('Text', para=u"hip", summary=u"hop", newattr=u"momo") |
746 note = cnx.execute('INSERT Note X: X para "hip", X shortpara "hop", X newattr "momo", X unique_id "x"').get_entity(0, 0) |
754 note = cnx.create_entity('Note', para=u"hip", shortpara=u"hop", |
747 aff = cnx.execute('INSERT Affaire X').get_entity(0, 0) |
755 newattr=u"momo", unique_id=u"x") |
|
756 aff = cnx.create_entity('Affaire') |
748 self.assertTrue(cnx.execute('SET X newnotinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
757 self.assertTrue(cnx.execute('SET X newnotinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
749 {'x': text.eid, 'y': aff.eid})) |
758 {'x': text.eid, 'y': aff.eid})) |
750 self.assertTrue(cnx.execute('SET X newnotinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
759 self.assertTrue(cnx.execute('SET X newnotinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
751 {'x': note.eid, 'y': aff.eid})) |
760 {'x': note.eid, 'y': aff.eid})) |
752 self.assertTrue(cnx.execute('SET X newinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
761 self.assertTrue(cnx.execute('SET X newinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
753 {'x': text.eid, 'y': aff.eid})) |
762 {'x': text.eid, 'y': aff.eid})) |
754 self.assertTrue(cnx.execute('SET X newinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
763 self.assertTrue(cnx.execute('SET X newinlined Y WHERE X eid %(x)s, Y eid %(y)s', |
755 {'x': note.eid, 'y': aff.eid})) |
764 {'x': note.eid, 'y': aff.eid})) |
756 # XXX remove specializes by ourselves, else tearDown fails when removing |
765 # XXX remove specializes by ourselves, else tearDown fails when removing |
757 # Para because of Note inheritance. This could be fixed by putting the |
766 # Para because of Note inheritance. This could be fixed by putting the |
758 # MemSchemaCWETypeDel(session, name) operation in the |
767 # MemSchemaCWETypeDel(session, name) operation in the |
759 # after_delete_entity(CWEType) hook, since in that case the MemSchemaSpecializesDel |
768 # after_delete_entity(CWEType) hook, since in that case the MemSchemaSpecializesDel |
760 # operation would be removed before, but I'm not sure this is a desired behaviour. |
769 # operation would be removed before, but I'm not sure this is a desired behaviour. |
787 self.assertIsInstance(tel, float) |
796 self.assertIsInstance(tel, float) |
788 |
797 |
789 def test_drop_required_inlined_relation(self): |
798 def test_drop_required_inlined_relation(self): |
790 with self.mh() as (cnx, mh): |
799 with self.mh() as (cnx, mh): |
791 bob = mh.cmd_create_entity('Personne', nom=u'bob') |
800 bob = mh.cmd_create_entity('Personne', nom=u'bob') |
792 note = mh.cmd_create_entity('Note', ecrit_par=bob) |
801 mh.cmd_create_entity('Note', ecrit_par=bob) |
793 mh.commit() |
802 mh.commit() |
794 rdef = mh.fs_schema.rschema('ecrit_par').rdefs[('Note', 'Personne')] |
803 rdef = mh.fs_schema.rschema('ecrit_par').rdefs[('Note', 'Personne')] |
795 with tempattr(rdef, 'cardinality', '1*'): |
804 with tempattr(rdef, 'cardinality', '1*'): |
796 mh.sync_schema_props_perms('ecrit_par', syncperms=False) |
805 mh.sync_schema_props_perms('ecrit_par', syncperms=False) |
797 mh.cmd_drop_relation_type('ecrit_par') |
806 mh.cmd_drop_relation_type('ecrit_par') |
798 self.assertNotIn('%secrit_par' % SQL_PREFIX, |
807 self.assertNotIn('%secrit_par' % SQL_PREFIX, |
799 self.table_schema(mh, '%sPersonne' % SQL_PREFIX)) |
808 self.table_schema(mh, '%sPersonne' % SQL_PREFIX)) |
800 |
809 |
801 def test_drop_inlined_rdef_delete_data(self): |
810 def test_drop_inlined_rdef_delete_data(self): |
802 with self.mh() as (cnx, mh): |
811 with self.mh() as (cnx, mh): |
803 note = mh.cmd_create_entity('Note', ecrit_par=cnx.user.eid) |
812 mh.cmd_create_entity('Note', ecrit_par=cnx.user.eid) |
804 mh.commit() |
813 mh.commit() |
805 mh.drop_relation_definition('Note', 'ecrit_par', 'CWUser') |
814 mh.drop_relation_definition('Note', 'ecrit_par', 'CWUser') |
806 self.assertFalse(mh.sqlexec('SELECT * FROM cw_Note WHERE cw_ecrit_par IS NOT NULL')) |
815 self.assertFalse(mh.sqlexec('SELECT * FROM cw_Note WHERE cw_ecrit_par IS NOT NULL')) |
807 |
816 |
808 def test_storage_changed(self): |
817 def test_storage_changed(self): |